2010-08-02 Mario Sanchez Prada <msanchez@igalia.com>

        Reviewed by Chris Fleizach.

        [GTK] Implement support for get_character_extents and get_range_extents
        https://bugs.webkit.org/show_bug.cgi?id=25677

        Implement get_range_extents() and modify get_character_extents()
        to properly work after "The Great Flattening" occurred in the ATK
        objects hierarchy, some months ago.

        In the case of the GTK port, not just the text controls should be
        considered when it comes to these functions but also those
        composite objects that would also allow to work with text ranges,
        such as headings and links. To take care of this, a new function
        AccessibilityObject::allowsTextRanges() was defined with a default
        implementation in the header file and an specific one for GTK in
        AccessibilityObjectAtk.cpp.

        Based on a previous patch by Joanmarie Diggs.

        * accessibility/AccessibilityObject.cpp:
        (WebCore::AccessibilityObject::visiblePositionRangeForRange):
        * accessibility/AccessibilityObject.h:
        (WebCore::AccessibilityObject::allowsTextRanges): New
        * accessibility/AccessibilityRenderObject.cpp:
        (WebCore::AccessibilityRenderObject::visiblePositionForIndex):
        (WebCore::AccessibilityRenderObject::doAXBoundsForRange):
        * accessibility/gtk/AccessibilityObjectAtk.cpp:
        (WebCore::AccessibilityObject::allowsTextRanges): New
        * accessibility/gtk/AccessibilityObjectWrapperAtk.cpp:
        (textExtents):
        (webkit_accessible_text_get_character_extents):
        (webkit_accessible_text_get_range_extents):
        (atk_text_interface_init):
2010-08-02  Mario Sanchez Prada  <msanchez@igalia.com>

        Reviewed by Chris Fleizach.

        [GTK] Implement support for get_character_extents and get_range_extents
        https://bugs.webkit.org/show_bug.cgi?id=25677

        Added new unit tests to check get_character_extents and
        get_range_extents functions for the ATK_TEXT interface

        Based on a previous patch by Joanmarie Diggs.

        * tests/testatk.c:
        (test_webkit_atk_get_extents):
        (main):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64475 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a4d02bd1
2010-08-02 Mario Sanchez Prada <msanchez@igalia.com>
Reviewed by Chris Fleizach.
[GTK] Implement support for get_character_extents and get_range_extents
https://bugs.webkit.org/show_bug.cgi?id=25677
Implement get_range_extents() and modify get_character_extents()
to properly work after "The Great Flattening" occurred in the ATK
objects hierarchy, some months ago.
In the case of the GTK port, not just the text controls should be
considered when it comes to these functions but also those
composite objects that would also allow to work with text ranges,
such as headings and links. To take care of this, a new function
AccessibilityObject::allowsTextRanges() was defined with a default
implementation in the header file and an specific one for GTK in
AccessibilityObjectAtk.cpp.
Based on a previous patch by Joanmarie Diggs.
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::visiblePositionRangeForRange):
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::allowsTextRanges): New
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::visiblePositionForIndex):
(WebCore::AccessibilityRenderObject::doAXBoundsForRange):
* accessibility/gtk/AccessibilityObjectAtk.cpp:
(WebCore::AccessibilityObject::allowsTextRanges): New
* accessibility/gtk/AccessibilityObjectWrapperAtk.cpp:
(textExtents):
(webkit_accessible_text_get_character_extents):
(webkit_accessible_text_get_range_extents):
(atk_text_interface_init):
2010-08-02 Chris Fleizach <cfleizach@apple.com>
AX: Support methods for web apps to interact with the native accessibility APIs
......@@ -373,7 +373,24 @@ VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePos
// NOTE: Consider providing this utility method as AX API
VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
{
if (range.start + range.length > text().length())
unsigned textLength = text().length();
#if PLATFORM(GTK)
// Gtk ATs need this for all text objects; not just text controls.
if (!textLength) {
Node* node = this->node();
if (node) {
RenderText* renderText = toRenderText(node->renderer());
if (renderText)
textLength = renderText->textLength();
// Get the text length from the elements under the
// accessibility object if not a RenderText object.
if (!textLength && allowsTextRanges())
textLength = textUnderElement().length();
}
}
#endif
if (range.start + range.length > textLength)
return VisiblePositionRange();
VisiblePosition startPosition = visiblePositionForIndex(range.start);
......
......@@ -587,6 +587,12 @@ protected:
virtual void clearChildren();
virtual bool isDetached() const { return true; }
#if PLATFORM(GTK)
bool allowsTextRanges() const;
#else
bool allowsTextRanges() const { return isTextControl(); }
#endif
#if PLATFORM(MAC)
RetainPtr<AccessibilityObjectWrapper> m_wrapper;
#elif PLATFORM(WIN) && !OS(WINCE)
......
......@@ -2393,8 +2393,8 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) co
if (isNativeTextControl())
return toRenderTextControl(m_renderer)->visiblePositionForIndex(index);
if (!isTextControl() && !m_renderer->isText())
if (!allowsTextRanges() && !m_renderer->isText())
return VisiblePosition();
Node* node = m_renderer->node();
......@@ -2653,7 +2653,7 @@ String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range
// on the display screen, in pixels.
IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const
{
if (isTextControl())
if (allowsTextRanges())
return boundsForVisiblePositionRange(visiblePositionRangeForRange(range));
return IntRect();
}
......
......@@ -93,6 +93,11 @@ void AccessibilityObject::setWrapper(AccessibilityObjectWrapper* wrapper)
g_object_ref(m_wrapper);
}
bool AccessibilityObject::allowsTextRanges() const
{
return isTextControl() || isWebArea() || isGroup() || isLink() || isHeading();
}
} // namespace WebCore
#endif // HAVE(ACCESSIBILITY)
......@@ -1259,29 +1259,48 @@ static AtkAttributeSet* webkit_accessible_text_get_default_attributes(AtkText* t
return getAttributeSetForAccessibilityObject(coreObject);
}
static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
static IntRect textExtents(AtkText* text, gint startOffset, gint length, AtkCoordType coords)
{
IntRect extents = core(text)->doAXBoundsForRange(PlainTextRange(offset, 1));
// FIXME: Use the AtkCoordType
// Requires WebCore::ScrollView::contentsToScreen() to be implemented
gchar* textContent = webkit_accessible_text_get_text(text, startOffset, -1);
gint textLength = g_utf8_strlen(textContent, -1);
// The first case (endOffset of -1) should work, but seems broken for all Gtk+ apps.
gint rangeLength = length;
if (rangeLength < 0 || rangeLength > textLength)
rangeLength = textLength;
AccessibilityObject* coreObject = core(text);
#if 0
IntRect extents = coreObject->doAXBoundsForRange(PlainTextRange(startOffset, rangeLength));
switch(coords) {
case ATK_XY_SCREEN:
extents = core(text)->document()->view()->contentsToScreen(extents);
extents = coreObject->document()->view()->contentsToScreen(extents);
break;
case ATK_XY_WINDOW:
// No-op
break;
}
#endif
return extents;
}
static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
{
IntRect extents = textExtents(text, offset, 1, coords);
*x = extents.x();
*y = extents.y();
*width = extents.width();
*height = extents.height();
}
static void webkit_accessible_text_get_range_extents(AtkText* text, gint startOffset, gint endOffset, AtkCoordType coords, AtkTextRectangle* rect)
{
IntRect extents = textExtents(text, startOffset, endOffset - startOffset + 1, coords);
rect->x = extents.x();
rect->y = extents.y();
rect->width = extents.width();
rect->height = extents.height();
}
static gint webkit_accessible_text_get_character_count(AtkText* text)
{
AccessibilityObject* coreObject = core(text);
......@@ -1391,6 +1410,7 @@ static void atk_text_interface_init(AtkTextIface* iface)
iface->get_run_attributes = webkit_accessible_text_get_run_attributes;
iface->get_default_attributes = webkit_accessible_text_get_default_attributes;
iface->get_character_extents = webkit_accessible_text_get_character_extents;
iface->get_range_extents = webkit_accessible_text_get_range_extents;
iface->get_character_count = webkit_accessible_text_get_character_count;
iface->get_offset_at_point = webkit_accessible_text_get_offset_at_point;
iface->get_n_selections = webkit_accessible_text_get_n_selections;
......
2010-08-02 Mario Sanchez Prada <msanchez@igalia.com>
Reviewed by Chris Fleizach.
[GTK] Implement support for get_character_extents and get_range_extents
https://bugs.webkit.org/show_bug.cgi?id=25677
Added new unit tests to check get_character_extents and
get_range_extents functions for the ATK_TEXT interface
Based on a previous patch by Joanmarie Diggs.
* tests/testatk.c:
(test_webkit_atk_get_extents):
(main):
2010-08-02 Jeremy Orlow <jorlow@chromium.org>
Speculative revert of 64425 due to Chromium instability
......
......@@ -26,6 +26,8 @@
#if GLIB_CHECK_VERSION(2, 16, 0) && GTK_CHECK_VERSION(2, 14, 0)
static const char* centeredContents = "<html><body><p style='text-align: center;'>Short line</p><p style='text-align: center;'>Long-size line with some foo bar baz content</p><p style='text-align: center;'>Short line</p><p style='text-align: center;'>This is a multi-line paragraph<br />where the first line<br />is the biggest one</p></body></html>";
static const char* contents = "<html><body><p>This is a test. This is the second sentence. And this the third.</p></body></html>";
static const char* contentsWithNewlines = "<html><body><p>This is a test. \n\nThis\n is the second sentence. And this the third.</p></body></html>";
......@@ -738,6 +740,109 @@ static void testWebkitAtkTextAttributes(void)
atk_attribute_set_free(set3);
}
static void test_webkit_atk_get_extents(void)
{
WebKitWebView* webView;
AtkObject* obj;
GMainLoop* loop;
webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
g_object_ref_sink(webView);
GtkAllocation alloc = { 0, 0, 800, 600 };
gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc);
webkit_web_view_load_string(webView, centeredContents, NULL, NULL, NULL);
loop = g_main_loop_new(NULL, TRUE);
g_timeout_add(100, (GSourceFunc)bail_out, loop);
g_main_loop_run(loop);
obj = gtk_widget_get_accessible(GTK_WIDGET(webView));
g_assert(obj);
AtkText* short_text1 = ATK_TEXT(atk_object_ref_accessible_child(obj, 0));
g_assert(ATK_IS_TEXT(short_text1));
AtkText* long_text = ATK_TEXT(atk_object_ref_accessible_child(obj, 1));
g_assert(ATK_IS_TEXT(long_text));
AtkText* short_text2 = ATK_TEXT(atk_object_ref_accessible_child(obj, 2));
g_assert(ATK_IS_TEXT(short_text2));
AtkText* multiline_text = ATK_TEXT(atk_object_ref_accessible_child(obj, 3));
g_assert(ATK_IS_TEXT(multiline_text));
// Start with window extents.
AtkTextRectangle sline_window1, sline_window2, lline_window, mline_window;
atk_text_get_range_extents(short_text1, 0, 10, ATK_XY_WINDOW, &sline_window1);
atk_text_get_range_extents(long_text, 0, 44, ATK_XY_WINDOW, &lline_window);
atk_text_get_range_extents(short_text2, 0, 10, ATK_XY_WINDOW, &sline_window2);
atk_text_get_range_extents(multiline_text, 0, 60, ATK_XY_WINDOW, &mline_window);
// Check vertical line position.
g_assert_cmpint(sline_window1.y + sline_window1.height, <=, lline_window.y);
g_assert_cmpint(lline_window.y + lline_window.height + sline_window2.height, <=, mline_window.y);
// Paragraphs 1 and 3 have identical text and alignment.
g_assert_cmpint(sline_window1.x, ==, sline_window2.x);
g_assert_cmpint(sline_window1.width, ==, sline_window2.width);
g_assert_cmpint(sline_window1.height, ==, sline_window2.height);
// All lines should be the same height; line 2 is the widest line.
g_assert_cmpint(sline_window1.height, ==, lline_window.height);
g_assert_cmpint(sline_window1.width, <, lline_window.width);
// Make sure the character extents jive with the range extents.
gint x, y, width, height;
// First paragraph (short text)
atk_text_get_character_extents(short_text1, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, sline_window1.x);
g_assert_cmpint(y, ==, sline_window1.y);
g_assert_cmpint(height, ==, sline_window1.height);
atk_text_get_character_extents(short_text1, 9, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, sline_window1.x + sline_window1.width - width);
g_assert_cmpint(y, ==, sline_window1.y);
g_assert_cmpint(height, ==, sline_window1.height);
// Second paragraph (long text)
atk_text_get_character_extents(long_text, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, lline_window.x);
g_assert_cmpint(y, ==, lline_window.y);
g_assert_cmpint(height, ==, lline_window.height);
atk_text_get_character_extents(long_text, 43, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, lline_window.x + lline_window.width - width);
g_assert_cmpint(y, ==, lline_window.y);
g_assert_cmpint(height, ==, lline_window.height);
// Third paragraph (short text)
atk_text_get_character_extents(short_text2, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, sline_window2.x);
g_assert_cmpint(y, ==, sline_window2.y);
g_assert_cmpint(height, ==, sline_window2.height);
atk_text_get_character_extents(short_text2, 9, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, sline_window2.x + sline_window2.width - width);
g_assert_cmpint(y, ==, sline_window2.y);
g_assert_cmpint(height, ==, sline_window2.height);
// Four paragraph (3 lines multi-line text)
atk_text_get_character_extents(multiline_text, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
g_assert_cmpint(x, ==, mline_window.x);
g_assert_cmpint(y, ==, mline_window.y);
g_assert_cmpint(3 * height, ==, mline_window.height);
atk_text_get_character_extents(multiline_text, 59, &x, &y, &width, &height, ATK_XY_WINDOW);
// Last line won't fill the whole width of the rectangle
g_assert_cmpint(x, <=, mline_window.x + mline_window.width - width);
g_assert_cmpint(y, ==, mline_window.y + mline_window.height - height);
g_assert_cmpint(height, <=, mline_window.height);
g_object_unref(short_text1);
g_object_unref(short_text2);
g_object_unref(long_text);
g_object_unref(multiline_text);
g_object_unref(webView);
}
int main(int argc, char** argv)
{
g_thread_init(NULL);
......@@ -754,6 +859,7 @@ int main(int argc, char** argv)
g_test_add_func("/webkit/atk/getTextInTable", testWebkitAtkGetTextInTable);
g_test_add_func("/webkit/atk/getHeadersInTable", testWebkitAtkGetHeadersInTable);
g_test_add_func("/webkit/atk/textAttributes", testWebkitAtkTextAttributes);
g_test_add_func("/webkit/atk/get_extents", test_webkit_atk_get_extents);
return g_test_run ();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment