1/* 2 * Copyright (C) 2009 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "FrameSelection.h" 22 23#if HAVE(ACCESSIBILITY) 24 25#include "AXObjectCache.h" 26#include "Document.h" 27#include "Frame.h" 28#include "WebKitAccessibleWrapperAtk.h" 29 30#if PLATFORM(EFL) 31#include <glib.h> 32#else 33#include <gtk/gtk.h> 34#endif 35 36#include <wtf/NeverDestroyed.h> 37#include <wtf/RefPtr.h> 38 39namespace WebCore { 40 41static void emitTextSelectionChange(AccessibilityObject* object, VisibleSelection selection, int offset) 42{ 43 AtkObject* axObject = object->wrapper(); 44 if (!axObject || !ATK_IS_TEXT(axObject)) 45 return; 46 47 g_signal_emit_by_name(axObject, "text-caret-moved", offset); 48 if (selection.isRange()) 49 g_signal_emit_by_name(axObject, "text-selection-changed"); 50} 51 52static void maybeEmitTextFocusChange(PassRefPtr<AccessibilityObject> prpObject) 53{ 54 // This static variable is needed to keep track of the old object 55 // as per previous calls to this function, in order to properly 56 // decide whether to emit some signals or not. 57 static NeverDestroyed<RefPtr<AccessibilityObject>> oldObject; 58 59 RefPtr<AccessibilityObject> object = prpObject; 60 61 // Ensure the oldObject belongs to the same document that the 62 // current object so further comparisons make sense. Otherwise, 63 // just reset oldObject to 0 so it won't be taken into account in 64 // the immediately following call to this function. 65 if (object && oldObject.get() && oldObject.get()->document() != object->document()) 66 oldObject.get() = nullptr; 67 68 AtkObject* axObject = object ? object->wrapper() : 0; 69 AtkObject* oldAxObject = oldObject.get() ? oldObject.get()->wrapper() : nullptr; 70 71 if (axObject != oldAxObject) { 72 if (oldAxObject && ATK_IS_TEXT(oldAxObject)) { 73 g_signal_emit_by_name(oldAxObject, "focus-event", false); 74 atk_object_notify_state_change(oldAxObject, ATK_STATE_FOCUSED, false); 75 } 76 if (axObject && ATK_IS_TEXT(axObject)) { 77 g_signal_emit_by_name(axObject, "focus-event", true); 78 atk_object_notify_state_change(axObject, ATK_STATE_FOCUSED, true); 79 } 80 } 81 82 // Update pointer to last focused object. 83 oldObject.get() = object; 84} 85 86 87void FrameSelection::notifyAccessibilityForSelectionChange() 88{ 89 if (!AXObjectCache::accessibilityEnabled()) 90 return; 91 92 if (!m_selection.start().isNotNull() || !m_selection.end().isNotNull()) 93 return; 94 95 RenderObject* focusedNode = m_selection.end().containerNode()->renderer(); 96 AXObjectCache* cache = m_frame->document()->existingAXObjectCache(); 97 if (!cache) 98 return; 99 100 AccessibilityObject* accessibilityObject = cache->getOrCreate(focusedNode); 101 if (!accessibilityObject) 102 return; 103 104 int offset; 105 RefPtr<AccessibilityObject> object = objectFocusedAndCaretOffsetUnignored(accessibilityObject, offset); 106 if (!object) 107 return; 108 109 emitTextSelectionChange(object.get(), m_selection, offset); 110 maybeEmitTextFocusChange(object.release()); 111} 112 113} // namespace WebCore 114 115#endif // HAVE(ACCESSIBILITY) 116