adg: avoid invalid access to private data
[adg.git] / src / adg / adg-toy-text.c
blob95cd20c47b6dbf422a3c61589b4bd3668bb4c904
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-toy-text
23 * @short_description: Simple text entity that uses the cairo "toy" text API
25 * The #AdgToyText class is a basic class to show simple text. It internally
26 * uses the so called cairo "toy" API and it shares the same limitations.
28 * The toy text entity is not subject to the local matrix, only its origin is.
30 * <note><para>
31 * By default, the #AdgEntity:local-mix property is set to
32 * #ADG_MIX_ANCESTORS_NORMALIZED on #AdgToyText entities.
33 * </para></note>
35 * Since: 1.0
36 **/
38 /**
39 * AdgToyText:
41 * All fields are privates and should not be used directly.
42 * Use its public methods instead.
44 * Since: 1.0
45 **/
48 #include "adg-internal.h"
49 #include "adg-dress.h"
50 #include "adg-style.h"
51 #include "adg-font-style.h"
52 #include "adg-textual.h"
54 #include "adg-toy-text.h"
55 #include "adg-toy-text-private.h"
58 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
59 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
62 static void _adg_iface_init (AdgTextualIface *iface);
65 G_DEFINE_TYPE_WITH_CODE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY,
66 G_IMPLEMENT_INTERFACE(ADG_TYPE_TEXTUAL, _adg_iface_init))
68 enum {
69 PROP_0,
70 PROP_FONT_DRESS,
71 PROP_TEXT
75 static void _adg_finalize (GObject *object);
76 static void _adg_get_property (GObject *object,
77 guint param_id,
78 GValue *value,
79 GParamSpec *pspec);
80 static void _adg_set_property (GObject *object,
81 guint param_id,
82 const GValue *value,
83 GParamSpec *pspec);
84 static void _adg_global_changed (AdgEntity *entity);
85 static void _adg_local_changed (AdgEntity *entity);
86 static void _adg_invalidate (AdgEntity *entity);
87 static void _adg_arrange (AdgEntity *entity);
88 static void _adg_render (AdgEntity *entity,
89 cairo_t *cr);
90 static void _adg_set_font_dress (AdgTextual *textual,
91 AdgDress dress);
92 static AdgDress _adg_get_font_dress (AdgTextual *textual);
93 static void _adg_set_text (AdgTextual *textual,
94 const gchar *text);
95 static gchar * _adg_dup_text (AdgTextual *textual);
96 static void _adg_clear_font (AdgToyText *toy_text);
97 static void _adg_clear_glyphs (AdgToyText *toy_text);
100 static void
101 adg_toy_text_class_init(AdgToyTextClass *klass)
103 GObjectClass *gobject_class;
104 AdgEntityClass *entity_class;
106 gobject_class = (GObjectClass *) klass;
107 entity_class = (AdgEntityClass *) klass;
109 g_type_class_add_private(klass, sizeof(AdgToyTextPrivate));
111 gobject_class->finalize = _adg_finalize;
112 gobject_class->get_property = _adg_get_property;
113 gobject_class->set_property = _adg_set_property;
115 entity_class->global_changed = _adg_global_changed;
116 entity_class->local_changed = _adg_local_changed;
117 entity_class->invalidate = _adg_invalidate;
118 entity_class->arrange = _adg_arrange;
119 entity_class->render = _adg_render;
121 g_object_class_override_property(gobject_class, PROP_FONT_DRESS, "font-dress");
122 g_object_class_override_property(gobject_class, PROP_TEXT, "text");
125 static void
126 _adg_iface_init(AdgTextualIface *iface)
128 iface->set_font_dress = _adg_set_font_dress;
129 iface->get_font_dress = _adg_get_font_dress;
130 iface->set_text = _adg_set_text;
131 iface->dup_text = _adg_dup_text;
132 iface->text_changed = NULL;
135 static void
136 adg_toy_text_init(AdgToyText *toy_text)
138 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
139 ADG_TYPE_TOY_TEXT,
140 AdgToyTextPrivate);
142 data->font_dress = ADG_DRESS_FONT_TEXT;
143 data->text = NULL;
144 data->glyphs = NULL;
146 toy_text->data = data;
148 adg_entity_set_local_mix((AdgEntity *) toy_text, ADG_MIX_ANCESTORS_NORMALIZED);
151 static void
152 _adg_finalize(GObject *object)
154 AdgToyText *toy_text;
155 AdgToyTextPrivate *data;
157 toy_text = (AdgToyText *) object;
158 data = toy_text->data;
160 g_free(data->text);
161 _adg_clear_font(toy_text);
162 _adg_clear_glyphs(toy_text);
164 if (_ADG_OLD_OBJECT_CLASS->finalize)
165 _ADG_OLD_OBJECT_CLASS->finalize(object);
168 static void
169 _adg_get_property(GObject *object, guint prop_id,
170 GValue *value, GParamSpec *pspec)
172 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
174 switch (prop_id) {
175 case PROP_FONT_DRESS:
176 g_value_set_enum(value, data->font_dress);
177 break;
178 case PROP_TEXT:
179 g_value_set_string(value, data->text);
180 break;
181 default:
182 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
183 break;
187 static void
188 _adg_set_property(GObject *object, guint prop_id,
189 const GValue *value, GParamSpec *pspec)
191 AdgToyText *toy_text;
192 AdgToyTextPrivate *data;
194 toy_text = (AdgToyText *) object;
195 data = toy_text->data;
197 switch (prop_id) {
198 case PROP_FONT_DRESS:
199 data->font_dress = g_value_get_enum(value);
200 _adg_clear_font(toy_text);
201 break;
202 case PROP_TEXT:
203 g_free(data->text);
204 data->text = g_value_dup_string(value);
205 _adg_clear_glyphs(toy_text);
206 break;
207 default:
208 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
209 break;
215 * adg_toy_text_new:
216 * @text: the text
218 * Creates a new toy text entity using @text as its content.
220 * Returns: the newly created toy text entity
222 * Since: 1.0
224 AdgToyText *
225 adg_toy_text_new(const gchar *text)
227 return g_object_new(ADG_TYPE_TOY_TEXT,
228 "text", text, NULL);
232 static void
233 _adg_global_changed(AdgEntity *entity)
235 if (_ADG_OLD_ENTITY_CLASS->global_changed)
236 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
238 adg_entity_invalidate(entity);
241 static void
242 _adg_local_changed(AdgEntity *entity)
244 if (_ADG_OLD_ENTITY_CLASS->local_changed)
245 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
247 adg_entity_invalidate(entity);
250 static void
251 _adg_invalidate(AdgEntity *entity)
253 _adg_clear_font((AdgToyText *) entity);
254 _adg_clear_glyphs((AdgToyText *) entity);
256 if (_ADG_OLD_ENTITY_CLASS->invalidate)
257 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
260 static void
261 _adg_arrange(AdgEntity *entity)
263 AdgToyText *toy_text;
264 AdgToyTextPrivate *data;
265 CpmlExtents extents;
267 toy_text = (AdgToyText *) entity;
268 data = toy_text->data;
270 if (data->font == NULL) {
271 AdgDress dress;
272 AdgFontStyle *font_style;
273 cairo_matrix_t ctm;
275 dress = data->font_dress;
276 font_style = (AdgFontStyle *) adg_entity_style(entity, dress);
278 adg_matrix_copy(&ctm, adg_entity_get_global_matrix(entity));
279 adg_matrix_transform(&ctm, adg_entity_get_local_matrix(entity),
280 ADG_TRANSFORM_BEFORE);
282 data->font = adg_font_style_get_scaled_font(font_style, &ctm);
285 if (adg_is_string_empty(data->text)) {
286 /* Undefined text */
287 extents.is_defined = FALSE;
288 } else if (data->glyphs != NULL) {
289 /* Cached result */
290 return;
291 } else {
292 cairo_status_t status;
293 cairo_text_extents_t cairo_extents;
295 status = cairo_scaled_font_text_to_glyphs(data->font, 0, 0,
296 data->text, -1,
297 &data->glyphs,
298 &data->num_glyphs,
299 NULL, NULL, NULL);
301 if (status != CAIRO_STATUS_SUCCESS) {
302 _adg_clear_glyphs(toy_text);
303 g_error(_("Unable to build glyphs (cairo message: %s)"),
304 cairo_status_to_string(status));
305 return;
308 cairo_scaled_font_glyph_extents(data->font, data->glyphs,
309 data->num_glyphs, &cairo_extents);
310 cpml_extents_from_cairo_text(&extents, &cairo_extents);
311 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
312 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
316 adg_entity_set_extents(entity, &extents);
319 static void
320 _adg_render(AdgEntity *entity, cairo_t *cr)
322 AdgToyText *toy_text;
323 AdgToyTextPrivate *data;
325 toy_text = (AdgToyText *) entity;
326 data = toy_text->data;
328 if (data->glyphs != NULL) {
329 adg_entity_apply_dress(entity, data->font_dress, cr);
330 cairo_transform(cr, adg_entity_get_global_matrix(entity));
331 cairo_transform(cr, adg_entity_get_local_matrix(entity));
332 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
336 static void
337 _adg_set_font_dress(AdgTextual *textual, AdgDress dress)
339 g_object_set(textual, "font-dress", dress, NULL);
342 static AdgDress
343 _adg_get_font_dress(AdgTextual *textual)
345 AdgToyTextPrivate *data = ((AdgToyText *) textual)->data;
346 return data->font_dress;
349 static void
350 _adg_set_text(AdgTextual *textual, const gchar *text)
352 g_object_set(textual, "text", text, NULL);
355 static gchar *
356 _adg_dup_text(AdgTextual *textual)
358 AdgToyTextPrivate *data = ((AdgToyText *) textual)->data;
359 return g_strdup(data->text);
362 static void
363 _adg_clear_font(AdgToyText *toy_text)
365 AdgToyTextPrivate *data = toy_text->data;
367 data->font = NULL;
370 static void
371 _adg_clear_glyphs(AdgToyText *toy_text)
373 AdgToyTextPrivate *data = toy_text->data;
375 if (data->glyphs != NULL) {
376 cairo_glyph_free(data->glyphs);
377 data->glyphs = NULL;
380 data->num_glyphs = 0;