| File: | ctk/ctkpango.c |
| Warning: | line 728, column 14 Access to field 'data' results in a dereference of a null pointer (loaded from variable 'l') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* ctkpango.c - pango-related utilities | |||
| 2 | * | |||
| 3 | * Copyright (c) 2010 Red Hat, Inc. | |||
| 4 | * | |||
| 5 | * This library is free software; you can redistribute it and/or | |||
| 6 | * modify it under the terms of the GNU Lesser General Public | |||
| 7 | * License as published by the Free Software Foundation; either | |||
| 8 | * version 2 of the License, or (at your option) any later version. | |||
| 9 | * | |||
| 10 | * This library is distributed in the hope that it will be useful, | |||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 13 | * Lesser General Public License for more details. | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU Lesser General Public | |||
| 16 | * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free | |||
| 17 | */ | |||
| 18 | /* | |||
| 19 | * Modified by the CTK+ Team and others 1997-2000. See the AUTHORS | |||
| 20 | * file for a list of people on the CTK+ Team. See the ChangeLog | |||
| 21 | * files for a list of changes. These files are distributed with | |||
| 22 | * CTK+ at ftp://ftp.ctk.org/pub/ctk/. | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include "config.h" | |||
| 26 | #include "ctkpango.h" | |||
| 27 | #include <pango/pangocairo.h> | |||
| 28 | #include <fribidi.h> | |||
| 29 | #include "ctkintl.h" | |||
| 30 | ||||
| 31 | #define CTK_TYPE_FILL_LAYOUT_RENDERER(_ctk_fill_layout_renderer_get_type()) (_ctk_fill_layout_renderer_get_type()) | |||
| 32 | #define CTK_FILL_LAYOUT_RENDERER(object)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((_ctk_fill_layout_renderer_get_type ())))))) (G_TYPE_CHECK_INSTANCE_CAST ((object), CTK_TYPE_FILL_LAYOUT_RENDERER, CtkFillLayoutRenderer)(((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((_ctk_fill_layout_renderer_get_type ())))))) | |||
| 33 | #define CTK_IS_FILL_LAYOUT_RENDERER(object)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (object)); GType __t = ((_ctk_fill_layout_renderer_get_type() )); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))) (G_TYPE_CHECK_INSTANCE_TYPE ((object), CTK_TYPE_FILL_LAYOUT_RENDERER)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (object)); GType __t = ((_ctk_fill_layout_renderer_get_type() )); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))) | |||
| 34 | #define CTK_FILL_LAYOUT_RENDERER_CLASS(klass)((((CtkFillLayoutRendererClass*) (void *) g_type_check_class_cast ((GTypeClass*) ((klass)), ((_ctk_fill_layout_renderer_get_type ())))))) (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_FILL_LAYOUT_RENDERER, CtkFillLayoutRendererClass)(((CtkFillLayoutRendererClass*) (void *) g_type_check_class_cast ((GTypeClass*) ((klass)), ((_ctk_fill_layout_renderer_get_type ())))))) | |||
| 35 | #define CTK_IS_FILL_LAYOUT_RENDERER_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass )); GType __t = ((_ctk_fill_layout_renderer_get_type())); gboolean __r; if (!__class) __r = (0); else if (__class->g_type == __t) __r = (!(0)); else __r = g_type_check_class_is_a (__class , __t); __r; })))) (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_FILL_LAYOUT_RENDERER)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass )); GType __t = ((_ctk_fill_layout_renderer_get_type())); gboolean __r; if (!__class) __r = (0); else if (__class->g_type == __t) __r = (!(0)); else __r = g_type_check_class_is_a (__class , __t); __r; })))) | |||
| 36 | #define CTK_FILL_LAYOUT_RENDERER_GET_CLASS(obj)((((CtkFillLayoutRendererClass*) (((GTypeInstance*) ((obj)))-> g_class)))) (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_FILL_LAYOUT_RENDERER, CtkFillLayoutRendererClass)(((CtkFillLayoutRendererClass*) (((GTypeInstance*) ((obj)))-> g_class)))) | |||
| 37 | ||||
| 38 | typedef struct _CtkFillLayoutRenderer CtkFillLayoutRenderer; | |||
| 39 | typedef struct _CtkFillLayoutRendererClass CtkFillLayoutRendererClass; | |||
| 40 | ||||
| 41 | struct _CtkFillLayoutRenderer | |||
| 42 | { | |||
| 43 | PangoRenderer parent_instance; | |||
| 44 | ||||
| 45 | cairo_t *cr; | |||
| 46 | }; | |||
| 47 | ||||
| 48 | struct _CtkFillLayoutRendererClass | |||
| 49 | { | |||
| 50 | PangoRendererClass parent_class; | |||
| 51 | }; | |||
| 52 | ||||
| 53 | GType _ctk_fill_layout_renderer_get_type (void); | |||
| 54 | ||||
| 55 | G_DEFINE_TYPE (CtkFillLayoutRenderer, _ctk_fill_layout_renderer, PANGO_TYPE_RENDERER)static void _ctk_fill_layout_renderer_init (CtkFillLayoutRenderer *self); static void _ctk_fill_layout_renderer_class_init (CtkFillLayoutRendererClass *klass); static GType _ctk_fill_layout_renderer_get_type_once (void); static gpointer _ctk_fill_layout_renderer_parent_class = ((void*)0); static gint CtkFillLayoutRenderer_private_offset ; static void _ctk_fill_layout_renderer_class_intern_init (gpointer klass) { _ctk_fill_layout_renderer_parent_class = g_type_class_peek_parent (klass); if (CtkFillLayoutRenderer_private_offset != 0) g_type_class_adjust_private_offset (klass, &CtkFillLayoutRenderer_private_offset); _ctk_fill_layout_renderer_class_init ((CtkFillLayoutRendererClass*) klass); } __attribute__ ((__unused__ )) static inline gpointer _ctk_fill_layout_renderer_get_instance_private (CtkFillLayoutRenderer *self) { return (((gpointer) ((guint8 *) (self) + (glong) (CtkFillLayoutRenderer_private_offset)))) ; } GType _ctk_fill_layout_renderer_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); (void) (0 ? (gpointer) * ( &static_g_define_type_id) : ((void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = _ctk_fill_layout_renderer_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void ) (*(&static_g_define_type_id) = (g_define_type_id)) : (void ) 0; g_once_init_leave_pointer ((&static_g_define_type_id ), (gpointer) (guintptr) (g_define_type_id)); })) ; } return static_g_define_type_id ; } __attribute__ ((__noinline__)) static GType _ctk_fill_layout_renderer_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple ((pango_renderer_get_type()), g_intern_static_string ("CtkFillLayoutRenderer" ), sizeof (CtkFillLayoutRendererClass), (GClassInitFunc)(void (*)(void)) _ctk_fill_layout_renderer_class_intern_init, sizeof (CtkFillLayoutRenderer), (GInstanceInitFunc)(void (*)(void)) _ctk_fill_layout_renderer_init, (GTypeFlags) 0); { {{};} } return g_define_type_id; } | |||
| 56 | ||||
| 57 | static void | |||
| 58 | ctk_fill_layout_renderer_draw_glyphs (PangoRenderer *renderer, | |||
| 59 | PangoFont *font, | |||
| 60 | PangoGlyphString *glyphs, | |||
| 61 | int x, | |||
| 62 | int y) | |||
| 63 | { | |||
| 64 | CtkFillLayoutRenderer *text_renderer = CTK_FILL_LAYOUT_RENDERER (renderer)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((renderer)), ((_ctk_fill_layout_renderer_get_type ())))))); | |||
| 65 | ||||
| 66 | cairo_move_to (text_renderer->cr, (double)x / PANGO_SCALE1024, (double)y / PANGO_SCALE1024); | |||
| 67 | pango_cairo_show_glyph_string (text_renderer->cr, font, glyphs); | |||
| 68 | } | |||
| 69 | ||||
| 70 | static void | |||
| 71 | ctk_fill_layout_renderer_draw_glyph_item (PangoRenderer *renderer, | |||
| 72 | const char *text, | |||
| 73 | PangoGlyphItem *glyph_item, | |||
| 74 | int x, | |||
| 75 | int y) | |||
| 76 | { | |||
| 77 | CtkFillLayoutRenderer *text_renderer = CTK_FILL_LAYOUT_RENDERER (renderer)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((renderer)), ((_ctk_fill_layout_renderer_get_type ())))))); | |||
| 78 | ||||
| 79 | cairo_move_to (text_renderer->cr, (double)x / PANGO_SCALE1024, (double)y / PANGO_SCALE1024); | |||
| 80 | pango_cairo_show_glyph_item (text_renderer->cr, text, glyph_item); | |||
| 81 | } | |||
| 82 | ||||
| 83 | static void | |||
| 84 | ctk_fill_layout_renderer_draw_rectangle (PangoRenderer *renderer, | |||
| 85 | PangoRenderPart part, | |||
| 86 | int x, | |||
| 87 | int y, | |||
| 88 | int width, | |||
| 89 | int height) | |||
| 90 | { | |||
| 91 | CtkFillLayoutRenderer *text_renderer = CTK_FILL_LAYOUT_RENDERER (renderer)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((renderer)), ((_ctk_fill_layout_renderer_get_type ())))))); | |||
| 92 | ||||
| 93 | if (part == PANGO_RENDER_PART_BACKGROUND) | |||
| 94 | return; | |||
| 95 | ||||
| 96 | cairo_rectangle (text_renderer->cr, | |||
| 97 | (double)x / PANGO_SCALE1024, (double)y / PANGO_SCALE1024, | |||
| 98 | (double)width / PANGO_SCALE1024, (double)height / PANGO_SCALE1024); | |||
| 99 | cairo_fill (text_renderer->cr); | |||
| 100 | } | |||
| 101 | ||||
| 102 | static void | |||
| 103 | ctk_fill_layout_renderer_draw_trapezoid (PangoRenderer *renderer, | |||
| 104 | PangoRenderPart part G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 105 | double y1_, | |||
| 106 | double x11, | |||
| 107 | double x21, | |||
| 108 | double y2, | |||
| 109 | double x12, | |||
| 110 | double x22) | |||
| 111 | { | |||
| 112 | CtkFillLayoutRenderer *text_renderer = CTK_FILL_LAYOUT_RENDERER (renderer)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((renderer)), ((_ctk_fill_layout_renderer_get_type ())))))); | |||
| 113 | cairo_matrix_t matrix; | |||
| 114 | cairo_t *cr; | |||
| 115 | ||||
| 116 | cr = text_renderer->cr; | |||
| 117 | ||||
| 118 | cairo_save (cr); | |||
| 119 | ||||
| 120 | /* use identity scale, but keep translation */ | |||
| 121 | cairo_get_matrix (cr, &matrix); | |||
| 122 | matrix.xx = matrix.yy = 1; | |||
| 123 | matrix.xy = matrix.yx = 0; | |||
| 124 | cairo_set_matrix (cr, &matrix); | |||
| 125 | ||||
| 126 | cairo_move_to (cr, x11, y1_); | |||
| 127 | cairo_line_to (cr, x21, y1_); | |||
| 128 | cairo_line_to (cr, x22, y2); | |||
| 129 | cairo_line_to (cr, x12, y2); | |||
| 130 | cairo_close_path (cr); | |||
| 131 | ||||
| 132 | cairo_fill (cr); | |||
| 133 | ||||
| 134 | cairo_restore (cr); | |||
| 135 | } | |||
| 136 | ||||
| 137 | static void | |||
| 138 | ctk_fill_layout_renderer_draw_error_underline (PangoRenderer *renderer, | |||
| 139 | int x, | |||
| 140 | int y, | |||
| 141 | int width, | |||
| 142 | int height) | |||
| 143 | { | |||
| 144 | CtkFillLayoutRenderer *text_renderer = CTK_FILL_LAYOUT_RENDERER (renderer)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((renderer)), ((_ctk_fill_layout_renderer_get_type ())))))); | |||
| 145 | ||||
| 146 | pango_cairo_show_error_underline (text_renderer->cr, | |||
| 147 | (double)x / PANGO_SCALE1024, (double)y / PANGO_SCALE1024, | |||
| 148 | (double)width / PANGO_SCALE1024, (double)height / PANGO_SCALE1024); | |||
| 149 | } | |||
| 150 | ||||
| 151 | static void | |||
| 152 | ctk_fill_layout_renderer_draw_shape (PangoRenderer *renderer, | |||
| 153 | PangoAttrShape *attr, | |||
| 154 | int x, | |||
| 155 | int y) | |||
| 156 | { | |||
| 157 | CtkFillLayoutRenderer *text_renderer = CTK_FILL_LAYOUT_RENDERER (renderer)((((CtkFillLayoutRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((renderer)), ((_ctk_fill_layout_renderer_get_type ())))))); | |||
| 158 | cairo_t *cr = text_renderer->cr; | |||
| 159 | PangoLayout *layout; | |||
| 160 | PangoCairoShapeRendererFunc shape_renderer; | |||
| 161 | gpointer shape_renderer_data; | |||
| 162 | ||||
| 163 | layout = pango_renderer_get_layout (renderer); | |||
| 164 | ||||
| 165 | if (!layout) | |||
| 166 | return; | |||
| 167 | ||||
| 168 | shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout), | |||
| 169 | &shape_renderer_data); | |||
| 170 | ||||
| 171 | if (!shape_renderer) | |||
| 172 | return; | |||
| 173 | ||||
| 174 | cairo_save (cr); | |||
| 175 | ||||
| 176 | cairo_move_to (cr, (double)x / PANGO_SCALE1024, (double)y / PANGO_SCALE1024); | |||
| 177 | ||||
| 178 | shape_renderer (cr, attr, FALSE(0), shape_renderer_data); | |||
| 179 | ||||
| 180 | cairo_restore (cr); | |||
| 181 | } | |||
| 182 | ||||
| 183 | static void | |||
| 184 | ctk_fill_layout_renderer_finalize (GObject *object) | |||
| 185 | { | |||
| 186 | G_OBJECT_CLASS (_ctk_fill_layout_renderer_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((_ctk_fill_layout_renderer_parent_class)), (((GType) ((20 ) << (2))))))))->finalize (object); | |||
| 187 | } | |||
| 188 | ||||
| 189 | static void | |||
| 190 | _ctk_fill_layout_renderer_init (CtkFillLayoutRenderer *renderer G_GNUC_UNUSED__attribute__ ((__unused__))) | |||
| 191 | { | |||
| 192 | } | |||
| 193 | ||||
| 194 | static void | |||
| 195 | _ctk_fill_layout_renderer_class_init (CtkFillLayoutRendererClass *klass) | |||
| 196 | { | |||
| 197 | GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); | |||
| 198 | ||||
| 199 | PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass)((((PangoRendererClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), ((pango_renderer_get_type())))))); | |||
| 200 | ||||
| 201 | renderer_class->draw_glyphs = ctk_fill_layout_renderer_draw_glyphs; | |||
| 202 | renderer_class->draw_glyph_item = ctk_fill_layout_renderer_draw_glyph_item; | |||
| 203 | renderer_class->draw_rectangle = ctk_fill_layout_renderer_draw_rectangle; | |||
| 204 | renderer_class->draw_trapezoid = ctk_fill_layout_renderer_draw_trapezoid; | |||
| 205 | renderer_class->draw_error_underline = ctk_fill_layout_renderer_draw_error_underline; | |||
| 206 | renderer_class->draw_shape = ctk_fill_layout_renderer_draw_shape; | |||
| 207 | ||||
| 208 | object_class->finalize = ctk_fill_layout_renderer_finalize; | |||
| 209 | } | |||
| 210 | ||||
| 211 | void | |||
| 212 | _ctk_pango_fill_layout (cairo_t *cr, | |||
| 213 | PangoLayout *layout) | |||
| 214 | { | |||
| 215 | static CtkFillLayoutRenderer *renderer = NULL((void*)0); | |||
| 216 | gboolean has_current_point; | |||
| 217 | double current_x, current_y; | |||
| 218 | ||||
| 219 | has_current_point = cairo_has_current_point (cr); | |||
| 220 | cairo_get_current_point (cr, ¤t_x, ¤t_y); | |||
| 221 | ||||
| 222 | if (renderer == NULL((void*)0)) | |||
| 223 | renderer = g_object_new (CTK_TYPE_FILL_LAYOUT_RENDERER(_ctk_fill_layout_renderer_get_type()), NULL((void*)0)); | |||
| 224 | ||||
| 225 | cairo_save (cr); | |||
| 226 | cairo_translate (cr, current_x, current_y); | |||
| 227 | ||||
| 228 | renderer->cr = cr; | |||
| 229 | pango_renderer_draw_layout (PANGO_RENDERER (renderer)((((PangoRenderer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((renderer)), ((pango_renderer_get_type())))))), layout, 0, 0); | |||
| 230 | ||||
| 231 | cairo_restore (cr); | |||
| 232 | ||||
| 233 | if (has_current_point) | |||
| 234 | cairo_move_to (cr, current_x, current_y); | |||
| 235 | } | |||
| 236 | ||||
| 237 | static AtkAttributeSet * | |||
| 238 | add_attribute (AtkAttributeSet *attributes, | |||
| 239 | AtkTextAttribute attr, | |||
| 240 | const gchar *value) | |||
| 241 | { | |||
| 242 | AtkAttribute *at; | |||
| 243 | ||||
| 244 | at = g_new (AtkAttribute, 1)((AtkAttribute *) g_malloc_n ((1), sizeof (AtkAttribute))); | |||
| 245 | at->name = g_strdup (atk_text_attribute_get_name (attr))g_strdup_inline (atk_text_attribute_get_name (attr)); | |||
| 246 | at->value = g_strdup (value)g_strdup_inline (value); | |||
| 247 | ||||
| 248 | return g_slist_prepend (attributes, at); | |||
| 249 | } | |||
| 250 | ||||
| 251 | /* | |||
| 252 | * _ctk_pango_get_default_attributes: | |||
| 253 | * @attributes: a #AtkAttributeSet to add the attributes to | |||
| 254 | * @layout: the #PangoLayout from which to get attributes | |||
| 255 | * | |||
| 256 | * Adds the default text attributes from @layout to @attributes, | |||
| 257 | * after translating them from Pango attributes to ATK attributes. | |||
| 258 | * | |||
| 259 | * This is a convenience function that can be used to implement | |||
| 260 | * support for the #AtkText interface in widgets using Pango | |||
| 261 | * layouts. | |||
| 262 | * | |||
| 263 | * Returns: the modified @attributes | |||
| 264 | */ | |||
| 265 | AtkAttributeSet* | |||
| 266 | _ctk_pango_get_default_attributes (AtkAttributeSet *attributes, | |||
| 267 | PangoLayout *layout) | |||
| 268 | { | |||
| 269 | PangoContext *context; | |||
| 270 | gint i; | |||
| 271 | PangoWrapMode mode; | |||
| 272 | ||||
| 273 | context = pango_layout_get_context (layout); | |||
| 274 | if (context) | |||
| 275 | { | |||
| 276 | PangoLanguage *language; | |||
| 277 | PangoFontDescription *font; | |||
| 278 | ||||
| 279 | language = pango_context_get_language (context); | |||
| 280 | if (language) | |||
| 281 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, | |||
| 282 | pango_language_to_string (language)((const char *)language)); | |||
| 283 | ||||
| 284 | font = pango_context_get_font_description (context); | |||
| 285 | if (font) | |||
| 286 | { | |||
| 287 | gchar buf[60]; | |||
| 288 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_STYLE, | |||
| 289 | atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, | |||
| 290 | pango_font_description_get_style (font))); | |||
| 291 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_VARIANT, | |||
| 292 | atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, | |||
| 293 | pango_font_description_get_variant (font))); | |||
| 294 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRETCH, | |||
| 295 | atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, | |||
| 296 | pango_font_description_get_stretch (font))); | |||
| 297 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, | |||
| 298 | pango_font_description_get_family (font)); | |||
| 299 | g_snprintf (buf, 60, "%d", pango_font_description_get_weight (font)); | |||
| 300 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, buf); | |||
| 301 | g_snprintf (buf, 60, "%i", pango_font_description_get_size (font) / PANGO_SCALE1024); | |||
| 302 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_SIZE, buf); | |||
| 303 | } | |||
| 304 | } | |||
| 305 | if (pango_layout_get_justify (layout)) | |||
| 306 | { | |||
| 307 | i = 3; | |||
| 308 | } | |||
| 309 | else | |||
| 310 | { | |||
| 311 | PangoAlignment align; | |||
| 312 | ||||
| 313 | align = pango_layout_get_alignment (layout); | |||
| 314 | if (align == PANGO_ALIGN_LEFT) | |||
| 315 | i = 0; | |||
| 316 | else if (align == PANGO_ALIGN_CENTER) | |||
| 317 | i = 2; | |||
| 318 | else /* PANGO_ALIGN_RIGHT */ | |||
| 319 | i = 1; | |||
| 320 | } | |||
| 321 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION, | |||
| 322 | atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, i)); | |||
| 323 | mode = pango_layout_get_wrap (layout); | |||
| 324 | if (mode == PANGO_WRAP_WORD) | |||
| 325 | i = 2; | |||
| 326 | else /* PANGO_WRAP_CHAR */ | |||
| 327 | i = 1; | |||
| 328 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE, | |||
| 329 | atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, i)); | |||
| 330 | ||||
| 331 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH, | |||
| 332 | atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0)); | |||
| 333 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE, | |||
| 334 | atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, 0)); | |||
| 335 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_RISE, "0"); | |||
| 336 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_SCALE, "1"); | |||
| 337 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, "0"); | |||
| 338 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, "0"); | |||
| 339 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, "0"); | |||
| 340 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, "0"); | |||
| 341 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_EDITABLE, | |||
| 342 | atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0)); | |||
| 343 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE, | |||
| 344 | atk_text_attribute_get_value (ATK_TEXT_ATTR_INVISIBLE, 0)); | |||
| 345 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_INDENT, "0"); | |||
| 346 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, "0"); | |||
| 347 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, "0"); | |||
| 348 | ||||
| 349 | return attributes; | |||
| 350 | } | |||
| 351 | ||||
| 352 | /* | |||
| 353 | * _ctk_pango_get_run_attributes: | |||
| 354 | * @attributes: a #AtkAttributeSet to add attributes to | |||
| 355 | * @layout: the #PangoLayout to get the attributes from | |||
| 356 | * @offset: the offset at which the attributes are wanted | |||
| 357 | * @start_offset: return location for the starting offset | |||
| 358 | * of the current run | |||
| 359 | * @end_offset: return location for the ending offset of the | |||
| 360 | * current run | |||
| 361 | * | |||
| 362 | * Finds the “run” around index (i.e. the maximal range of characters | |||
| 363 | * where the set of applicable attributes remains constant) and | |||
| 364 | * returns the starting and ending offsets for it. | |||
| 365 | * | |||
| 366 | * The attributes for the run are added to @attributes, after | |||
| 367 | * translating them from Pango attributes to ATK attributes. | |||
| 368 | * | |||
| 369 | * This is a convenience function that can be used to implement | |||
| 370 | * support for the #AtkText interface in widgets using Pango | |||
| 371 | * layouts. | |||
| 372 | * | |||
| 373 | * Returns: the modified #AtkAttributeSet | |||
| 374 | */ | |||
| 375 | AtkAttributeSet * | |||
| 376 | _ctk_pango_get_run_attributes (AtkAttributeSet *attributes, | |||
| 377 | PangoLayout *layout, | |||
| 378 | gint offset, | |||
| 379 | gint *start_offset, | |||
| 380 | gint *end_offset) | |||
| 381 | { | |||
| 382 | PangoAttrIterator *iter; | |||
| 383 | PangoAttrList *attr; | |||
| 384 | PangoAttrString *pango_string; | |||
| 385 | PangoAttrInt *pango_int; | |||
| 386 | PangoAttrColor *pango_color; | |||
| 387 | PangoAttrLanguage *pango_lang; | |||
| 388 | PangoAttrFloat *pango_float; | |||
| 389 | gint index, start_index, end_index; | |||
| 390 | gboolean is_next; | |||
| 391 | glong len; | |||
| 392 | const gchar *text; | |||
| 393 | gchar *value; | |||
| 394 | ||||
| 395 | text = pango_layout_get_text (layout); | |||
| 396 | len = g_utf8_strlen (text, -1); | |||
| 397 | ||||
| 398 | /* Grab the attributes of the PangoLayout, if any */ | |||
| 399 | attr = pango_layout_get_attributes (layout); | |||
| 400 | ||||
| 401 | if (attr == NULL((void*)0)) | |||
| 402 | { | |||
| 403 | *start_offset = 0; | |||
| 404 | *end_offset = len; | |||
| 405 | return attributes; | |||
| 406 | } | |||
| 407 | ||||
| 408 | iter = pango_attr_list_get_iterator (attr); | |||
| 409 | /* Get invariant range offsets */ | |||
| 410 | /* If offset out of range, set offset in range */ | |||
| 411 | if (offset > len) | |||
| 412 | offset = len; | |||
| 413 | else if (offset < 0) | |||
| 414 | offset = 0; | |||
| 415 | ||||
| 416 | index = g_utf8_offset_to_pointer (text, offset) - text; | |||
| 417 | pango_attr_iterator_range (iter, &start_index, &end_index); | |||
| 418 | is_next = TRUE(!(0)); | |||
| 419 | while (is_next) | |||
| 420 | { | |||
| 421 | if (index >= start_index && index < end_index) | |||
| 422 | { | |||
| 423 | *start_offset = g_utf8_pointer_to_offset (text, text + start_index); | |||
| 424 | if (end_index == G_MAXINT2147483647) /* Last iterator */ | |||
| 425 | end_index = len; | |||
| 426 | ||||
| 427 | *end_offset = g_utf8_pointer_to_offset (text, text + end_index); | |||
| 428 | break; | |||
| 429 | } | |||
| 430 | is_next = pango_attr_iterator_next (iter); | |||
| 431 | pango_attr_iterator_range (iter, &start_index, &end_index); | |||
| 432 | } | |||
| 433 | ||||
| 434 | /* Get attributes */ | |||
| 435 | pango_string = (PangoAttrString*) pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY); | |||
| 436 | if (pango_string != NULL((void*)0)) | |||
| 437 | { | |||
| 438 | value = g_strdup_printf ("%s", pango_string->value); | |||
| 439 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value); | |||
| 440 | g_free (value); | |||
| 441 | } | |||
| 442 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STYLE); | |||
| 443 | if (pango_int != NULL((void*)0)) | |||
| 444 | { | |||
| 445 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_STYLE, | |||
| 446 | atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_int->value)); | |||
| 447 | } | |||
| 448 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT); | |||
| 449 | if (pango_int != NULL((void*)0)) | |||
| 450 | { | |||
| 451 | value = g_strdup_printf ("%i", pango_int->value); | |||
| 452 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value); | |||
| 453 | g_free (value); | |||
| 454 | } | |||
| 455 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT); | |||
| 456 | if (pango_int != NULL((void*)0)) | |||
| 457 | { | |||
| 458 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_VARIANT, | |||
| 459 | atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_int->value)); | |||
| 460 | } | |||
| 461 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH); | |||
| 462 | if (pango_int != NULL((void*)0)) | |||
| 463 | { | |||
| 464 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRETCH, | |||
| 465 | atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_int->value)); | |||
| 466 | } | |||
| 467 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_SIZE); | |||
| 468 | if (pango_int != NULL((void*)0)) | |||
| 469 | { | |||
| 470 | value = g_strdup_printf ("%i", pango_int->value / PANGO_SCALE1024); | |||
| 471 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_SIZE, value); | |||
| 472 | g_free (value); | |||
| 473 | } | |||
| 474 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE); | |||
| 475 | if (pango_int != NULL((void*)0)) | |||
| 476 | { | |||
| 477 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE, | |||
| 478 | atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, pango_int->value)); | |||
| 479 | } | |||
| 480 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH); | |||
| 481 | if (pango_int != NULL((void*)0)) | |||
| 482 | { | |||
| 483 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH, | |||
| 484 | atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, pango_int->value)); | |||
| 485 | } | |||
| 486 | pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_RISE); | |||
| 487 | if (pango_int != NULL((void*)0)) | |||
| 488 | { | |||
| 489 | value = g_strdup_printf ("%i", pango_int->value); | |||
| 490 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_RISE, value); | |||
| 491 | g_free (value); | |||
| 492 | } | |||
| 493 | pango_lang = (PangoAttrLanguage*) pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE); | |||
| 494 | if (pango_lang != NULL((void*)0)) | |||
| 495 | { | |||
| 496 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, | |||
| 497 | pango_language_to_string (pango_lang->value)((const char *)pango_lang->value)); | |||
| 498 | } | |||
| 499 | pango_float = (PangoAttrFloat*) pango_attr_iterator_get (iter, PANGO_ATTR_SCALE); | |||
| 500 | if (pango_float != NULL((void*)0)) | |||
| 501 | { | |||
| 502 | value = g_strdup_printf ("%g", pango_float->value); | |||
| 503 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_SCALE, value); | |||
| 504 | g_free (value); | |||
| 505 | } | |||
| 506 | pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND); | |||
| 507 | if (pango_color != NULL((void*)0)) | |||
| 508 | { | |||
| 509 | value = g_strdup_printf ("%u,%u,%u", | |||
| 510 | pango_color->color.red, | |||
| 511 | pango_color->color.green, | |||
| 512 | pango_color->color.blue); | |||
| 513 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value); | |||
| 514 | g_free (value); | |||
| 515 | } | |||
| 516 | pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND); | |||
| 517 | if (pango_color != NULL((void*)0)) | |||
| 518 | { | |||
| 519 | value = g_strdup_printf ("%u,%u,%u", | |||
| 520 | pango_color->color.red, | |||
| 521 | pango_color->color.green, | |||
| 522 | pango_color->color.blue); | |||
| 523 | attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value); | |||
| 524 | g_free (value); | |||
| 525 | } | |||
| 526 | pango_attr_iterator_destroy (iter); | |||
| 527 | ||||
| 528 | return attributes; | |||
| 529 | } | |||
| 530 | ||||
| 531 | /* | |||
| 532 | * _ctk_pango_move_chars: | |||
| 533 | * @layout: a #PangoLayout | |||
| 534 | * @offset: a character offset in @layout | |||
| 535 | * @count: the number of characters to move from @offset | |||
| 536 | * | |||
| 537 | * Returns the position that is @count characters from the | |||
| 538 | * given @offset. @count may be positive or negative. | |||
| 539 | * | |||
| 540 | * For the purpose of this function, characters are defined | |||
| 541 | * by what Pango considers cursor positions. | |||
| 542 | * | |||
| 543 | * Returns: the new position | |||
| 544 | */ | |||
| 545 | gint | |||
| 546 | _ctk_pango_move_chars (PangoLayout *layout, | |||
| 547 | gint offset, | |||
| 548 | gint count) | |||
| 549 | { | |||
| 550 | const PangoLogAttr *attrs; | |||
| 551 | gint n_attrs; | |||
| 552 | ||||
| 553 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 554 | ||||
| 555 | while (count > 0 && offset < n_attrs - 1) | |||
| 556 | { | |||
| 557 | do | |||
| 558 | offset++; | |||
| 559 | while (offset < n_attrs - 1 && !attrs[offset].is_cursor_position); | |||
| 560 | ||||
| 561 | count--; | |||
| 562 | } | |||
| 563 | while (count < 0 && offset > 0) | |||
| 564 | { | |||
| 565 | do | |||
| 566 | offset--; | |||
| 567 | while (offset > 0 && !attrs[offset].is_cursor_position); | |||
| 568 | ||||
| 569 | count++; | |||
| 570 | } | |||
| 571 | ||||
| 572 | return offset; | |||
| 573 | } | |||
| 574 | ||||
| 575 | /* | |||
| 576 | * _ctk_pango_move_words: | |||
| 577 | * @layout: a #PangoLayout | |||
| 578 | * @offset: a character offset in @layout | |||
| 579 | * @count: the number of words to move from @offset | |||
| 580 | * | |||
| 581 | * Returns the position that is @count words from the | |||
| 582 | * given @offset. @count may be positive or negative. | |||
| 583 | * | |||
| 584 | * If @count is positive, the returned position will | |||
| 585 | * be a word end, otherwise it will be a word start. | |||
| 586 | * See the Pango documentation for details on how | |||
| 587 | * word starts and ends are defined. | |||
| 588 | * | |||
| 589 | * Returns: the new position | |||
| 590 | */ | |||
| 591 | gint | |||
| 592 | _ctk_pango_move_words (PangoLayout *layout, | |||
| 593 | gint offset, | |||
| 594 | gint count) | |||
| 595 | { | |||
| 596 | const PangoLogAttr *attrs; | |||
| 597 | gint n_attrs; | |||
| 598 | ||||
| 599 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 600 | ||||
| 601 | while (count > 0 && offset < n_attrs - 1) | |||
| 602 | { | |||
| 603 | do | |||
| 604 | offset++; | |||
| 605 | while (offset < n_attrs - 1 && !attrs[offset].is_word_end); | |||
| 606 | ||||
| 607 | count--; | |||
| 608 | } | |||
| 609 | while (count < 0 && offset > 0) | |||
| 610 | { | |||
| 611 | do | |||
| 612 | offset--; | |||
| 613 | while (offset > 0 && !attrs[offset].is_word_start); | |||
| 614 | ||||
| 615 | count++; | |||
| 616 | } | |||
| 617 | ||||
| 618 | return offset; | |||
| 619 | } | |||
| 620 | ||||
| 621 | /* | |||
| 622 | * _ctk_pango_move_sentences: | |||
| 623 | * @layout: a #PangoLayout | |||
| 624 | * @offset: a character offset in @layout | |||
| 625 | * @count: the number of sentences to move from @offset | |||
| 626 | * | |||
| 627 | * Returns the position that is @count sentences from the | |||
| 628 | * given @offset. @count may be positive or negative. | |||
| 629 | * | |||
| 630 | * If @count is positive, the returned position will | |||
| 631 | * be a sentence end, otherwise it will be a sentence start. | |||
| 632 | * See the Pango documentation for details on how | |||
| 633 | * sentence starts and ends are defined. | |||
| 634 | * | |||
| 635 | * Returns: the new position | |||
| 636 | */ | |||
| 637 | gint | |||
| 638 | _ctk_pango_move_sentences (PangoLayout *layout, | |||
| 639 | gint offset, | |||
| 640 | gint count) | |||
| 641 | { | |||
| 642 | const PangoLogAttr *attrs; | |||
| 643 | gint n_attrs; | |||
| 644 | ||||
| 645 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 646 | ||||
| 647 | while (count > 0 && offset < n_attrs - 1) | |||
| 648 | { | |||
| 649 | do | |||
| 650 | offset++; | |||
| 651 | while (offset < n_attrs - 1 && !attrs[offset].is_sentence_end); | |||
| 652 | ||||
| 653 | count--; | |||
| 654 | } | |||
| 655 | while (count < 0 && offset > 0) | |||
| 656 | { | |||
| 657 | do | |||
| 658 | offset--; | |||
| 659 | while (offset > 0 && !attrs[offset].is_sentence_start); | |||
| 660 | ||||
| 661 | count++; | |||
| 662 | } | |||
| 663 | ||||
| 664 | return offset; | |||
| 665 | } | |||
| 666 | ||||
| 667 | /* | |||
| 668 | * _ctk_pango_move_lines: | |||
| 669 | * @layout: a #PangoLayout | |||
| 670 | * @offset: a character offset in @layout | |||
| 671 | * @count: the number of lines to move from @offset | |||
| 672 | * | |||
| 673 | * Returns the position that is @count lines from the | |||
| 674 | * given @offset. @count may be positive or negative. | |||
| 675 | * | |||
| 676 | * If @count is negative, the returned position will | |||
| 677 | * be the start of a line, else it will be the end of | |||
| 678 | * line. | |||
| 679 | * | |||
| 680 | * Returns: the new position | |||
| 681 | */ | |||
| 682 | gint | |||
| 683 | _ctk_pango_move_lines (PangoLayout *layout, | |||
| 684 | gint offset, | |||
| 685 | gint count) | |||
| 686 | { | |||
| 687 | GSList *lines, *l; | |||
| 688 | PangoLayoutLine *line; | |||
| 689 | gint num; | |||
| 690 | const gchar *text; | |||
| 691 | gint pos, line_pos; | |||
| 692 | gint index; | |||
| 693 | gint len; | |||
| 694 | ||||
| 695 | text = pango_layout_get_text (layout); | |||
| 696 | index = g_utf8_offset_to_pointer (text, offset) - text; | |||
| 697 | lines = pango_layout_get_lines (layout); | |||
| 698 | line = NULL((void*)0); | |||
| 699 | ||||
| 700 | num = 0; | |||
| 701 | for (l = lines; l; l = l->next) | |||
| ||||
| 702 | { | |||
| 703 | line = l->data; | |||
| 704 | if (index < line->start_index + line->length) | |||
| 705 | break; | |||
| 706 | num++; | |||
| 707 | } | |||
| 708 | ||||
| 709 | if (count < 0) | |||
| 710 | { | |||
| 711 | num += count; | |||
| 712 | if (num < 0) | |||
| 713 | num = 0; | |||
| 714 | ||||
| 715 | line = g_slist_nth_data (lines, num); | |||
| 716 | ||||
| 717 | return g_utf8_pointer_to_offset (text, text + line->start_index); | |||
| 718 | } | |||
| 719 | else | |||
| 720 | { | |||
| 721 | line_pos = index - line->start_index; | |||
| 722 | ||||
| 723 | len = g_slist_length (lines); | |||
| 724 | num += count; | |||
| 725 | if (num >= len || (count == 0 && num == len - 1)) | |||
| 726 | return g_utf8_strlen (text, -1) - 1; | |||
| 727 | ||||
| 728 | line = l->data; | |||
| ||||
| 729 | pos = line->start_index + line_pos; | |||
| 730 | if (pos >= line->start_index + line->length) | |||
| 731 | pos = line->start_index + line->length - 1; | |||
| 732 | ||||
| 733 | return g_utf8_pointer_to_offset (text, text + pos); | |||
| 734 | } | |||
| 735 | } | |||
| 736 | ||||
| 737 | /* | |||
| 738 | * _ctk_pango_is_inside_word: | |||
| 739 | * @layout: a #PangoLayout | |||
| 740 | * @offset: a character offset in @layout | |||
| 741 | * | |||
| 742 | * Returns whether the given position is inside | |||
| 743 | * a word. | |||
| 744 | * | |||
| 745 | * Returns: %TRUE if @offset is inside a word | |||
| 746 | */ | |||
| 747 | gboolean | |||
| 748 | _ctk_pango_is_inside_word (PangoLayout *layout, | |||
| 749 | gint offset) | |||
| 750 | { | |||
| 751 | const PangoLogAttr *attrs; | |||
| 752 | gint n_attrs; | |||
| 753 | ||||
| 754 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 755 | ||||
| 756 | while (offset >= 0 && | |||
| 757 | !(attrs[offset].is_word_start || attrs[offset].is_word_end)) | |||
| 758 | offset--; | |||
| 759 | ||||
| 760 | if (offset >= 0) | |||
| 761 | return attrs[offset].is_word_start; | |||
| 762 | ||||
| 763 | return FALSE(0); | |||
| 764 | } | |||
| 765 | ||||
| 766 | /* | |||
| 767 | * _ctk_pango_is_inside_sentence: | |||
| 768 | * @layout: a #PangoLayout | |||
| 769 | * @offset: a character offset in @layout | |||
| 770 | * | |||
| 771 | * Returns whether the given position is inside | |||
| 772 | * a sentence. | |||
| 773 | * | |||
| 774 | * Returns: %TRUE if @offset is inside a sentence | |||
| 775 | */ | |||
| 776 | gboolean | |||
| 777 | _ctk_pango_is_inside_sentence (PangoLayout *layout, | |||
| 778 | gint offset) | |||
| 779 | { | |||
| 780 | const PangoLogAttr *attrs; | |||
| 781 | gint n_attrs; | |||
| 782 | ||||
| 783 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 784 | ||||
| 785 | while (offset >= 0 && | |||
| 786 | !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end)) | |||
| 787 | offset--; | |||
| 788 | ||||
| 789 | if (offset >= 0) | |||
| 790 | return attrs[offset].is_sentence_start; | |||
| 791 | ||||
| 792 | return FALSE(0); | |||
| 793 | } | |||
| 794 | ||||
| 795 | static void | |||
| 796 | pango_layout_get_line_before (PangoLayout *layout, | |||
| 797 | AtkTextBoundary boundary_type, | |||
| 798 | gint offset, | |||
| 799 | gint *start_offset, | |||
| 800 | gint *end_offset) | |||
| 801 | { | |||
| 802 | PangoLayoutIter *iter; | |||
| 803 | PangoLayoutLine *line, *prev_line = NULL((void*)0), *prev_prev_line = NULL((void*)0); | |||
| 804 | gint index, start_index, end_index; | |||
| 805 | const gchar *text; | |||
| 806 | gboolean found = FALSE(0); | |||
| 807 | ||||
| 808 | text = pango_layout_get_text (layout); | |||
| 809 | index = g_utf8_offset_to_pointer (text, offset) - text; | |||
| 810 | iter = pango_layout_get_iter (layout); | |||
| 811 | do | |||
| 812 | { | |||
| 813 | line = pango_layout_iter_get_line (iter); | |||
| 814 | start_index = line->start_index; | |||
| 815 | end_index = start_index + line->length; | |||
| 816 | ||||
| 817 | if (index >= start_index && index <= end_index) | |||
| 818 | { | |||
| 819 | /* Found line for offset */ | |||
| 820 | if (prev_line) | |||
| 821 | { | |||
| 822 | switch (boundary_type) | |||
| 823 | { | |||
| 824 | case ATK_TEXT_BOUNDARY_LINE_START: | |||
| 825 | end_index = start_index; | |||
| 826 | start_index = prev_line->start_index; | |||
| 827 | break; | |||
| 828 | case ATK_TEXT_BOUNDARY_LINE_END: | |||
| 829 | if (prev_prev_line) | |||
| 830 | start_index = prev_prev_line->start_index + prev_prev_line->length; | |||
| 831 | else | |||
| 832 | start_index = 0; | |||
| 833 | end_index = prev_line->start_index + prev_line->length; | |||
| 834 | break; | |||
| 835 | default: | |||
| 836 | g_assert_not_reached()do { g_assertion_message_expr ("Ctk", "ctkpango.c", 836, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 837 | } | |||
| 838 | } | |||
| 839 | else | |||
| 840 | start_index = end_index = 0; | |||
| 841 | ||||
| 842 | found = TRUE(!(0)); | |||
| 843 | break; | |||
| 844 | } | |||
| 845 | ||||
| 846 | prev_prev_line = prev_line; | |||
| 847 | prev_line = line; | |||
| 848 | } | |||
| 849 | while (pango_layout_iter_next_line (iter)); | |||
| 850 | ||||
| 851 | if (!found) | |||
| 852 | { | |||
| 853 | start_index = prev_line->start_index + prev_line->length; | |||
| 854 | end_index = start_index; | |||
| 855 | } | |||
| 856 | pango_layout_iter_free (iter); | |||
| 857 | ||||
| 858 | *start_offset = g_utf8_pointer_to_offset (text, text + start_index); | |||
| 859 | *end_offset = g_utf8_pointer_to_offset (text, text + end_index); | |||
| 860 | } | |||
| 861 | ||||
| 862 | static void | |||
| 863 | pango_layout_get_line_at (PangoLayout *layout, | |||
| 864 | AtkTextBoundary boundary_type, | |||
| 865 | gint offset, | |||
| 866 | gint *start_offset, | |||
| 867 | gint *end_offset) | |||
| 868 | { | |||
| 869 | PangoLayoutIter *iter; | |||
| 870 | PangoLayoutLine *line, *prev_line = NULL((void*)0); | |||
| 871 | gint index, start_index, end_index; | |||
| 872 | const gchar *text; | |||
| 873 | gboolean found = FALSE(0); | |||
| 874 | ||||
| 875 | text = pango_layout_get_text (layout); | |||
| 876 | index = g_utf8_offset_to_pointer (text, offset) - text; | |||
| 877 | iter = pango_layout_get_iter (layout); | |||
| 878 | do | |||
| 879 | { | |||
| 880 | line = pango_layout_iter_get_line (iter); | |||
| 881 | start_index = line->start_index; | |||
| 882 | end_index = start_index + line->length; | |||
| 883 | ||||
| 884 | if (index >= start_index && index <= end_index) | |||
| 885 | { | |||
| 886 | /* Found line for offset */ | |||
| 887 | switch (boundary_type) | |||
| 888 | { | |||
| 889 | case ATK_TEXT_BOUNDARY_LINE_START: | |||
| 890 | if (pango_layout_iter_next_line (iter)) | |||
| 891 | end_index = pango_layout_iter_get_line (iter)->start_index; | |||
| 892 | break; | |||
| 893 | case ATK_TEXT_BOUNDARY_LINE_END: | |||
| 894 | if (prev_line) | |||
| 895 | start_index = prev_line->start_index + prev_line->length; | |||
| 896 | break; | |||
| 897 | default: | |||
| 898 | g_assert_not_reached()do { g_assertion_message_expr ("Ctk", "ctkpango.c", 898, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 899 | } | |||
| 900 | ||||
| 901 | found = TRUE(!(0)); | |||
| 902 | break; | |||
| 903 | } | |||
| 904 | ||||
| 905 | prev_line = line; | |||
| 906 | } | |||
| 907 | while (pango_layout_iter_next_line (iter)); | |||
| 908 | ||||
| 909 | if (!found) | |||
| 910 | { | |||
| 911 | start_index = prev_line->start_index + prev_line->length; | |||
| 912 | end_index = start_index; | |||
| 913 | } | |||
| 914 | pango_layout_iter_free (iter); | |||
| 915 | ||||
| 916 | *start_offset = g_utf8_pointer_to_offset (text, text + start_index); | |||
| 917 | *end_offset = g_utf8_pointer_to_offset (text, text + end_index); | |||
| 918 | } | |||
| 919 | ||||
| 920 | static void | |||
| 921 | pango_layout_get_line_after (PangoLayout *layout, | |||
| 922 | AtkTextBoundary boundary_type, | |||
| 923 | gint offset, | |||
| 924 | gint *start_offset, | |||
| 925 | gint *end_offset) | |||
| 926 | { | |||
| 927 | PangoLayoutIter *iter; | |||
| 928 | PangoLayoutLine *line, *prev_line = NULL((void*)0); | |||
| 929 | gint index, start_index, end_index; | |||
| 930 | const gchar *text; | |||
| 931 | gboolean found = FALSE(0); | |||
| 932 | ||||
| 933 | text = pango_layout_get_text (layout); | |||
| 934 | index = g_utf8_offset_to_pointer (text, offset) - text; | |||
| 935 | iter = pango_layout_get_iter (layout); | |||
| 936 | do | |||
| 937 | { | |||
| 938 | line = pango_layout_iter_get_line (iter); | |||
| 939 | start_index = line->start_index; | |||
| 940 | end_index = start_index + line->length; | |||
| 941 | ||||
| 942 | if (index >= start_index && index <= end_index) | |||
| 943 | { | |||
| 944 | /* Found line for offset */ | |||
| 945 | if (pango_layout_iter_next_line (iter)) | |||
| 946 | { | |||
| 947 | line = pango_layout_iter_get_line (iter); | |||
| 948 | switch (boundary_type) | |||
| 949 | { | |||
| 950 | case ATK_TEXT_BOUNDARY_LINE_START: | |||
| 951 | start_index = line->start_index; | |||
| 952 | if (pango_layout_iter_next_line (iter)) | |||
| 953 | end_index = pango_layout_iter_get_line (iter)->start_index; | |||
| 954 | else | |||
| 955 | end_index = start_index + line->length; | |||
| 956 | break; | |||
| 957 | case ATK_TEXT_BOUNDARY_LINE_END: | |||
| 958 | start_index = end_index; | |||
| 959 | end_index = line->start_index + line->length; | |||
| 960 | break; | |||
| 961 | default: | |||
| 962 | g_assert_not_reached()do { g_assertion_message_expr ("Ctk", "ctkpango.c", 962, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 963 | } | |||
| 964 | } | |||
| 965 | else | |||
| 966 | start_index = end_index; | |||
| 967 | ||||
| 968 | found = TRUE(!(0)); | |||
| 969 | break; | |||
| 970 | } | |||
| 971 | ||||
| 972 | prev_line = line; | |||
| 973 | } | |||
| 974 | while (pango_layout_iter_next_line (iter)); | |||
| 975 | ||||
| 976 | if (!found) | |||
| 977 | { | |||
| 978 | start_index = prev_line->start_index + prev_line->length; | |||
| 979 | end_index = start_index; | |||
| 980 | } | |||
| 981 | pango_layout_iter_free (iter); | |||
| 982 | ||||
| 983 | *start_offset = g_utf8_pointer_to_offset (text, text + start_index); | |||
| 984 | *end_offset = g_utf8_pointer_to_offset (text, text + end_index); | |||
| 985 | } | |||
| 986 | ||||
| 987 | /* | |||
| 988 | * _ctk_pango_get_text_before: | |||
| 989 | * @layout: a #PangoLayout | |||
| 990 | * @boundary_type: a #AtkTextBoundary | |||
| 991 | * @offset: a character offset in @layout | |||
| 992 | * @start_offset: return location for the start of the returned text | |||
| 993 | * @end_offset: return location for the end of the return text | |||
| 994 | * | |||
| 995 | * Gets a slice of the text from @layout before @offset. | |||
| 996 | * | |||
| 997 | * The @boundary_type determines the size of the returned slice of | |||
| 998 | * text. For the exact semantics of this function, see | |||
| 999 | * atk_text_get_text_before_offset(). | |||
| 1000 | * | |||
| 1001 | * Returns: a newly allocated string containing a slice of text | |||
| 1002 | * from layout. Free with g_free(). | |||
| 1003 | */ | |||
| 1004 | gchar * | |||
| 1005 | _ctk_pango_get_text_before (PangoLayout *layout, | |||
| 1006 | AtkTextBoundary boundary_type, | |||
| 1007 | gint offset, | |||
| 1008 | gint *start_offset, | |||
| 1009 | gint *end_offset) | |||
| 1010 | { | |||
| 1011 | const gchar *text; | |||
| 1012 | gint start, end; | |||
| 1013 | const PangoLogAttr *attrs; | |||
| 1014 | gint n_attrs; | |||
| 1015 | ||||
| 1016 | text = pango_layout_get_text (layout); | |||
| 1017 | ||||
| 1018 | if (text[0] == 0) | |||
| 1019 | { | |||
| 1020 | *start_offset = 0; | |||
| 1021 | *end_offset = 0; | |||
| 1022 | return g_strdup ("")g_strdup_inline (""); | |||
| 1023 | } | |||
| 1024 | ||||
| 1025 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 1026 | ||||
| 1027 | start = offset; | |||
| 1028 | end = start; | |||
| 1029 | ||||
| 1030 | switch (boundary_type) | |||
| 1031 | { | |||
| 1032 | case ATK_TEXT_BOUNDARY_CHAR: | |||
| 1033 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1034 | break; | |||
| 1035 | ||||
| 1036 | case ATK_TEXT_BOUNDARY_WORD_START: | |||
| 1037 | if (!attrs[start].is_word_start) | |||
| 1038 | start = _ctk_pango_move_words (layout, start, -1); | |||
| 1039 | end = start; | |||
| 1040 | start = _ctk_pango_move_words (layout, start, -1); | |||
| 1041 | break; | |||
| 1042 | ||||
| 1043 | case ATK_TEXT_BOUNDARY_WORD_END: | |||
| 1044 | if (_ctk_pango_is_inside_word (layout, start) && | |||
| 1045 | !attrs[start].is_word_start) | |||
| 1046 | start = _ctk_pango_move_words (layout, start, -1); | |||
| 1047 | while (!attrs[start].is_word_end && start > 0) | |||
| 1048 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1049 | end = start; | |||
| 1050 | start = _ctk_pango_move_words (layout, start, -1); | |||
| 1051 | while (!attrs[start].is_word_end && start > 0) | |||
| 1052 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1053 | break; | |||
| 1054 | ||||
| 1055 | case ATK_TEXT_BOUNDARY_SENTENCE_START: | |||
| 1056 | if (!attrs[start].is_sentence_start) | |||
| 1057 | start = _ctk_pango_move_sentences (layout, start, -1); | |||
| 1058 | end = start; | |||
| 1059 | start = _ctk_pango_move_sentences (layout, start, -1); | |||
| 1060 | break; | |||
| 1061 | ||||
| 1062 | case ATK_TEXT_BOUNDARY_SENTENCE_END: | |||
| 1063 | if (_ctk_pango_is_inside_sentence (layout, start) && | |||
| 1064 | !attrs[start].is_sentence_start) | |||
| 1065 | start = _ctk_pango_move_sentences (layout, start, -1); | |||
| 1066 | while (!attrs[start].is_sentence_end && start > 0) | |||
| 1067 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1068 | end = start; | |||
| 1069 | start = _ctk_pango_move_sentences (layout, start, -1); | |||
| 1070 | while (!attrs[start].is_sentence_end && start > 0) | |||
| 1071 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1072 | break; | |||
| 1073 | ||||
| 1074 | case ATK_TEXT_BOUNDARY_LINE_START: | |||
| 1075 | case ATK_TEXT_BOUNDARY_LINE_END: | |||
| 1076 | pango_layout_get_line_before (layout, boundary_type, offset, &start, &end); | |||
| 1077 | break; | |||
| 1078 | } | |||
| 1079 | ||||
| 1080 | *start_offset = start; | |||
| 1081 | *end_offset = end; | |||
| 1082 | ||||
| 1083 | g_assert (start <= end)do { if (start <= end) ; else g_assertion_message_expr ("Ctk" , "ctkpango.c", 1083, ((const char*) (__func__)), "start <= end" ); } while (0); | |||
| 1084 | ||||
| 1085 | return g_utf8_substring (text, start, end); | |||
| 1086 | } | |||
| 1087 | ||||
| 1088 | /* | |||
| 1089 | * _ctk_pango_get_text_after: | |||
| 1090 | * @layout: a #PangoLayout | |||
| 1091 | * @boundary_type: a #AtkTextBoundary | |||
| 1092 | * @offset: a character offset in @layout | |||
| 1093 | * @start_offset: return location for the start of the returned text | |||
| 1094 | * @end_offset: return location for the end of the return text | |||
| 1095 | * | |||
| 1096 | * Gets a slice of the text from @layout after @offset. | |||
| 1097 | * | |||
| 1098 | * The @boundary_type determines the size of the returned slice of | |||
| 1099 | * text. For the exact semantics of this function, see | |||
| 1100 | * atk_text_get_text_after_offset(). | |||
| 1101 | * | |||
| 1102 | * Returns: a newly allocated string containing a slice of text | |||
| 1103 | * from layout. Free with g_free(). | |||
| 1104 | */ | |||
| 1105 | gchar * | |||
| 1106 | _ctk_pango_get_text_after (PangoLayout *layout, | |||
| 1107 | AtkTextBoundary boundary_type, | |||
| 1108 | gint offset, | |||
| 1109 | gint *start_offset, | |||
| 1110 | gint *end_offset) | |||
| 1111 | { | |||
| 1112 | const gchar *text; | |||
| 1113 | gint start, end; | |||
| 1114 | const PangoLogAttr *attrs; | |||
| 1115 | gint n_attrs; | |||
| 1116 | ||||
| 1117 | text = pango_layout_get_text (layout); | |||
| 1118 | ||||
| 1119 | if (text[0] == 0) | |||
| 1120 | { | |||
| 1121 | *start_offset = 0; | |||
| 1122 | *end_offset = 0; | |||
| 1123 | return g_strdup ("")g_strdup_inline (""); | |||
| 1124 | } | |||
| 1125 | ||||
| 1126 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 1127 | ||||
| 1128 | start = offset; | |||
| 1129 | end = start; | |||
| 1130 | ||||
| 1131 | switch (boundary_type) | |||
| 1132 | { | |||
| 1133 | case ATK_TEXT_BOUNDARY_CHAR: | |||
| 1134 | start = _ctk_pango_move_chars (layout, start, 1); | |||
| 1135 | end = start; | |||
| 1136 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1137 | break; | |||
| 1138 | ||||
| 1139 | case ATK_TEXT_BOUNDARY_WORD_START: | |||
| 1140 | if (_ctk_pango_is_inside_word (layout, end)) | |||
| 1141 | end = _ctk_pango_move_words (layout, end, 1); | |||
| 1142 | while (!attrs[end].is_word_start && end < n_attrs - 1) | |||
| 1143 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1144 | start = end; | |||
| 1145 | if (end < n_attrs - 1) | |||
| 1146 | { | |||
| 1147 | end = _ctk_pango_move_words (layout, end, 1); | |||
| 1148 | while (!attrs[end].is_word_start && end < n_attrs - 1) | |||
| 1149 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1150 | } | |||
| 1151 | break; | |||
| 1152 | ||||
| 1153 | case ATK_TEXT_BOUNDARY_WORD_END: | |||
| 1154 | end = _ctk_pango_move_words (layout, end, 1); | |||
| 1155 | start = end; | |||
| 1156 | if (end < n_attrs - 1) | |||
| 1157 | end = _ctk_pango_move_words (layout, end, 1); | |||
| 1158 | break; | |||
| 1159 | ||||
| 1160 | case ATK_TEXT_BOUNDARY_SENTENCE_START: | |||
| 1161 | if (_ctk_pango_is_inside_sentence (layout, end)) | |||
| 1162 | end = _ctk_pango_move_sentences (layout, end, 1); | |||
| 1163 | while (!attrs[end].is_sentence_start && end < n_attrs - 1) | |||
| 1164 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1165 | start = end; | |||
| 1166 | if (end < n_attrs - 1) | |||
| 1167 | { | |||
| 1168 | end = _ctk_pango_move_sentences (layout, end, 1); | |||
| 1169 | while (!attrs[end].is_sentence_start && end < n_attrs - 1) | |||
| 1170 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1171 | } | |||
| 1172 | break; | |||
| 1173 | ||||
| 1174 | case ATK_TEXT_BOUNDARY_SENTENCE_END: | |||
| 1175 | end = _ctk_pango_move_sentences (layout, end, 1); | |||
| 1176 | start = end; | |||
| 1177 | if (end < n_attrs - 1) | |||
| 1178 | end = _ctk_pango_move_sentences (layout, end, 1); | |||
| 1179 | break; | |||
| 1180 | ||||
| 1181 | case ATK_TEXT_BOUNDARY_LINE_START: | |||
| 1182 | case ATK_TEXT_BOUNDARY_LINE_END: | |||
| 1183 | pango_layout_get_line_after (layout, boundary_type, offset, &start, &end); | |||
| 1184 | break; | |||
| 1185 | } | |||
| 1186 | ||||
| 1187 | *start_offset = start; | |||
| 1188 | *end_offset = end; | |||
| 1189 | ||||
| 1190 | g_assert (start <= end)do { if (start <= end) ; else g_assertion_message_expr ("Ctk" , "ctkpango.c", 1190, ((const char*) (__func__)), "start <= end" ); } while (0); | |||
| 1191 | ||||
| 1192 | return g_utf8_substring (text, start, end); | |||
| 1193 | } | |||
| 1194 | ||||
| 1195 | /* | |||
| 1196 | * _ctk_pango_get_text_at: | |||
| 1197 | * @layout: a #PangoLayout | |||
| 1198 | * @boundary_type: a #AtkTextBoundary | |||
| 1199 | * @offset: a character offset in @layout | |||
| 1200 | * @start_offset: return location for the start of the returned text | |||
| 1201 | * @end_offset: return location for the end of the return text | |||
| 1202 | * | |||
| 1203 | * Gets a slice of the text from @layout at @offset. | |||
| 1204 | * | |||
| 1205 | * The @boundary_type determines the size of the returned slice of | |||
| 1206 | * text. For the exact semantics of this function, see | |||
| 1207 | * atk_text_get_text_after_offset(). | |||
| 1208 | * | |||
| 1209 | * Returns: a newly allocated string containing a slice of text | |||
| 1210 | * from layout. Free with g_free(). | |||
| 1211 | */ | |||
| 1212 | gchar * | |||
| 1213 | _ctk_pango_get_text_at (PangoLayout *layout, | |||
| 1214 | AtkTextBoundary boundary_type, | |||
| 1215 | gint offset, | |||
| 1216 | gint *start_offset, | |||
| 1217 | gint *end_offset) | |||
| 1218 | { | |||
| 1219 | const gchar *text; | |||
| 1220 | gint start, end; | |||
| 1221 | const PangoLogAttr *attrs; | |||
| 1222 | gint n_attrs; | |||
| 1223 | ||||
| 1224 | text = pango_layout_get_text (layout); | |||
| 1225 | ||||
| 1226 | if (text[0] == 0) | |||
| 1227 | { | |||
| 1228 | *start_offset = 0; | |||
| 1229 | *end_offset = 0; | |||
| 1230 | return g_strdup ("")g_strdup_inline (""); | |||
| 1231 | } | |||
| 1232 | ||||
| 1233 | attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); | |||
| 1234 | ||||
| 1235 | start = offset; | |||
| 1236 | end = start; | |||
| 1237 | ||||
| 1238 | switch (boundary_type) | |||
| 1239 | { | |||
| 1240 | case ATK_TEXT_BOUNDARY_CHAR: | |||
| 1241 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1242 | break; | |||
| 1243 | ||||
| 1244 | case ATK_TEXT_BOUNDARY_WORD_START: | |||
| 1245 | if (!attrs[start].is_word_start) | |||
| 1246 | start = _ctk_pango_move_words (layout, start, -1); | |||
| 1247 | if (_ctk_pango_is_inside_word (layout, end)) | |||
| 1248 | end = _ctk_pango_move_words (layout, end, 1); | |||
| 1249 | while (!attrs[end].is_word_start && end < n_attrs - 1) | |||
| 1250 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1251 | break; | |||
| 1252 | ||||
| 1253 | case ATK_TEXT_BOUNDARY_WORD_END: | |||
| 1254 | if (_ctk_pango_is_inside_word (layout, start) && | |||
| 1255 | !attrs[start].is_word_start) | |||
| 1256 | start = _ctk_pango_move_words (layout, start, -1); | |||
| 1257 | while (!attrs[start].is_word_end && start > 0) | |||
| 1258 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1259 | end = _ctk_pango_move_words (layout, end, 1); | |||
| 1260 | break; | |||
| 1261 | ||||
| 1262 | case ATK_TEXT_BOUNDARY_SENTENCE_START: | |||
| 1263 | if (!attrs[start].is_sentence_start) | |||
| 1264 | start = _ctk_pango_move_sentences (layout, start, -1); | |||
| 1265 | if (_ctk_pango_is_inside_sentence (layout, end)) | |||
| 1266 | end = _ctk_pango_move_sentences (layout, end, 1); | |||
| 1267 | while (!attrs[end].is_sentence_start && end < n_attrs - 1) | |||
| 1268 | end = _ctk_pango_move_chars (layout, end, 1); | |||
| 1269 | break; | |||
| 1270 | ||||
| 1271 | case ATK_TEXT_BOUNDARY_SENTENCE_END: | |||
| 1272 | if (_ctk_pango_is_inside_sentence (layout, start) && | |||
| 1273 | !attrs[start].is_sentence_start) | |||
| 1274 | start = _ctk_pango_move_sentences (layout, start, -1); | |||
| 1275 | while (!attrs[start].is_sentence_end && start > 0) | |||
| 1276 | start = _ctk_pango_move_chars (layout, start, -1); | |||
| 1277 | end = _ctk_pango_move_sentences (layout, end, 1); | |||
| 1278 | break; | |||
| 1279 | ||||
| 1280 | case ATK_TEXT_BOUNDARY_LINE_START: | |||
| 1281 | case ATK_TEXT_BOUNDARY_LINE_END: | |||
| 1282 | pango_layout_get_line_at (layout, boundary_type, offset, &start, &end); | |||
| 1283 | break; | |||
| 1284 | } | |||
| 1285 | ||||
| 1286 | *start_offset = start; | |||
| 1287 | *end_offset = end; | |||
| 1288 | ||||
| 1289 | g_assert (start <= end)do { if (start <= end) ; else g_assertion_message_expr ("Ctk" , "ctkpango.c", 1289, ((const char*) (__func__)), "start <= end" ); } while (0); | |||
| 1290 | ||||
| 1291 | return g_utf8_substring (text, start, end); | |||
| 1292 | } | |||
| 1293 | ||||
| 1294 | static gboolean | |||
| 1295 | attr_list_merge_filter (PangoAttribute *attribute, | |||
| 1296 | gpointer list) | |||
| 1297 | { | |||
| 1298 | pango_attr_list_change (list, pango_attribute_copy (attribute)); | |||
| 1299 | return FALSE(0); | |||
| 1300 | } | |||
| 1301 | ||||
| 1302 | /* | |||
| 1303 | * _ctk_pango_attr_list_merge: | |||
| 1304 | * @into: a #PangoAttrList where attributes are merged or %NULL | |||
| 1305 | * @from: a #PangoAttrList with the attributes to merge or %NULL | |||
| 1306 | * | |||
| 1307 | * Merges attributes from @from into @into. | |||
| 1308 | * | |||
| 1309 | * Returns: the merged list. | |||
| 1310 | */ | |||
| 1311 | PangoAttrList * | |||
| 1312 | _ctk_pango_attr_list_merge (PangoAttrList *into, | |||
| 1313 | PangoAttrList *from) | |||
| 1314 | { | |||
| 1315 | if (from) | |||
| 1316 | { | |||
| 1317 | if (into) | |||
| 1318 | pango_attr_list_filter (from, attr_list_merge_filter, into); | |||
| 1319 | else | |||
| 1320 | return pango_attr_list_ref (from); | |||
| 1321 | } | |||
| 1322 | ||||
| 1323 | return into; | |||
| 1324 | } | |||
| 1325 | ||||
| 1326 | PangoDirection | |||
| 1327 | _ctk_pango_unichar_direction (gunichar ch) | |||
| 1328 | { | |||
| 1329 | FriBidiCharType fribidi_ch_type; | |||
| 1330 | ||||
| 1331 | G_STATIC_ASSERT (sizeof (FriBidiChar) == sizeof (gunichar))_Static_assert (sizeof (FriBidiChar) == sizeof (gunichar), "Expression evaluates to false" ); | |||
| 1332 | ||||
| 1333 | fribidi_ch_type = fribidi_get_bidi_type (ch); | |||
| 1334 | ||||
| 1335 | if (!FRIBIDI_IS_STRONG (fribidi_ch_type)((fribidi_ch_type) & 0x00000010L)) | |||
| 1336 | return PANGO_DIRECTION_NEUTRAL; | |||
| 1337 | else if (FRIBIDI_IS_RTL (fribidi_ch_type)((fribidi_ch_type) & 0x00000001L)) | |||
| 1338 | return PANGO_DIRECTION_RTL; | |||
| 1339 | else | |||
| 1340 | return PANGO_DIRECTION_LTR; | |||
| 1341 | } | |||
| 1342 | ||||
| 1343 | PangoDirection | |||
| 1344 | _ctk_pango_find_base_dir (const gchar *text, | |||
| 1345 | gint length) | |||
| 1346 | { | |||
| 1347 | PangoDirection dir = PANGO_DIRECTION_NEUTRAL; | |||
| 1348 | const gchar *p; | |||
| 1349 | ||||
| 1350 | g_return_val_if_fail (text != NULL || length == 0, PANGO_DIRECTION_NEUTRAL)do { if ((text != ((void*)0) || length == 0)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL || length == 0" ); return (PANGO_DIRECTION_NEUTRAL); } } while (0); | |||
| 1351 | ||||
| 1352 | p = text; | |||
| 1353 | while ((length < 0 || p < text + length) && *p) | |||
| 1354 | { | |||
| 1355 | gunichar wc = g_utf8_get_char (p); | |||
| 1356 | ||||
| 1357 | dir = _ctk_pango_unichar_direction (wc); | |||
| 1358 | ||||
| 1359 | if (dir != PANGO_DIRECTION_NEUTRAL) | |||
| 1360 | break; | |||
| 1361 | ||||
| 1362 | p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]); | |||
| 1363 | } | |||
| 1364 | ||||
| 1365 | return dir; | |||
| 1366 | } | |||
| 1367 |