nsMaiInterfaceComponent.cpp (5379B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "InterfaceInitFuncs.h" 8 9 #include "LocalAccessible-inl.h" 10 #include "AccessibleWrap.h" 11 #include "nsAccUtils.h" 12 #include "nsMai.h" 13 #include "nsWindow.h" 14 #include "mozilla/Likely.h" 15 #include "mozilla/a11y/DocAccessibleParent.h" 16 #include "mozilla/a11y/RemoteAccessible.h" 17 #include "mozilla/dom/BrowserParent.h" 18 #include "mozilla/dom/Document.h" 19 #include "nsAccessibilityService.h" 20 21 using namespace mozilla; 22 using namespace mozilla::a11y; 23 24 extern "C" { 25 26 static AtkObject* refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, 27 gint aAccY, AtkCoordType aCoordType) { 28 return refAccessibleAtPointHelper(ATK_OBJECT(aComponent), aAccX, aAccY, 29 aCoordType); 30 } 31 32 static void getExtentsCB(AtkComponent* aComponent, gint* aX, gint* aY, 33 gint* aWidth, gint* aHeight, AtkCoordType aCoordType) { 34 getExtentsHelper(ATK_OBJECT(aComponent), aX, aY, aWidth, aHeight, aCoordType); 35 } 36 37 static gboolean grabFocusCB(AtkComponent* aComponent) { 38 AtkObject* atkObject = ATK_OBJECT(aComponent); 39 Accessible* acc = GetInternalObj(atkObject); 40 if (acc) { 41 acc->TakeFocus(); 42 return TRUE; 43 } 44 return FALSE; 45 } 46 47 // ScrollType is compatible 48 MOZ_CAN_RUN_SCRIPT_BOUNDARY 49 static gboolean scrollToCB(AtkComponent* aComponent, AtkScrollType type) { 50 AtkObject* atkObject = ATK_OBJECT(aComponent); 51 if (Accessible* acc = GetInternalObj(atkObject)) { 52 acc->ScrollTo(type); 53 return TRUE; 54 } 55 56 return FALSE; 57 } 58 59 // CoordType is compatible 60 static gboolean scrollToPointCB(AtkComponent* aComponent, AtkCoordType coords, 61 gint x, gint y) { 62 AtkObject* atkObject = ATK_OBJECT(aComponent); 63 AccessibleWrap* accWrap = GetAccessibleWrap(atkObject); 64 if (accWrap) { 65 accWrap->ScrollToPoint(coords, x, y); 66 return TRUE; 67 } 68 69 RemoteAccessible* proxy = GetProxy(atkObject); 70 if (proxy) { 71 proxy->ScrollToPoint(coords, x, y); 72 return TRUE; 73 } 74 75 return FALSE; 76 } 77 } 78 79 AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY, 80 AtkCoordType aCoordType) { 81 Accessible* acc = GetInternalObj(aAtkObj); 82 if (!acc) { 83 return nullptr; 84 } 85 86 // Accessible::ChildAtPoint(x,y) is in screen pixels. 87 if (aCoordType == ATK_XY_WINDOW) { 88 mozilla::LayoutDeviceIntPoint winCoords = 89 nsAccUtils::GetScreenCoordsForWindow(acc); 90 aX += winCoords.x; 91 aY += winCoords.y; 92 } 93 94 Accessible* accAtPoint = 95 acc->ChildAtPoint(aX, aY, Accessible::EWhichChildAtPoint::DeepestChild); 96 if (!accAtPoint) { 97 return nullptr; 98 } 99 roles::Role role = accAtPoint->Role(); 100 if (role == roles::TEXT_LEAF || role == roles::STATICTEXT) { 101 // We don't include text leaf nodes in the ATK tree, so return the parent. 102 accAtPoint = accAtPoint->Parent(); 103 MOZ_ASSERT(accAtPoint, "Text leaf should always have a parent"); 104 } 105 AtkObject* atkObj = GetWrapperFor(accAtPoint); 106 if (atkObj) { 107 g_object_ref(atkObj); 108 } 109 return atkObj; 110 } 111 112 static double getScaleFactor(Accessible* aAccessible) { 113 DocAccessible* docAcc = nullptr; 114 if (LocalAccessible* localAcc = aAccessible->AsLocal()) { 115 docAcc = localAcc->Document(); 116 } else { 117 RemoteAccessible* remote = aAccessible->AsRemote(); 118 LocalAccessible* outerDoc = remote->OuterDocOfRemoteBrowser(); 119 if (outerDoc) { 120 docAcc = outerDoc->Document(); 121 } 122 } 123 124 if (!docAcc || !docAcc->DocumentNode()) { 125 return 1.0; 126 } 127 128 nsCOMPtr<nsIWidget> rootWidget = 129 nsContentUtils::WidgetForDocument(docAcc->DocumentNode()); 130 if (!rootWidget) { 131 return 1.0; 132 } 133 134 if (RefPtr<nsWindow> window = 135 static_cast<nsWindow*>(rootWidget->GetTopLevelWidget())) { 136 return window->FractionalScaleFactor(); 137 } 138 139 return 1.0; 140 } 141 142 void getExtentsHelper(AtkObject* aAtkObj, gint* aX, gint* aY, gint* aWidth, 143 gint* aHeight, AtkCoordType aCoordType) { 144 *aX = *aY = *aWidth = *aHeight = -1; 145 146 Accessible* acc = GetInternalObj(aAtkObj); 147 if (!acc) { 148 return; 149 } 150 151 mozilla::LayoutDeviceIntRect screenRect = acc->Bounds(); 152 if (screenRect.IsEmpty()) { 153 return; 154 } 155 156 if (aCoordType == ATK_XY_WINDOW) { 157 mozilla::LayoutDeviceIntPoint winCoords = 158 nsAccUtils::GetScreenCoordsForWindow(acc); 159 screenRect.x -= winCoords.x; 160 screenRect.y -= winCoords.y; 161 } 162 163 double scaleFactor = getScaleFactor(acc); 164 165 *aX = screenRect.x / scaleFactor; 166 *aY = screenRect.y / scaleFactor; 167 *aWidth = screenRect.width / scaleFactor; 168 *aHeight = screenRect.height / scaleFactor; 169 } 170 171 void componentInterfaceInitCB(AtkComponentIface* aIface) { 172 NS_ASSERTION(aIface, "Invalid Interface"); 173 if (MOZ_UNLIKELY(!aIface)) return; 174 175 /* 176 * Use default implementation in atk for contains, get_position, 177 * and get_size 178 */ 179 aIface->ref_accessible_at_point = refAccessibleAtPointCB; 180 aIface->get_extents = getExtentsCB; 181 aIface->grab_focus = grabFocusCB; 182 if (IsAtkVersionAtLeast(2, 30)) { 183 aIface->scroll_to = scrollToCB; 184 aIface->scroll_to_point = scrollToPointCB; 185 } 186 }