RemoteAccessible.h (18185B)
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 #ifndef mozilla_a11y_RemoteAccessible_h 8 #define mozilla_a11y_RemoteAccessible_h 9 10 #include "mozilla/a11y/Accessible.h" 11 #include "mozilla/a11y/CacheConstants.h" 12 #include "mozilla/a11y/HyperTextAccessibleBase.h" 13 #include "mozilla/a11y/Role.h" 14 #include "AccAttributes.h" 15 #include "nsIAccessibleText.h" 16 #include "nsIAccessibleTypes.h" 17 #include "nsTArray.h" 18 #include "nsRect.h" 19 #include "LocalAccessible.h" 20 21 namespace mozilla { 22 namespace a11y { 23 24 class Attribute; 25 class DocAccessibleParent; 26 class RemoteAccessible; 27 enum class RelationType; 28 29 /** 30 * The class for an accessibility tree node that originated in the parent 31 * process. 32 */ 33 class RemoteAccessible : public Accessible, public HyperTextAccessibleBase { 34 public: 35 virtual ~RemoteAccessible() { 36 MOZ_ASSERT(!mWrapper); 37 MOZ_COUNT_DTOR(RemoteAccessible); 38 } 39 40 virtual bool IsRemote() const override { return true; } 41 42 void AddChildAt(uint32_t aIdx, RemoteAccessible* aChild) { 43 mChildren.InsertElementAt(aIdx, aChild); 44 UpdateChildIndexCache(static_cast<int32_t>(aIdx)); 45 if (IsHyperText()) { 46 InvalidateCachedHyperTextOffsets(); 47 } 48 } 49 50 virtual uint32_t ChildCount() const override { return mChildren.Length(); } 51 RemoteAccessible* RemoteChildAt(uint32_t aIdx) const { 52 RemoteAccessible* child = mChildren.SafeElementAt(aIdx); 53 MOZ_ASSERT(!child || child->mParent == this, 54 "Child's parent should be this"); 55 return child; 56 } 57 RemoteAccessible* RemoteFirstChild() const { 58 return mChildren.Length() ? mChildren[0] : nullptr; 59 } 60 RemoteAccessible* RemoteLastChild() const { 61 return mChildren.Length() ? mChildren[mChildren.Length() - 1] : nullptr; 62 } 63 RemoteAccessible* RemotePrevSibling() const { 64 if (IsDoc()) { 65 // The normal code path doesn't work for documents because the parent 66 // might be a local OuterDoc, but IndexInParent() will return 0. 67 // A document is always a single child of an OuterDoc anyway. 68 return nullptr; 69 } 70 int32_t idx = IndexInParent(); 71 if (idx == -1) { 72 return nullptr; // No parent. 73 } 74 MOZ_ASSERT(RemoteParent()); 75 return idx > 0 ? RemoteParent()->mChildren[idx - 1] : nullptr; 76 } 77 RemoteAccessible* RemoteNextSibling() const { 78 if (IsDoc()) { 79 // The normal code path doesn't work for documents because the parent 80 // might be a local OuterDoc, but IndexInParent() will return 0. 81 // A document is always a single child of an OuterDoc anyway. 82 return nullptr; 83 } 84 int32_t idx = IndexInParent(); 85 if (idx == -1) { 86 return nullptr; // No parent. 87 } 88 MOZ_ASSERT(idx >= 0); 89 size_t newIdx = idx + 1; 90 MOZ_ASSERT(RemoteParent()); 91 return newIdx < RemoteParent()->mChildren.Length() 92 ? RemoteParent()->mChildren[newIdx] 93 : nullptr; 94 } 95 96 // Accessible hierarchy method overrides 97 98 virtual Accessible* Parent() const override { return RemoteParent(); } 99 100 virtual Accessible* ChildAt(uint32_t aIndex) const override { 101 return RemoteChildAt(aIndex); 102 } 103 104 virtual Accessible* NextSibling() const override { 105 return RemoteNextSibling(); 106 } 107 108 virtual Accessible* PrevSibling() const override { 109 return RemotePrevSibling(); 110 } 111 112 virtual int32_t IndexInParent() const override { 113 MOZ_ASSERT(mParent || mIndexInParent == -1, 114 "IndexInParent should be -1 if no parent"); 115 return mIndexInParent; 116 } 117 118 virtual uint32_t EmbeddedChildCount() override; 119 virtual int32_t IndexOfEmbeddedChild(Accessible* aChild) override; 120 virtual Accessible* EmbeddedChildAt(uint32_t aChildIdx) override; 121 122 void Shutdown(); 123 124 void SetChildDoc(DocAccessibleParent* aChildDoc); 125 void ClearChildDoc(DocAccessibleParent* aChildDoc); 126 127 /** 128 * Remove The given child. 129 */ 130 void RemoveChild(RemoteAccessible* aChild) { 131 mChildren.RemoveElement(aChild); 132 MOZ_ASSERT(aChild->mIndexInParent != -1); 133 UpdateChildIndexCache(aChild->mIndexInParent); 134 aChild->mIndexInParent = -1; 135 if (IsHyperText()) { 136 InvalidateCachedHyperTextOffsets(); 137 } 138 } 139 140 /** 141 * Return the proxy for the parent of the wrapped accessible. 142 */ 143 RemoteAccessible* RemoteParent() const; 144 145 LocalAccessible* OuterDocOfRemoteBrowser() const; 146 147 /** 148 * Get the native role of the accessible we're proxying. 149 */ 150 virtual mozilla::a11y::role NativeRole() const override { 151 return mNativeRole; 152 } 153 154 /** 155 * Return true if this is an embedded object. 156 */ 157 bool IsEmbeddedObject() const { return !IsText(); } 158 159 virtual bool IsLink() const override { 160 if (IsHTMLLink()) { 161 // XXX: HTML links always return true for IsLink. 162 return true; 163 } 164 165 if (IsText()) { 166 return false; 167 } 168 169 if (Accessible* parent = Parent()) { 170 return parent->IsHyperText(); 171 } 172 173 return false; 174 } 175 176 virtual bool HasNumericValue() const override { 177 // XXX: We combine the aria and native "has numeric value" field 178 // when we serialize the local accessible into eNumericValue. 179 return HasGenericType(eNumericValue); 180 } 181 182 // Methods that potentially access a cache. 183 184 virtual ENameValueFlag Name(nsString& aName) const override final; 185 virtual EDescriptionValueFlag Description( 186 nsString& aDescription) const override; 187 virtual void Value(nsString& aValue) const override; 188 189 virtual double CurValue() const override; 190 virtual double MinValue() const override; 191 virtual double MaxValue() const override; 192 virtual double Step() const override; 193 virtual bool SetCurValue(double aValue) override; 194 195 virtual Accessible* ChildAtPoint( 196 int32_t aX, int32_t aY, 197 LocalAccessible::EWhichChildAtPoint aWhichChild) override; 198 199 virtual LayoutDeviceIntRect Bounds() const override; 200 201 virtual nsRect BoundsInAppUnits() const override; 202 203 virtual Relation RelationByType(RelationType aType) const override; 204 205 virtual uint64_t State() override; 206 207 virtual already_AddRefed<AccAttributes> Attributes() override; 208 209 virtual nsAtom* TagName() const override; 210 211 virtual already_AddRefed<nsAtom> DisplayStyle() const override; 212 213 virtual float Opacity() const override; 214 215 virtual WritingMode GetWritingMode() const override; 216 217 virtual void LiveRegionAttributes(nsAString* aLive, nsAString* aRelevant, 218 Maybe<bool>* aAtomic, 219 nsAString* aBusy) const override; 220 221 virtual Maybe<bool> ARIASelected() const override; 222 223 virtual uint8_t ActionCount() const override; 224 225 virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override; 226 227 virtual bool DoAction(uint8_t aIndex) const override; 228 229 virtual KeyBinding AccessKey() const override; 230 231 virtual void SelectionRanges(nsTArray<TextRange>* aRanges) const override; 232 233 MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual bool RemoveFromSelection( 234 int32_t aSelectionNum) override; 235 236 virtual Maybe<int32_t> GetIntARIAAttr(nsAtom* aAttrName) const override; 237 238 virtual bool GetStringARIAAttr(nsAtom* aAttrName, 239 nsAString& aAttrValue) const override; 240 241 virtual bool ARIAAttrValueIs(nsAtom* aAttrName, 242 nsAtom* aAttrValue) const override; 243 244 virtual bool HasARIAAttr(nsAtom* aAttrName) const override; 245 246 virtual void Language(nsAString& aLocale) override; 247 248 ////////////////////////////////////////////////////////////////////////////// 249 // EditableTextAccessible 250 251 MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void ReplaceText( 252 const nsAString& aText) override; 253 MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void InsertText( 254 const nsAString& aText, int32_t aPosition) override; 255 MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void CopyText(int32_t aStartPos, 256 int32_t aEndPos) override; 257 MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void CutText(int32_t aStartPos, 258 int32_t aEndPos) override; 259 MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void DeleteText(int32_t aStartPos, 260 int32_t aEndPos) override; 261 MOZ_CAN_RUN_SCRIPT virtual void PasteText(int32_t aPosition) override; 262 263 ////////////////////////////////////////////////////////////////////////////// 264 // SelectAccessible 265 266 virtual void SelectedItems(nsTArray<Accessible*>* aItems) override; 267 268 virtual uint32_t SelectedItemCount() override; 269 270 virtual Accessible* GetSelectedItem(uint32_t aIndex) override; 271 272 virtual bool IsItemSelected(uint32_t aIndex) override; 273 274 virtual bool AddItemToSelection(uint32_t aIndex) override; 275 276 virtual bool RemoveItemFromSelection(uint32_t aIndex) override; 277 278 virtual bool SelectAll() override; 279 280 virtual bool UnselectAll() override; 281 282 virtual void TakeSelection() override; 283 284 virtual void SetSelected(bool aSelect) override; 285 286 // Methods that interact with content. 287 288 virtual void TakeFocus() const override; 289 virtual void ScrollTo(uint32_t aHow) const override; 290 291 /** 292 * Allow the platform to store a pointers worth of data on us. 293 */ 294 uintptr_t GetWrapper() const { return mWrapper; } 295 void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; } 296 297 virtual uint64_t ID() const override { return mID; } 298 299 /** 300 * Return the document containing this proxy, or the proxy itself if it is a 301 * document. 302 */ 303 DocAccessibleParent* Document() const { return mDoc; } 304 305 DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; } 306 307 void ApplyCache(CacheUpdateType aUpdateType, AccAttributes* aFields); 308 309 void UpdateStateCache(uint64_t aState, bool aEnabled) { 310 if (aState & kRemoteCalculatedStates) { 311 return; 312 } 313 uint64_t state = 0; 314 if (mCachedFields) { 315 if (auto oldState = 316 mCachedFields->GetAttribute<uint64_t>(CacheKey::State)) { 317 state = *oldState; 318 } 319 } else { 320 mCachedFields = new AccAttributes(); 321 } 322 if (aEnabled) { 323 state |= aState; 324 } else { 325 state &= ~aState; 326 } 327 mCachedFields->SetAttribute(CacheKey::State, state); 328 } 329 330 void InvalidateGroupInfo(); 331 332 virtual void AppendTextTo(nsAString& aText, uint32_t aStartOffset = 0, 333 uint32_t aLength = UINT32_MAX) override; 334 335 virtual bool TableIsProbablyForLayout(); 336 337 /** 338 * Iterates through each atom in kRelationTypeAtoms, checking to see 339 * if it is present in aFields. If it is present (or if aFields contains 340 * a DeleteEntry() for this atom) and mCachedFields is initialized, 341 * fetches the old rel targets and removes their existing reverse relations 342 * stored in mReverseRelations. 343 * Returns an array of bools where the ith array entry corresponds 344 * to whether or not the rel at the ith entry of kRelationTypeAtoms 345 * requires a post-processing update. 346 */ 347 nsTArray<bool> PreProcessRelations(AccAttributes* aFields); 348 349 /** 350 * Takes in the array returned from PreProcessRelations. 351 * For each entry requiring an update, fetches the new relation 352 * targets stored in mCachedFields and appropriately 353 * updates their reverse relations in mReverseRelations. 354 */ 355 void PostProcessRelations(const nsTArray<bool>& aToUpdate); 356 357 /** 358 * This method is called during shutdown, before we clear our 359 * reverse rel map from the document's mReverseRelations cache. 360 * Here, we traverse our reverse relations, removing our ID from 361 * the corresponding forward relation's target list. This ensures 362 * the stored forward relations do not reference defunct accessibles. 363 */ 364 void PruneRelationsOnShutdown(); 365 366 uint32_t GetCachedTextLength(); 367 Maybe<const nsTArray<int32_t>&> GetCachedTextLines(); 368 nsRect GetCachedCharRect(int32_t aOffset); 369 RefPtr<const AccAttributes> GetCachedTextAttributes(); 370 const AccAttributes* GetCachedARIAAttributes() const; 371 372 nsString GetCachedHTMLNameAttribute() const; 373 374 virtual HyperTextAccessibleBase* AsHyperTextBase() override { 375 return IsHyperText() ? static_cast<HyperTextAccessibleBase*>(this) 376 : nullptr; 377 } 378 379 virtual TableAccessible* AsTable() override; 380 virtual TableCellAccessible* AsTableCell() override; 381 382 virtual void DOMNodeID(nsString& aID) const override; 383 384 virtual void DOMNodeClass(nsString& aClass) const override; 385 386 virtual void ScrollToPoint(uint32_t aScrollType, int32_t aX, 387 int32_t aY) override; 388 389 virtual bool IsScrollable() const override; 390 391 virtual bool IsPopover() const override; 392 393 virtual bool HasPrimaryAction() const override; 394 395 virtual bool HasCustomActions() const override; 396 virtual bool IsEditable() const override; 397 398 #if !defined(XP_WIN) 399 void Announce(const nsString& aAnnouncement, uint16_t aPriority); 400 #endif // !defined(XP_WIN) 401 402 // HTMLMeterAccessible 403 int32_t ValueRegion() const; 404 405 // HyperTextAccessibleBase 406 virtual already_AddRefed<AccAttributes> DefaultTextAttributes() override; 407 408 virtual void ScrollSubstringToPoint(int32_t aStartOffset, int32_t aEndOffset, 409 uint32_t aCoordinateType, int32_t aX, 410 int32_t aY) override; 411 412 virtual std::pair<mozilla::LayoutDeviceIntRect, nsIWidget*> GetCaretRect() 413 override; 414 415 /** 416 * Invalidate cached HyperText offsets. This should be called whenever a 417 * child is added or removed or the text of a text leaf child is changed. 418 * Although GetChildOffset can either fully or partially invalidate the 419 * offsets cache, calculating which offset to invalidate is not worthwhile 420 * because a client might not even query offsets. This is in contrast to 421 * LocalAccessible, where the offsets are always needed to fire text change 422 * events. For RemoteAccessible, it's cheaper overall to just rebuild the 423 * offsets cache when a client next needs it. 424 */ 425 void InvalidateCachedHyperTextOffsets() { 426 if (mCachedFields) { 427 mCachedFields->Remove(CacheKey::HyperTextOffsets); 428 } 429 } 430 431 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf); 432 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf); 433 434 protected: 435 RemoteAccessible(uint64_t aID, DocAccessibleParent* aDoc, role aRole, 436 AccType aType, AccGenericType aGenericTypes, 437 uint8_t aRoleMapEntryIndex) 438 : Accessible(aType, aGenericTypes, aRoleMapEntryIndex), 439 mParent(nullptr), 440 mDoc(aDoc), 441 mWrapper(0), 442 mID(aID), 443 mCachedFields(nullptr), 444 mNativeRole(aRole) { 445 MOZ_COUNT_CTOR(RemoteAccessible); 446 } 447 448 explicit RemoteAccessible(DocAccessibleParent* aThisAsDoc) 449 : mParent(nullptr), 450 mDoc(aThisAsDoc), 451 mWrapper(0), 452 mID(0), 453 mCachedFields(nullptr), 454 mNativeRole(roles::DOCUMENT) { 455 mGenericTypes = eDocument | eHyperText; 456 MOZ_COUNT_CTOR(RemoteAccessible); 457 } 458 459 protected: 460 void SetParent(RemoteAccessible* aParent); 461 Maybe<nsRect> RetrieveCachedBounds() const; 462 bool ApplyTransform(nsRect& aCumulativeBounds) const; 463 bool ApplyScrollOffset(nsRect& aBounds, float aResolution) const; 464 void ApplyCrossDocOffset(nsRect& aBounds) const; 465 void ApplyVisualViewportOffset(nsRect& aBounds) const; 466 LayoutDeviceIntRect BoundsWithOffset( 467 Maybe<nsRect> aOffset, bool aBoundsAreForHittesting = false) const; 468 bool IsFixedPos() const; 469 bool IsOverflowHidden() const; 470 471 /** 472 * Returns true if an accessible's frame has no scrollable overflow, and 473 * false otherwise. 474 * Does not return true for partially clipped accessibles. 475 */ 476 bool IsClipped() const; 477 478 /** 479 * Checks if our hittesting match has any clipped children and, if so 480 * descends it and subsequent TEXT_CONTAINERs in search of a text leaf. 481 * We do this because some sites use clipping to hide text that is only 482 * visible to a11y, while displaying a visual version of the same text on 483 * the web page. We want a hittest of the visible text to resolve to the 484 * hidden, a11y-only text node. 485 */ 486 RemoteAccessible* DoFuzzyHittesting(); 487 488 // This function is used exclusively for hit testing. 489 bool ContainsPoint(int32_t aX, int32_t aY); 490 491 virtual void ARIAGroupPosition(int32_t* aLevel, int32_t* aSetSize, 492 int32_t* aPosInSet) const override; 493 494 virtual AccGroupInfo* GetGroupInfo() const override; 495 496 virtual AccGroupInfo* GetOrCreateGroupInfo() override; 497 498 virtual void GetPositionAndSetSize(int32_t* aPosInSet, 499 int32_t* aSetSize) override; 500 nsAtom* GetPrimaryAction() const; 501 502 virtual nsTArray<int32_t>& GetCachedHyperTextOffsets() override; 503 504 nsTArray<Accessible*> LegendsOrCaptions() const; 505 506 RemoteAccessible* LegendOrCaptionFor() const; 507 508 private: 509 /** 510 * Update mIndexInParent on each child starting at aStartIdx up to the last 511 * child. This should be called when a child is added or removed. 512 */ 513 void UpdateChildIndexCache(int32_t aStartIdx) { 514 int32_t count = static_cast<int32_t>(mChildren.Length()); 515 for (int32_t idx = aStartIdx; idx < count; ++idx) { 516 mChildren[idx]->mIndexInParent = idx; 517 } 518 } 519 520 RemoteAccessible* mParent; 521 522 friend DocAccessibleParent; 523 friend TextLeafPoint; 524 friend HyperTextAccessibleBase; 525 friend class xpcAccessible; 526 friend class CachedTableCellAccessible; 527 #ifdef XP_WIN 528 friend class sdnAccessible; 529 #endif 530 531 nsTArray<RemoteAccessible*> mChildren; 532 DocAccessibleParent* mDoc; 533 uintptr_t mWrapper; 534 uint64_t mID; 535 int32_t mIndexInParent = -1; 536 537 protected: 538 virtual const Accessible* Acc() const override { return this; } 539 540 RefPtr<AccAttributes> mCachedFields; 541 542 // XXX DocAccessibleParent gets to change this to change the role of 543 // documents. 544 role mNativeRole : 27; 545 }; 546 547 //////////////////////////////////////////////////////////////////////////////// 548 // RemoteAccessible downcasting method 549 550 inline RemoteAccessible* Accessible::AsRemote() { 551 return IsRemote() ? static_cast<RemoteAccessible*>(this) : nullptr; 552 } 553 554 } // namespace a11y 555 } // namespace mozilla 556 557 #endif