25 #include <glib/gi18n-lib.h>
61 return page_accessible->priv->page;
81 return ATK_OBJECT (self->priv->view_accessible);
94 return ABS (dy) > 10 ? dy : dx;
104 GList *children = NULL;
107 if (self->priv->children_initialized)
114 self->priv->children_initialized =
TRUE;
119 if (!links && !images && !fields)
127 self->priv->children = g_ptr_array_new_full (g_list_length (children), (GDestroyNotify) g_object_unref);
129 for (list = children; list && list->data; list = list->next) {
131 AtkObject *child = NULL;
135 AtkHyperlink *atk_link = atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (link));
137 child = atk_hyperlink_get_object (atk_link, 0);
144 g_ptr_array_add (self->priv->children, child);
147 g_list_free (children);
156 if (!self->priv->children)
159 for (i = 0; i <
self->priv->children->len; i++) {
160 child = g_ptr_array_index (self->priv->children, i);
161 atk_object_notify_state_change (child, ATK_STATE_DEFUNCT,
TRUE);
164 g_clear_pointer (&self->priv->children, g_ptr_array_unref);
172 g_clear_pointer (&priv->
links, (GDestroyNotify)g_hash_table_destroy);
175 G_OBJECT_CLASS (ev_page_accessible_parent_class)->finalize (
object);
191 accessible->
priv->
page = g_value_get_int (value);
194 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
224 static AtkRelationSet *
229 AtkRelationSet *relation_set;
230 AtkObject *accessible_array[1];
231 AtkRelation *relation;
236 relation_set = ATK_OBJECT_CLASS (ev_page_accessible_parent_class)->ref_relation_set (accessible);
237 if (relation_set == NULL)
244 if ((self->priv->page + 1) < n_pages && !atk_relation_set_contains (relation_set, ATK_RELATION_FLOWS_TO)) {
245 AtkObject *next_page;
247 next_page = atk_object_ref_accessible_child (ATK_OBJECT (self->priv->view_accessible),
248 self->priv->page + 1);
249 accessible_array [0] = next_page;
250 relation = atk_relation_new (accessible_array, 1, ATK_RELATION_FLOWS_TO);
251 atk_relation_set_add (relation_set, relation);
253 g_object_unref (relation);
254 g_object_unref (next_page);
257 if (self->priv->page > 0 && !atk_relation_set_contains (relation_set, ATK_RELATION_FLOWS_FROM)) {
258 AtkObject *prev_page;
260 prev_page = atk_object_ref_accessible_child (ATK_OBJECT (self->priv->view_accessible),
261 self->priv->page - 1);
262 accessible_array [0] = prev_page;
263 relation = atk_relation_new (accessible_array, 1, ATK_RELATION_FLOWS_FROM);
264 atk_relation_set_add (relation_set, relation);
266 g_object_unref (relation);
267 g_object_unref (prev_page);
279 AtkStateSet *state_set;
280 AtkStateSet *copy_set;
281 AtkStateSet *view_accessible_state_set;
290 state_set = ATK_OBJECT_CLASS (ev_page_accessible_parent_class)->ref_state_set (accessible);
291 atk_state_set_clear_states (state_set);
293 view_accessible_state_set = atk_object_ref_state_set (ATK_OBJECT (self->priv->view_accessible));
294 copy_set = atk_state_set_or_sets (state_set, view_accessible_state_set);
297 atk_state_set_add_state (copy_set, ATK_STATE_SHOWING);
299 atk_state_set_remove_state (copy_set, ATK_STATE_SHOWING);
302 if (atk_state_set_contains_state (view_accessible_state_set, ATK_STATE_FOCUSED) &&
303 self->priv->page == relevant_page)
304 atk_state_set_add_state (copy_set, ATK_STATE_FOCUSED);
306 atk_state_set_remove_state (copy_set, ATK_STATE_FOCUSED);
309 if (atk_state_set_contains_state (view_accessible_state_set, ATK_STATE_FOCUSED) &&
310 self->priv->page == relevant_page)
311 atk_state_set_add_state (copy_set, ATK_STATE_FOCUSED);
313 atk_state_set_remove_state (copy_set, ATK_STATE_FOCUSED);
315 g_object_unref (state_set);
316 g_object_unref (view_accessible_state_set);
328 return self->priv->children == NULL ? 0 :
self->priv->children->len;
339 g_return_val_if_fail (i >= 0 || i < self->priv->children->len, NULL);
341 return g_object_ref (g_ptr_array_index (self->priv->children, i));
347 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
348 AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
362 g_object_class_install_property (g_object_class,
364 g_param_spec_object (
"view-accessible",
366 "The view accessible associated to this page",
369 G_PARAM_CONSTRUCT_ONLY |
370 G_PARAM_STATIC_STRINGS));
371 g_object_class_install_property (g_object_class,
373 g_param_spec_int (
"page",
375 "Page index this page represents",
378 G_PARAM_CONSTRUCT_ONLY |
379 G_PARAM_STATIC_STRINGS));
401 PangoLogAttr *log_attrs,
406 gdouble line_spacing, this_line_height, next_word_width;
412 gint prev_offset, next_offset;
415 if (!log_attrs[offset].is_white)
419 if (n_areas <= offset + 1)
422 prev_offset = offset - 1;
423 next_offset = offset + 1;
429 if (!log_attrs[next_offset].is_word_start &&
430 (next_offset + 1 >= n_areas || !log_attrs[next_offset + 1].is_word_start))
437 this_line_end = areas + prev_offset;
438 next_line_start = areas + next_offset;;
440 this_line_height = this_line_end->
y2 - this_line_end->
y1;
441 if (ABS (this_line_height - (next_line_start->
y2 - next_line_start->
y1)) > 0.25)
448 line_spacing = next_line_start->
y1 - this_line_end->
y2;
449 if (line_spacing - this_line_height > 1)
458 for ( ; prev_offset > 0 && !log_attrs[prev_offset].is_mandatory_break; prev_offset--);
459 this_line_start = areas + prev_offset;
460 if (ABS (this_line_start->
x1 - next_line_start->
x1) > 20)
464 for ( ; next_offset < n_areas && !log_attrs[next_offset].is_word_end; next_offset++);
465 next_word_end = areas + next_offset;
466 next_word_width = next_word_end->
x2 - next_line_start->
x1;
468 for ( ; next_offset < n_areas && !log_attrs[next_offset + 1].is_mandatory_break; next_offset++);
469 next_line_end = areas + next_offset;
470 if (next_line_end->
x2 - (this_line_end->
x2 + next_word_width) > 20)
483 gchar *substring, *normalized;
484 const gchar* page_text;
490 if (end_offset < 0 || end_offset > g_utf8_strlen (page_text, -1))
491 end_offset = strlen (page_text);
492 start_offset = CLAMP (start_offset, 0, end_offset);
494 substring = g_utf8_substring (page_text, start_offset, end_offset);
495 normalized = g_utf8_normalize (substring, -1, G_NORMALIZE_NFKC);
517 unichar = g_utf8_get_char (
string);
525 AtkTextBoundary boundary_type,
534 PangoLogAttr *log_attrs = NULL;
544 if (offset < 0 || offset >= n_attrs)
547 switch (boundary_type) {
548 case ATK_TEXT_BOUNDARY_CHAR:
552 case ATK_TEXT_BOUNDARY_WORD_START:
553 for (start = offset; start > 0 && !log_attrs[start].is_word_start; start--);
554 for (end = offset + 1; end < n_attrs && !log_attrs[end].is_word_start; end++);
556 case ATK_TEXT_BOUNDARY_SENTENCE_START:
557 for (start = offset; start > 0; start--) {
558 if (log_attrs[start].is_mandatory_break &&
treat_as_soft_return (view, self->priv->page, log_attrs, start - 1))
560 if (log_attrs[start].is_sentence_start)
563 for (end = offset + 1; end < n_attrs; end++) {
564 if (log_attrs[end].is_mandatory_break &&
treat_as_soft_return (view, self->priv->page, log_attrs, end - 1))
566 if (log_attrs[end].is_sentence_start)
570 case ATK_TEXT_BOUNDARY_LINE_START:
571 for (start = offset; start > 0 && !log_attrs[start].is_mandatory_break; start--);
572 for (end = offset + 1; end < n_attrs && !log_attrs[end].is_mandatory_break; end++);
579 *start_offset = start;
586 AtkTextBoundary boundary_type,
601 if (boundary_type == ATK_TEXT_BOUNDARY_SENTENCE_START)
602 g_strdelimit (retval,
"\n",
' ');
650 cairo_rectangle_int_t rect;
659 rect.x / view->
scale,
660 (rect.y + (rect.height / 2)) / view->
scale);
669 (rect.x + rect.width) / view->
scale,
670 (rect.y + (rect.height / 2)) / view->
scale);
674 *start_offset = start;
685 gint n_selections = 0;
694 if (selection->
page != self->priv->page)
712 gchar *selected_text = NULL;
713 gchar *normalized_text = NULL;
719 if (selection_num != 0)
729 if (selection->
page != self->priv->page)
745 g_object_unref (page);
755 normalized_text = g_utf8_normalize (selected_text, -1, G_NORMALIZE_NFKC);
756 g_free (selected_text);
759 return normalized_text;
762 static AtkAttributeSet *
764 AtkTextAttribute attr_type,
767 AtkAttribute *attr = g_new (AtkAttribute, 1);
769 attr->name = g_strdup (atk_text_attribute_get_name (attr_type));
770 attr->value = attr_value;
772 return g_slist_prepend (attr_set, attr);
775 static AtkAttributeSet *
782 AtkAttributeSet *atk_attr_set = NULL;
783 PangoAttrString *pango_string;
784 PangoAttrInt *pango_int;
785 PangoAttrColor *pango_color;
786 PangoAttrIterator *iter;
788 gboolean has_attrs =
FALSE;
792 text_length = g_utf8_strlen (text, -1);
793 if (offset < 0 || offset >= text_length)
798 iter = pango_attr_list_get_iterator (attrs);
799 i = g_utf8_offset_to_pointer (text, offset) - text;
802 pango_attr_iterator_range (iter, &start, &end);
803 if (i >= start && i < end) {
804 *start_offset = g_utf8_pointer_to_offset (text, text + start);
807 *end_offset = g_utf8_pointer_to_offset (text, text + end);
810 }
while (!has_attrs && pango_attr_iterator_next (iter));
813 pango_attr_iterator_destroy (iter);
818 pango_string = (PangoAttrString *) pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY);
820 attr_value = g_strdup (pango_string->value);
821 atk_attr_set =
add_attribute (atk_attr_set, ATK_TEXT_ATTR_FAMILY_NAME, attr_value);
824 pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_SIZE);
826 attr_value = g_strdup_printf (
"%i", pango_int->value / PANGO_SCALE);
827 atk_attr_set =
add_attribute (atk_attr_set, ATK_TEXT_ATTR_SIZE, attr_value);
830 pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
833 ATK_TEXT_ATTR_UNDERLINE,
834 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE,
838 pango_color = (PangoAttrColor *) pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
840 attr_value = g_strdup_printf (
"%u,%u,%u",
841 pango_color->color.red,
842 pango_color->color.green,
843 pango_color->color.blue);
844 atk_attr_set =
add_attribute (atk_attr_set, ATK_TEXT_ATTR_FG_COLOR, attr_value);
847 pango_attr_iterator_destroy (iter);
852 static AtkAttributeSet*
860 PangoAttrList *attrs;
861 const gchar *page_text;
880 static AtkAttributeSet*
902 gint x_widget, y_widget;
903 GdkRectangle view_rect;
909 if (!areas || offset >= n_areas)
912 doc_rect = areas + offset;
917 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
918 gtk_widget_translate_coordinates (GTK_WIDGET (view), toplevel, 0, 0, &x_widget, &y_widget);
919 view_rect.x += x_widget;
920 view_rect.y += y_widget;
922 if (coords == ATK_XY_SCREEN) {
923 gint x_window, y_window;
925 gdk_window_get_origin (gtk_widget_get_window (toplevel), &x_window, &y_window);
926 view_rect.x += x_window;
927 view_rect.y += y_window;
932 *width = view_rect.width;
933 *height = view_rect.height;
949 gint x_widget, y_widget;
952 gdouble doc_x, doc_y;
954 GdkRectangle page_area;
965 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (
self));
966 gtk_widget_translate_coordinates (GTK_WIDGET (
self), toplevel, 0, 0, &x_widget, &y_widget);
967 view_point.x -= x_widget;
968 view_point.y -= y_widget;
970 if (coords == ATK_XY_SCREEN) {
971 gint x_window, y_window;
973 gdk_window_get_origin (gtk_widget_get_window (toplevel), &x_window, &y_window);
974 view_point.x -= x_window;
975 view_point.y -= y_window;
981 for (i = 0; i < n_areas; i++) {
983 if (doc_x >= rect->
x1 && doc_x <= rect->x2 &&
984 doc_y >= rect->
y1 && doc_y <= rect->y2)
1019 GdkRectangle start_rect, end_rect;
1020 GdkPoint start_point, end_point;
1023 if (start_pos < 0 || end_pos >= n_areas)
1028 start_point.x = start_rect.x;
1029 start_point.y = start_rect.y;
1030 end_point.x = end_rect.x + end_rect.width;
1031 end_point.y = end_rect.y + end_rect.height;
1049 atk_object_set_role (ATK_OBJECT (page), ATK_ROLE_PAGE);
1081 priv->
links = g_hash_table_new_full (g_direct_hash,
1084 (GDestroyNotify)g_object_unref);
1088 static AtkHyperlink *
1108 atk_link = g_hash_table_lookup (links, GINT_TO_POINTER (link_index));
1110 return atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (atk_link));
1117 if (link_index > n_links - 1)
1124 g_hash_table_insert (links, GINT_TO_POINTER (link_index), atk_link);
1126 return atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (atk_link));
1152 for (i = 0; i < n_links; i++) {
1153 AtkHyperlink *hyperlink;
1154 gint start_index, end_index;
1157 start_index = atk_hyperlink_get_start_index (hyperlink);
1158 end_index = atk_hyperlink_get_end_index (hyperlink);
1160 if (start_index <= offset && end_index >= offset)
1181 AtkCoordType coord_type)
1185 GdkRectangle page_area;
1193 doc_rect.
x1 = page_area.x;
1194 doc_rect.
y1 = page_area.y;
1195 doc_rect.
x2 = page_area.x + page_area.width;
1196 doc_rect.
y2 = page_area.y + page_area.height;
1201 *width = atk_rect.
x2 - atk_rect.
x1;
1202 *height = atk_rect.
y2 - atk_rect.
y1;
1216 if (page == self->priv->page)
1228 g_return_val_if_fail (page >= 0, NULL);
1231 "view-accessible", view_accessible,
1239 g_signal_connect (view->
page_cache,
"page-cached",
1256 for (i = 0; i < page_accessible->
priv->
children->len; i++) {
1259 child = g_ptr_array_index (page_accessible->
priv->
children, i);