summaryrefslogtreecommitdiff
path: root/vcl/unx/gtk/a11y/atktext.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/gtk/a11y/atktext.cxx')
-rw-r--r--vcl/unx/gtk/a11y/atktext.cxx876
1 files changed, 876 insertions, 0 deletions
diff --git a/vcl/unx/gtk/a11y/atktext.cxx b/vcl/unx/gtk/a11y/atktext.cxx
new file mode 100644
index 000000000000..e6d3276891de
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktext.cxx
@@ -0,0 +1,876 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+#include "atktextattributes.hxx"
+#include <algorithm>
+
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/accessibility/TextSegment.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
+#include <com/sun/star/text/TextMarkupType.hpp>
+
+// #define ENABLE_TRACING
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static sal_Int16
+text_type_from_boundary(AtkTextBoundary boundary_type)
+{
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ return accessibility::AccessibleTextType::CHARACTER;
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ return accessibility::AccessibleTextType::WORD;
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ return accessibility::AccessibleTextType::SENTENCE;
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ return accessibility::AccessibleTextType::LINE;
+ default:
+ return -1;
+ }
+}
+
+/*****************************************************************************/
+
+static gchar *
+adjust_boundaries( accessibility::XAccessibleText* pText,
+ accessibility::TextSegment& rTextSegment,
+ AtkTextBoundary boundary_type,
+ gint * start_offset, gint * end_offset )
+{
+ accessibility::TextSegment aTextSegment;
+ rtl::OUString aString;
+ gint start = 0, end = 0;
+
+ if( rTextSegment.SegmentText.getLength() > 0 )
+ {
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ start = rTextSegment.SegmentStart;
+ end = rTextSegment.SegmentEnd;
+ aString = rTextSegment.SegmentText;
+ break;
+
+ // the OOo break iterator behaves as SENTENCE_START
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ start = rTextSegment.SegmentStart;
+ end = rTextSegment.SegmentEnd;
+
+ if( start > 0 )
+ --start;
+ if( end > 0 && end < pText->getCharacterCount() - 1 )
+ --end;
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ start = rTextSegment.SegmentStart;
+
+ // Determine the start index of the next segment
+ aTextSegment = pText->getTextBehindIndex(rTextSegment.SegmentEnd,
+ text_type_from_boundary(boundary_type));
+ if( aTextSegment.SegmentText.getLength() > 0 )
+ end = aTextSegment.SegmentStart;
+ else
+ end = pText->getCharacterCount();
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ end = rTextSegment.SegmentEnd;
+
+ // Determine the end index of the previous segment
+ aTextSegment = pText->getTextBeforeIndex(rTextSegment.SegmentStart,
+ text_type_from_boundary(boundary_type));
+ if( aTextSegment.SegmentText.getLength() > 0 )
+ start = aTextSegment.SegmentEnd;
+ else
+ start = 0;
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ default:
+ return NULL;
+ }
+ }
+
+ *start_offset = start;
+ *end_offset = end;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "adjust_boundaries( %d, %d, %d ) returns %d, %d\n",
+ rTextSegment.SegmentStart, rTextSegment.SegmentEnd, boundary_type,
+ start, end);
+#endif
+
+ return OUStringToGChar(aString);
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleText*
+ getText( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
+ pWrap->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
+ pWrap->mpText->acquire();
+ }
+
+ return pWrap->mpText;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTextMarkup*
+ getTextMarkup( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpTextMarkup && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextMarkup::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpTextMarkup = reinterpret_cast< accessibility::XAccessibleTextMarkup * > (any.pReserved);
+ if( pWrap->mpTextMarkup )
+ pWrap->mpTextMarkup->acquire();
+ }
+ }
+
+ return pWrap->mpTextMarkup;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTextAttributes*
+ getTextAttributes( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpTextAttributes && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextAttributes::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpTextAttributes = reinterpret_cast< accessibility::XAccessibleTextAttributes * > (any.pReserved);
+ pWrap->mpTextAttributes->acquire();
+ }
+ }
+
+ return pWrap->mpTextAttributes;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleMultiLineText*
+ getMultiLineText( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpMultiLineText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleMultiLineText::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpMultiLineText = reinterpret_cast< accessibility::XAccessibleMultiLineText * > (any.pReserved);
+ pWrap->mpMultiLineText->acquire();
+ }
+ }
+
+ return pWrap->mpMultiLineText;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gchar *
+text_wrapper_get_text (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ gchar * ret = NULL;
+
+ g_return_val_if_fail( (end_offset == -1) || (end_offset >= start_offset), NULL );
+
+ /* at-spi expects the delete event to be send before the deletion happened
+ * so we save the deleted string object in the UNO event notification and
+ * fool libatk-bridge.so here ..
+ */
+ void * pData = g_object_get_data( G_OBJECT(text), "ooo::text_changed::delete" );
+ if( pData != NULL )
+ {
+ accessibility::TextSegment * pTextSegment =
+ reinterpret_cast <accessibility::TextSegment *> (pData);
+
+ if( pTextSegment->SegmentStart == start_offset &&
+ pTextSegment->SegmentEnd == end_offset )
+ {
+ rtl::OString aUtf8 = rtl::OUStringToOString( pTextSegment->SegmentText, RTL_TEXTENCODING_UTF8 );
+ return g_strdup( aUtf8.getStr() );
+ }
+ }
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ rtl::OUString aText;
+ sal_Int32 n = pText->getCharacterCount();
+
+ if( -1 == end_offset )
+ aText = pText->getText();
+ else if( start_offset < n )
+ aText = pText->getTextRange(start_offset, end_offset);
+
+ ret = g_strdup( rtl::OUStringToOString(aText, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getText()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "text_wrapper_get_text( %d,%d ) returns %s\n", start_offset, end_offset, ret ? ret : "null" );
+#endif
+ return ret;
+}
+
+static gchar *
+text_wrapper_get_text_after_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ accessibility::TextSegment aTextSegment = pText->getTextBehindIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_text_after_offset()" );
+ }
+
+ return NULL;
+}
+
+static gchar *
+text_wrapper_get_text_at_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ /* If the user presses the 'End' key, the caret will be placed behind the last character,
+ * which is the same index as the first character of the next line. In atk the magic offset
+ * '-2' is used to cover this special case.
+ */
+ if (
+ -2 == offset &&
+ (ATK_TEXT_BOUNDARY_LINE_START == boundary_type ||
+ ATK_TEXT_BOUNDARY_LINE_END == boundary_type)
+ )
+ {
+ accessibility::XAccessibleMultiLineText* pMultiLineText = getMultiLineText( text );
+ if( pMultiLineText )
+ {
+ accessibility::TextSegment aTextSegment = pMultiLineText->getTextAtLineWithCaret();
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+
+ accessibility::TextSegment aTextSegment = pText->getTextAtIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_text_at_offset()" );
+ }
+
+ return NULL;
+}
+
+static gunichar
+text_wrapper_get_character_at_offset (AtkText *text,
+ gint offset)
+{
+ gint start, end;
+ gunichar uc = 0;
+
+ gchar * char_as_string =
+ text_wrapper_get_text_at_offset(text, offset, ATK_TEXT_BOUNDARY_CHAR,
+ &start, &end);
+ if( char_as_string )
+ {
+ uc = g_utf8_get_char( char_as_string );
+ g_free( char_as_string );
+ }
+
+ return uc;
+}
+
+static gchar *
+text_wrapper_get_text_before_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ accessibility::TextSegment aTextSegment = pText->getTextBeforeIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in text_before_offset()" );
+ }
+
+ return NULL;
+}
+
+static gint
+text_wrapper_get_caret_offset (AtkText *text)
+{
+ gint offset = -1;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ offset = pText->getCaretPosition();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCaretPosition()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_caret_offset(%p) returns %d\n", text, offset);
+#endif
+
+ return offset;
+}
+
+static gboolean
+text_wrapper_set_caret_offset (AtkText *text,
+ gint offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setCaretPosition( offset );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setCaretPosition()" );
+ }
+
+ return FALSE;
+}
+
+// --> OD 2010-03-04 #i92232#
+AtkAttributeSet*
+handle_text_markup_as_run_attribute( accessibility::XAccessibleTextMarkup* pTextMarkup,
+ const gint nTextMarkupType,
+ const gint offset,
+ AtkAttributeSet* pSet,
+ gint *start_offset,
+ gint *end_offset )
+{
+ const gint nTextMarkupCount( pTextMarkup->getTextMarkupCount( nTextMarkupType ) );
+ if ( nTextMarkupCount > 0 )
+ {
+ for ( gint nTextMarkupIndex = 0;
+ nTextMarkupIndex < nTextMarkupCount;
+ ++nTextMarkupIndex )
+ {
+ accessibility::TextSegment aTextSegment =
+ pTextMarkup->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
+ const gint nStartOffsetTextMarkup = aTextSegment.SegmentStart;
+ const gint nEndOffsetTextMarkup = aTextSegment.SegmentEnd;
+ if ( nStartOffsetTextMarkup <= offset )
+ {
+ if ( offset < nEndOffsetTextMarkup )
+ {
+ // text markup at <offset>
+ *start_offset = ::std::max( *start_offset,
+ nStartOffsetTextMarkup );
+ *end_offset = ::std::min( *end_offset,
+ nEndOffsetTextMarkup );
+ switch ( nTextMarkupType )
+ {
+ case com::sun::star::text::TextMarkupType::SPELLCHECK:
+ {
+ pSet = attribute_set_prepend_misspelled( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION:
+ {
+ pSet = attribute_set_prepend_tracked_change_insertion( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION:
+ {
+ pSet = attribute_set_prepend_tracked_change_deletion( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
+ {
+ pSet = attribute_set_prepend_tracked_change_formatchange( pSet );
+ }
+ break;
+ default:
+ {
+ OSL_ASSERT( false );
+ }
+ }
+ break; // no further iteration needed.
+ }
+ else
+ {
+ *start_offset = ::std::max( *start_offset,
+ nEndOffsetTextMarkup );
+ // continue iteration.
+ }
+ }
+ else
+ {
+ *end_offset = ::std::min( *end_offset,
+ nStartOffsetTextMarkup );
+ break; // no further iteration.
+ }
+ } // eof iteration over text markups
+ }
+
+ return pSet;
+}
+// <--
+
+static AtkAttributeSet *
+text_wrapper_get_run_attributes( AtkText *text,
+ gint offset,
+ gint *start_offset,
+ gint *end_offset)
+{
+ AtkAttributeSet *pSet = NULL;
+
+ try {
+ bool bOffsetsAreValid = false;
+
+ accessibility::XAccessibleText* pText = getText( text );
+ accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
+ if( pText && pTextAttributes )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList =
+ pTextAttributes->getRunAttributes( offset, uno::Sequence< rtl::OUString > () );
+
+ pSet = attribute_set_new_from_property_values( aAttributeList, true, text );
+ // --> OD 2009-06-22 #i100938#
+ // - always provide start_offset and end_offset
+// if( pSet )
+ // <--
+ {
+ accessibility::TextSegment aTextSegment =
+ pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+
+ *start_offset = aTextSegment.SegmentStart;
+ // --> OD 2009-06-22 #i100938#
+ // Do _not_ increment the end_offset provide by <accessibility::TextSegment> instance
+// *end_offset = aTextSegment.SegmentEnd + 1; // FIXME: TESTME
+ *end_offset = aTextSegment.SegmentEnd;
+ // <--
+ bOffsetsAreValid = true;
+ }
+ }
+
+ // Special handling for misspelled text
+ // --> OD 2010-03-01 #i92232#
+ // - add special handling for tracked changes and refactor the
+ // corresponding code for handling misspelled text.
+ accessibility::XAccessibleTextMarkup* pTextMarkup = getTextMarkup( text );
+ if( pTextMarkup )
+ {
+ // Get attribute run here if it hasn't been done before
+ if( !bOffsetsAreValid )
+ {
+ accessibility::TextSegment aAttributeTextSegment =
+ pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+ *start_offset = aAttributeTextSegment.SegmentStart;
+ *end_offset = aAttributeTextSegment.SegmentEnd;
+ }
+ // handle misspelled text
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::SPELLCHECK,
+ offset, pSet, start_offset, end_offset );
+ // handle tracked changes
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION,
+ offset, pSet, start_offset, end_offset );
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION,
+ offset, pSet, start_offset, end_offset );
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE,
+ offset, pSet, start_offset, end_offset );
+ }
+ // <--
+ }
+ catch(const uno::Exception& e){
+
+ g_warning( "Exception in get_run_attributes()" );
+
+ if( pSet )
+ {
+ atk_attribute_set_free( pSet );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+static AtkAttributeSet *
+text_wrapper_get_default_attributes( AtkText *text )
+{
+ AtkAttributeSet *pSet = NULL;
+
+ try {
+ accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
+ if( pTextAttributes )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList =
+ pTextAttributes->getDefaultAttributes( uno::Sequence< rtl::OUString > () );
+
+ pSet = attribute_set_new_from_property_values( aAttributeList, false, text );
+ }
+ }
+ catch(const uno::Exception& e) {
+
+ g_warning( "Exception in get_default_attributes()" );
+
+ if( pSet )
+ {
+ atk_attribute_set_free( pSet );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+static void
+text_wrapper_get_character_extents( AtkText *text,
+ gint offset,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coords )
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ *x = *y = *width = *height = 0;
+ awt::Rectangle aRect = pText->getCharacterBounds( offset );
+
+ gint origin_x = 0;
+ gint origin_y = 0;
+
+ if( coords == ATK_XY_SCREEN )
+ {
+ g_return_if_fail( ATK_IS_COMPONENT( text ) );
+ atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
+ }
+
+ *x = aRect.X + origin_x;
+ *y = aRect.Y + origin_y;
+ *width = aRect.Width;
+ *height = aRect.Height;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_character_extents(%d, %d) returns: %d,%d,%d,%d ",
+ offset, coords, *x, *y, *width, *height);
+#endif
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCharacterBounds" );
+ }
+}
+
+static gint
+text_wrapper_get_character_count (AtkText *text)
+{
+ gint rv = 0;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ rv = pText->getCharacterCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCharacterCount" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_character_count(%p) returns: %d\n", text, rv);
+#endif
+
+ return rv;
+}
+
+static gint
+text_wrapper_get_offset_at_point (AtkText *text,
+ gint x,
+ gint y,
+ AtkCoordType coords)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ gint origin_x = 0;
+ gint origin_y = 0;
+
+ if( coords == ATK_XY_SCREEN )
+ {
+ g_return_val_if_fail( ATK_IS_COMPONENT( text ), -1 );
+ atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
+ }
+
+ return pText->getIndexAtPoint( awt::Point(x - origin_x, y - origin_y) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getIndexAtPoint" );
+ }
+
+ return -1;
+}
+
+// FIXME: the whole series of selections API is problematic ...
+
+static gint
+text_wrapper_get_n_selections (AtkText *text)
+{
+ gint rv = 0;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ rv = ( pText->getSelectionEnd() > pText->getSelectionStart() ) ? 1 : 0;
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectionEnd() or getSelectionStart()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_n_selections(%p) returns %d\n", text, rv);
+#endif
+
+ return rv;
+}
+
+static gchar *
+text_wrapper_get_selection (AtkText *text,
+ gint selection_num,
+ gint *start_offset,
+ gint *end_offset)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ *start_offset = pText->getSelectionStart();
+ *end_offset = pText->getSelectionEnd();
+
+ return OUStringToGChar( pText->getSelectedText() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectionEnd(), getSelectionStart() or getSelectedText()" );
+ }
+
+ return NULL;
+}
+
+static gboolean
+text_wrapper_add_selection (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ // FIXME: can we try to be more compatible by expanding an
+ // existing adjacent selection ?
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( start_offset, end_offset ); // ?
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+text_wrapper_remove_selection (AtkText *text,
+ gint selection_num)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( 0, 0 ); // ?
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+text_wrapper_set_selection (AtkText *text,
+ gint selection_num,
+ gint start_offset,
+ gint end_offset)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( start_offset, end_offset );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+textIfaceInit (AtkTextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_text = text_wrapper_get_text;
+ iface->get_character_at_offset = text_wrapper_get_character_at_offset;
+ iface->get_text_before_offset = text_wrapper_get_text_before_offset;
+ iface->get_text_at_offset = text_wrapper_get_text_at_offset;
+ iface->get_text_after_offset = text_wrapper_get_text_after_offset;
+ iface->get_caret_offset = text_wrapper_get_caret_offset;
+ iface->set_caret_offset = text_wrapper_set_caret_offset;
+ iface->get_character_count = text_wrapper_get_character_count;
+ iface->get_n_selections = text_wrapper_get_n_selections;
+ iface->get_selection = text_wrapper_get_selection;
+ iface->add_selection = text_wrapper_add_selection;
+ iface->remove_selection = text_wrapper_remove_selection;
+ iface->set_selection = text_wrapper_set_selection;
+ iface->get_run_attributes = text_wrapper_get_run_attributes;
+ iface->get_default_attributes = text_wrapper_get_default_attributes;
+ iface->get_character_extents = text_wrapper_get_character_extents;
+ iface->get_offset_at_point = text_wrapper_get_offset_at_point;
+}