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 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
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
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  */
40 
41 #include "cairoint.h"
42 #include "cairo-error-private.h"
43 
44 /**
45  * SECTION:cairo-font-face
46  * @Title: cairo_font_face_t
47  * @Short_Description: Base class for font faces
48  * @See_Also: #cairo_scaled_font_t
49  *
50  * #cairo_font_face_t represents a particular font at a particular weight,
51  * slant, and other characteristic but no size, transformation, or size.
52  *
53  * Font faces are created using <firstterm>font-backend</firstterm>-specific
54  * constructors, typically of the form
55  * <function>cairo_<emphasis>backend</emphasis>_font_face_create(<!-- -->)</function>,
56  * or implicitly using the <firstterm>toy</firstterm> text API by way of
57  * cairo_select_font_face().  The resulting face can be accessed using
58  * cairo_get_font_face().
59  **/
60 
61 /* #cairo_font_face_t */
62 
63 const cairo_font_face_t _cairo_font_face_nil = {
64     { 0 },				/* hash_entry */
65     CAIRO_STATUS_NO_MEMORY,		/* status */
66     CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
67     { 0, 0, 0, NULL },			/* user_data */
68     NULL
69 };
70 const cairo_font_face_t _cairo_font_face_nil_file_not_found = {
71     { 0 },				/* hash_entry */
72     CAIRO_STATUS_FILE_NOT_FOUND,	/* status */
73     CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
74     { 0, 0, 0, NULL },			/* user_data */
75     NULL
76 };
77 
78 cairo_status_t
_cairo_font_face_set_error(cairo_font_face_t * font_face,cairo_status_t status)79 _cairo_font_face_set_error (cairo_font_face_t *font_face,
80 	                    cairo_status_t     status)
81 {
82     if (status == CAIRO_STATUS_SUCCESS)
83 	return status;
84 
85     /* Don't overwrite an existing error. This preserves the first
86      * error, which is the most significant. */
87     _cairo_status_set_error (&font_face->status, status);
88 
89     return _cairo_error (status);
90 }
91 
92 void
_cairo_font_face_init(cairo_font_face_t * font_face,const cairo_font_face_backend_t * backend)93 _cairo_font_face_init (cairo_font_face_t               *font_face,
94 		       const cairo_font_face_backend_t *backend)
95 {
96     CAIRO_MUTEX_INITIALIZE ();
97 
98     font_face->status = CAIRO_STATUS_SUCCESS;
99     CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1);
100     font_face->backend = backend;
101 
102     _cairo_user_data_array_init (&font_face->user_data);
103 }
104 
105 /**
106  * cairo_font_face_reference:
107  * @font_face: a #cairo_font_face_t, (may be %NULL in which case this
108  * function does nothing).
109  *
110  * Increases the reference count on @font_face by one. This prevents
111  * @font_face from being destroyed until a matching call to
112  * cairo_font_face_destroy() is made.
113  *
114  * Use cairo_font_face_get_reference_count() to get the number of
115  * references to a #cairo_font_face_t.
116  *
117  * Return value: the referenced #cairo_font_face_t.
118  *
119  * Since: 1.0
120  **/
121 cairo_font_face_t *
cairo_font_face_reference(cairo_font_face_t * font_face)122 cairo_font_face_reference (cairo_font_face_t *font_face)
123 {
124     if (font_face == NULL ||
125 	CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
126 	return font_face;
127 
128     /* We would normally assert that we have a reference here but we
129      * can't get away with that due to the zombie case as documented
130      * in _cairo_ft_font_face_destroy. */
131 
132     _cairo_reference_count_inc (&font_face->ref_count);
133 
134     return font_face;
135 }
136 slim_hidden_def (cairo_font_face_reference);
137 
138 static inline cairo_bool_t
__put(cairo_reference_count_t * v)139 __put(cairo_reference_count_t *v)
140 {
141     int c, old;
142 
143     c = CAIRO_REFERENCE_COUNT_GET_VALUE(v);
144     while (c != 1 && (old = _cairo_atomic_int_cmpxchg_return_old(&v->ref_count, c, c - 1)) != c)
145 	c = old;
146 
147     return c != 1;
148 }
149 
150 cairo_bool_t
_cairo_font_face_destroy(void * abstract_face)151 _cairo_font_face_destroy (void *abstract_face)
152 {
153 #if 0 /* Nothing needs to be done, we can just drop the last reference */
154     cairo_font_face_t *font_face = abstract_face;
155     return _cairo_reference_count_dec_and_test (&font_face->ref_count);
156 #endif
157     return TRUE;
158 }
159 
160 /**
161  * cairo_font_face_destroy:
162  * @font_face: a #cairo_font_face_t
163  *
164  * Decreases the reference count on @font_face by one. If the result
165  * is zero, then @font_face and all associated resources are freed.
166  * See cairo_font_face_reference().
167  *
168  * Since: 1.0
169  **/
170 void
cairo_font_face_destroy(cairo_font_face_t * font_face)171 cairo_font_face_destroy (cairo_font_face_t *font_face)
172 {
173     if (font_face == NULL ||
174 	CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
175 	return;
176 
177     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
178 
179     /* We allow resurrection to deal with some memory management for the
180      * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
181      * need to effectively mutually reference each other
182      */
183     if (__put (&font_face->ref_count))
184 	return;
185 
186     if (! font_face->backend->destroy (font_face))
187 	return;
188 
189     _cairo_user_data_array_fini (&font_face->user_data);
190 
191     free (font_face);
192 }
193 slim_hidden_def (cairo_font_face_destroy);
194 
195 /**
196  * cairo_font_face_get_type:
197  * @font_face: a font face
198  *
199  * This function returns the type of the backend used to create
200  * a font face. See #cairo_font_type_t for available types.
201  *
202  * Return value: The type of @font_face.
203  *
204  * Since: 1.2
205  **/
206 cairo_font_type_t
cairo_font_face_get_type(cairo_font_face_t * font_face)207 cairo_font_face_get_type (cairo_font_face_t *font_face)
208 {
209     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
210 	return CAIRO_FONT_TYPE_TOY;
211 
212     return font_face->backend->type;
213 }
214 
215 /**
216  * cairo_font_face_get_reference_count:
217  * @font_face: a #cairo_font_face_t
218  *
219  * Returns the current reference count of @font_face.
220  *
221  * Return value: the current reference count of @font_face.  If the
222  * object is a nil object, 0 will be returned.
223  *
224  * Since: 1.4
225  **/
226 unsigned int
cairo_font_face_get_reference_count(cairo_font_face_t * font_face)227 cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
228 {
229     if (font_face == NULL ||
230 	CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
231 	return 0;
232 
233     return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count);
234 }
235 
236 /**
237  * cairo_font_face_status:
238  * @font_face: a #cairo_font_face_t
239  *
240  * Checks whether an error has previously occurred for this
241  * font face
242  *
243  * Return value: %CAIRO_STATUS_SUCCESS or another error such as
244  *   %CAIRO_STATUS_NO_MEMORY.
245  *
246  * Since: 1.0
247  **/
248 cairo_status_t
cairo_font_face_status(cairo_font_face_t * font_face)249 cairo_font_face_status (cairo_font_face_t *font_face)
250 {
251     return font_face->status;
252 }
253 
254 /**
255  * cairo_font_face_get_user_data:
256  * @font_face: a #cairo_font_face_t
257  * @key: the address of the #cairo_user_data_key_t the user data was
258  * attached to
259  *
260  * Return user data previously attached to @font_face using the specified
261  * key.  If no user data has been attached with the given key this
262  * function returns %NULL.
263  *
264  * Return value: the user data previously attached or %NULL.
265  *
266  * Since: 1.0
267  **/
268 void *
cairo_font_face_get_user_data(cairo_font_face_t * font_face,const cairo_user_data_key_t * key)269 cairo_font_face_get_user_data (cairo_font_face_t	   *font_face,
270 			       const cairo_user_data_key_t *key)
271 {
272     return _cairo_user_data_array_get_data (&font_face->user_data,
273 					    key);
274 }
275 slim_hidden_def (cairo_font_face_get_user_data);
276 
277 /**
278  * cairo_font_face_set_user_data:
279  * @font_face: a #cairo_font_face_t
280  * @key: the address of a #cairo_user_data_key_t to attach the user data to
281  * @user_data: the user data to attach to the font face
282  * @destroy: a #cairo_destroy_func_t which will be called when the
283  * font face is destroyed or when new user data is attached using the
284  * same key.
285  *
286  * Attach user data to @font_face.  To remove user data from a font face,
287  * call this function with the key that was used to set it and %NULL
288  * for @data.
289  *
290  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
291  * slot could not be allocated for the user data.
292  *
293  * Since: 1.0
294  **/
295 cairo_status_t
cairo_font_face_set_user_data(cairo_font_face_t * font_face,const cairo_user_data_key_t * key,void * user_data,cairo_destroy_func_t destroy)296 cairo_font_face_set_user_data (cairo_font_face_t	   *font_face,
297 			       const cairo_user_data_key_t *key,
298 			       void			   *user_data,
299 			       cairo_destroy_func_t	    destroy)
300 {
301     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
302 	return font_face->status;
303 
304     return _cairo_user_data_array_set_data (&font_face->user_data,
305 					    key, user_data, destroy);
306 }
307 slim_hidden_def (cairo_font_face_set_user_data);
308 
309 void
_cairo_unscaled_font_init(cairo_unscaled_font_t * unscaled_font,const cairo_unscaled_font_backend_t * backend)310 _cairo_unscaled_font_init (cairo_unscaled_font_t               *unscaled_font,
311 			   const cairo_unscaled_font_backend_t *backend)
312 {
313     CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1);
314     unscaled_font->backend = backend;
315 }
316 
317 cairo_unscaled_font_t *
_cairo_unscaled_font_reference(cairo_unscaled_font_t * unscaled_font)318 _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
319 {
320     if (unscaled_font == NULL)
321 	return NULL;
322 
323     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
324 
325     _cairo_reference_count_inc (&unscaled_font->ref_count);
326 
327     return unscaled_font;
328 }
329 
330 void
_cairo_unscaled_font_destroy(cairo_unscaled_font_t * unscaled_font)331 _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
332 {
333     if (unscaled_font == NULL)
334 	return;
335 
336     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
337 
338     if (__put (&unscaled_font->ref_count))
339 	return;
340 
341     if (! unscaled_font->backend->destroy (unscaled_font))
342 	return;
343 
344     free (unscaled_font);
345 }
346