2008-01-14 Li Yuan <li.yuan@sun.com>
[platform/core/uifw/at-spi2-atk.git] / libspi / text.c
index bfe1ed4..103e719 100644 (file)
@@ -41,56 +41,6 @@ typedef struct {
   gint h;
 } SpiTextRect;
 
-static SpiTextRect *
-_spi_text_rect_union (SpiTextRect *aggregate, SpiTextRect *subrect)
-{
-  if (subrect != NULL)
-    {
-      /* 'normalize' subrect */
-      if (subrect->w < 0)
-       {
-         subrect->x += subrect->w;
-         subrect->w *= -1;
-       }
-      if (subrect->h < 0)
-       {
-         subrect->y += subrect->h;
-         subrect->h *= -1;
-       }
-      if (aggregate == NULL)
-       {
-         aggregate = g_new (SpiTextRect, 1);
-         memcpy (aggregate, subrect, sizeof (SpiTextRect));
-       }
-      else
-       {
-         gint ax2 = aggregate->x + aggregate->w;
-         gint ay2 = aggregate->y + aggregate->h; 
-         gint sx2 = subrect->x + subrect->w; 
-         gint sy2 = subrect->y + subrect->h;
-         if (subrect->x < aggregate->x)
-           {
-             aggregate->w += (aggregate->x - subrect->x);
-             aggregate->x = subrect->x;
-           }
-         if (sx2 > ax2)
-           {
-             aggregate->w += (sx2 - ax2);
-           }
-         if (subrect->y < aggregate->y)
-           {
-             aggregate->h += (aggregate->y - subrect->y);
-             aggregate->y = subrect->y;
-           }
-         if (sy2 > ay2)
-           {
-             aggregate->h += (sy2 - ay2);
-           }
-       }
-    }
-  return aggregate;
-}
-
 static AtkText *
 get_text_from_servant (PortableServer_Servant servant)
 {
@@ -126,7 +76,7 @@ impl_getText (PortableServer_Servant servant,
 }
 
 
-CORBA_string
+static CORBA_string
 impl_getTextAfterOffset (PortableServer_Servant servant,
                         const CORBA_long offset,
                         const
@@ -309,11 +259,49 @@ impl_getAttributes (PortableServer_Servant servant,
 }
 
 static CORBA_string
+impl_getAttributeValue (PortableServer_Servant servant,
+                       const CORBA_long offset,
+                       const CORBA_char *attributename,
+                       CORBA_long * startOffset,
+                       CORBA_long * endOffset,
+                       CORBA_boolean * defined,
+                       CORBA_Environment *ev)
+{
+  AtkAttributeSet *set;
+  gint intstart_offset, intend_offset;
+  GSList *cur_attr;
+  CORBA_string rv = NULL;
+  AtkText *text = get_text_from_servant (servant);
+  AtkAttribute *at;
+
+  g_return_val_if_fail (text != NULL, CORBA_string_dup (""));
+
+  set = atk_text_get_run_attributes (text, offset,
+                                    &intstart_offset, &intend_offset);
+  *startOffset = intstart_offset;
+  *endOffset = intend_offset;
+  *defined = FALSE;
+  cur_attr = (GSList *) set;
+  while (cur_attr)
+    {
+      at = (AtkAttribute *) cur_attr->data;
+      if (!strcmp (at->name, attributename))
+      {
+         rv = CORBA_string_dup (at->value);
+         *defined = TRUE;
+         break;
+      }
+      cur_attr = cur_attr->next;
+    }
+  atk_attribute_set_free (set);
+  return (rv ? rv : CORBA_string_dup (""));  
+}
+
+static CORBA_string
 impl_getDefaultAttributes (PortableServer_Servant servant,
                           CORBA_Environment *ev)
 {
   AtkAttributeSet *set;
-  gint intstart_offset, intend_offset;
   CORBA_char *rv;
   AtkText *text = get_text_from_servant (servant);
 
@@ -466,8 +454,6 @@ impl_setCaretOffset (PortableServer_Servant servant,
   return atk_text_set_caret_offset (text, value);
 }
 
-#define SPI_TEXT_MIN_RANGE_FOR_LINE_CHECK 6
-
 static void
 impl_getRangeExtents(PortableServer_Servant servant,
                     const CORBA_long startOffset,
@@ -479,86 +465,42 @@ impl_getRangeExtents(PortableServer_Servant servant,
                     CORBA_Environment * ev)
 {
   AtkText *text = get_text_from_servant (servant);
-  SpiTextRect cbounds, bounds;
-  int i;
+  AtkTextRectangle rect;
 
   g_return_if_fail (text != NULL);
   
-  atk_text_get_character_extents (text, startOffset,
-                                 &bounds.x, &bounds.y, &bounds.w, &bounds.h,
-                                 (AtkCoordType) coordType);
-  /* no equivalent ATK API yet, must do the hard way. :-( */
-  for (i = startOffset + 1; i < endOffset; i++) 
-    {
-      atk_text_get_character_extents (text, i,
-                                     &cbounds.x, &cbounds.y, &cbounds.w, &cbounds.h,
-                                     (AtkCoordType) coordType);
-      _spi_text_rect_union (&bounds, &cbounds);
-    }
-
-  *x = bounds.x;
-  *y = bounds.y;
-  *width = bounds.w;
-  *height = bounds.h;
+  atk_text_get_range_extents (text, (gint) startOffset, (gint) endOffset, 
+                             (AtkCoordType) coordType, &rect);
+  *x = rect.x;
+  *y = rect.y;
+  *width = rect.width;
+  *height = rect.height;
 }
 
+#define MAXRANGELEN 512
+
 static Accessibility_Text_RangeList *
-_spi_text_range_seq_from_gslist (GSList *range_list) 
+_spi_text_range_seq_from_atkrangelist (AtkTextRange **range_list) 
 { 
   Accessibility_Text_RangeList *rangeList = 
     Accessibility_Text_RangeList__alloc ();
-  int i, len = g_slist_length (range_list);
-  GSList *list = range_list;
+  int i, len;
+
+  for (len = 0; len < MAXRANGELEN && range_list[len]; ++len);
 
   rangeList->_length = len;
   rangeList->_buffer = Accessibility_Text_RangeList_allocbuf (len);
   for (i = 0; i < len; ++i) 
     {
-      memcpy (&rangeList->_buffer[i], list->data, sizeof (Accessibility_Text_Range));
-      spi_init_any_nil (&rangeList->_buffer[i].data);
-      g_free (list->data);
-      list = g_slist_next (range_list);
+      rangeList->_buffer[i].startOffset = range_list[i]->start_offset; 
+      rangeList->_buffer[i].endOffset = range_list[i]->end_offset;
+      rangeList->_buffer[i].content = CORBA_string_dup (range_list[i]->content);
     }
-  g_slist_free (range_list);
 
   return rangeList;
 }
 
-static gboolean
-_spi_bounds_contain (SpiTextRect *clip, SpiTextRect *cbounds, 
-                    Accessibility_TEXT_CLIP_TYPE xClipType, 
-                    Accessibility_TEXT_CLIP_TYPE yClipType)
-{
-  gint clipx2 = clip->x + clip->w;
-  gint clipy2 = clip->y + clip->h;
-  gint charx2 = cbounds->x + cbounds->w;
-  gint chary2 = cbounds->y + cbounds->h;
-  gboolean x_min_ok, y_min_ok, x_max_ok, y_max_ok;
-
-  x_min_ok = (cbounds->x >= clip->x) || 
-    ((charx2 >= clip->x) && 
-     ((xClipType == Accessibility_TEXT_CLIP_NONE) || 
-      (xClipType == Accessibility_TEXT_CLIP_MAX)));
-  x_max_ok = (charx2 <= clipx2) || 
-    ((cbounds->x <= clipx2) && 
-     ((xClipType == Accessibility_TEXT_CLIP_NONE) || 
-      (xClipType == Accessibility_TEXT_CLIP_MIN)));
-  y_min_ok = (cbounds->y >= clip->y) || 
-    ((chary2 >= clip->y) && 
-     ((yClipType == Accessibility_TEXT_CLIP_NONE) || 
-      (yClipType == Accessibility_TEXT_CLIP_MAX)));
-  y_max_ok = (chary2 <= clipy2) || 
-    ((cbounds->y <= clipy2) && 
-     ((yClipType == Accessibility_TEXT_CLIP_NONE) || 
-      (yClipType == Accessibility_TEXT_CLIP_MIN)));
-  
-  if (x_min_ok && y_min_ok && x_max_ok && y_max_ok)
-    return TRUE;
-  else 
-    return FALSE;
-}
-
-Accessibility_Text_RangeList *
+static Accessibility_Text_RangeList *
 impl_getBoundedRanges(PortableServer_Servant servant,
                      const CORBA_long x,
                      const CORBA_long y,
@@ -570,64 +512,114 @@ impl_getBoundedRanges(PortableServer_Servant servant,
                      CORBA_Environment * ev)
 {
   AtkText *text = get_text_from_servant (servant);
-  GSList *range_list = NULL;
-  SpiTextRect clip;
-  int startOffset = 0, endOffset = atk_text_get_character_count (text);
-  int curr_offset;
-  gint minLineStart, minLineEnd, maxLineStart, maxLineEnd;
-  long bounds_min_offset;
-  long bounds_max_offset;
-
-  clip.x = x;
-  clip.y = y;
-  clip.w = width;
-  clip.h = height;
-
-  /* for horizontal text layouts, at least, the following check helps. */
-  bounds_min_offset =  atk_text_get_offset_at_point (text, x, y, 
-                                                    (AtkCoordType) coordType);
-  bounds_max_offset =  atk_text_get_offset_at_point (text, x + width, y + height, 
-                                                    (AtkCoordType) coordType);
-  atk_text_get_text_at_offset (text, bounds_min_offset, 
-                              ATK_TEXT_BOUNDARY_LINE_START,
-                              &minLineStart, &minLineEnd);
-  atk_text_get_text_at_offset (text, bounds_max_offset, 
-                              ATK_TEXT_BOUNDARY_LINE_START,
-                              &maxLineStart, &maxLineEnd);
-  startOffset = MIN (minLineStart, maxLineStart);
-  endOffset  = MAX (minLineEnd, maxLineEnd);
-
-  curr_offset = startOffset;
-
-  while (curr_offset < endOffset) 
-    {
-      int offset = startOffset;
-      SpiTextRect cbounds;
-      while (curr_offset < endOffset) 
-       {
-         atk_text_get_character_extents (text, curr_offset, 
-                                         &cbounds.x, &cbounds.y, 
-                                         &cbounds.w, &cbounds.h, 
-                                         (AtkCoordType) coordType);
-         if (!_spi_bounds_contain (&clip, &cbounds, xClipType, yClipType))
-           break;
-         curr_offset++;
-       }
-      /* add the range to our list */
-      if (curr_offset > offset) 
-       {
-         Accessibility_Text_Range *range = g_malloc (sizeof (Accessibility_Text_Range));
-         char *s;
-         range->startOffset = offset;
-         range->endOffset = curr_offset;
-         s = atk_text_get_text (text, offset, curr_offset);
-         range->content = CORBA_string_dup (s ? s : "");
-         range_list = g_slist_append (range_list, range);
-         offset = curr_offset;
-       }
-      offset++;
-    }  
-  return _spi_text_range_seq_from_gslist (range_list); /* frees the GSList too */
+  AtkTextRange **range_list = NULL;
+  AtkTextRectangle rect;
+
+  rect.x = x;
+  rect.y = y;
+  rect.width = width;
+  rect.height = height;
+
+  range_list = atk_text_get_bounded_ranges (text, &rect, 
+                                           (AtkCoordType) coordType,
+                                           (AtkTextClipType) xClipType,
+                                           (AtkTextClipType) yClipType);
+
+  return _spi_text_range_seq_from_atkrangelist (range_list); 
+}
+
+
+
+static Accessibility_AttributeSet *    
+impl_getAttributeRun (PortableServer_Servant servant,             
+                     const CORBA_long offset, 
+                     CORBA_long *startOffset, CORBA_long *endOffset, 
+                     const CORBA_boolean includeDefaults, 
+                     CORBA_Environment *ev){
+                     
+     AtkAttributeSet *attributes, *default_attributes = NULL;
+     AtkAttribute *attr = NULL;
+     gint intstart_offset, intend_offset;
+     Accessibility_AttributeSet *retval = NULL;
+     AtkText *text = get_text_from_servant (servant);
+     gint n_attributes = 0, total_attributes = 0, n_default_attributes = 0;
+     gint i, j;
+     
+     g_return_val_if_fail (text != NULL, NULL);
+
+     attributes = atk_text_get_run_attributes (text, offset,
+                                              &intstart_offset, &intend_offset);
+
+     if (attributes) total_attributes = n_attributes = g_slist_length (attributes);
+
+     if (includeDefaults)
+     {
+        default_attributes = atk_text_get_default_attributes (text);
+        if (default_attributes)
+            n_default_attributes = g_slist_length (default_attributes);
+        total_attributes += n_default_attributes;
+     }
+
+     *startOffset = intstart_offset;
+     *endOffset = intend_offset; 
+
+     retval = CORBA_sequence_CORBA_string__alloc ();
+     retval->_length = retval->_maximum = total_attributes;
+     retval->_buffer = CORBA_sequence_CORBA_string_allocbuf (total_attributes);
+     CORBA_sequence_set_release (retval, CORBA_TRUE);
+
+     if (total_attributes)
+     {  
+        for (i = 0; i < n_attributes; ++i)
+        {
+            attr = g_slist_nth_data (attributes, i);
+            retval->_buffer[i] = CORBA_string_dup (g_strconcat (attr->name, ":", attr->value, NULL));
+        }
+        
+        for (j = 0; j < n_default_attributes; ++i, ++j)
+        {
+            attr = g_slist_nth_data (default_attributes, j);
+            retval->_buffer[i] = CORBA_string_dup (g_strconcat (attr->name, ":", attr->value, NULL));
+        }
+        
+        atk_attribute_set_free (attributes);
+        if (default_attributes)
+            atk_attribute_set_free (default_attributes);
+     }
+     return retval;
+}
+
+static Accessibility_AttributeSet *
+impl_getDefaultAttributeSet (PortableServer_Servant servant,
+                            CORBA_Environment *ev){
+     AtkAttributeSet *attributes;
+     AtkAttribute *attr = NULL;
+     Accessibility_AttributeSet *retval = NULL;
+     AtkText *text = get_text_from_servant (servant);
+     gint n_attributes = 0;
+     gint i;
+     
+     g_return_val_if_fail (text != NULL, NULL);
+     
+     attributes = atk_text_get_default_attributes (text);
+     
+     if (attributes) 
+     {
+        n_attributes = g_slist_length (attributes);
+
+        retval = CORBA_sequence_CORBA_string__alloc ();
+        retval->_length = retval->_maximum = n_attributes;
+        retval->_buffer = CORBA_sequence_CORBA_string_allocbuf (n_attributes);
+        CORBA_sequence_set_release (retval, CORBA_TRUE);
+        
+        for (i = 0; i < n_attributes; ++i)
+        {
+            attr = g_slist_nth_data (attributes, i);
+            retval->_buffer [i] = CORBA_string_dup (g_strconcat (attr->name, ":", attr->value, NULL));
+        }
+        atk_attribute_set_free (attributes);
+     }     
+     return retval;       
 }
 
 
@@ -657,6 +649,9 @@ spi_text_class_init (SpiTextClass *klass)
   epv->setCaretOffset = impl_setCaretOffset;
   epv->getRangeExtents = impl_getRangeExtents;
   epv->getBoundedRanges = impl_getBoundedRanges;
+  epv->getAttributeValue = impl_getAttributeValue;
+  epv->getAttributeRun = impl_getAttributeRun;
+  epv->getDefaultAttributeSet = impl_getDefaultAttributeSet;
 }
 
 static void