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_RemoteAccessibleBase_h
8 #define mozilla_a11y_RemoteAccessibleBase_h
9 
10 #include "mozilla/a11y/Accessible.h"
11 #include "mozilla/a11y/Role.h"
12 #include "nsIAccessibleText.h"
13 #include "nsIAccessibleTypes.h"
14 #include "LocalAccessible.h"
15 #include "nsString.h"
16 #include "nsTArray.h"
17 #include "nsRect.h"
18 #include "LocalAccessible.h"
19 
20 namespace mozilla {
21 namespace a11y {
22 
23 class LocalAccessible;
24 class Attribute;
25 class DocAccessibleParent;
26 class RemoteAccessible;
27 enum class RelationType;
28 
29 template <class Derived>
30 class RemoteAccessibleBase : public Accessible {
31  public:
~RemoteAccessibleBase()32   virtual ~RemoteAccessibleBase() { MOZ_ASSERT(!mWrapper); }
33 
IsRemote()34   virtual bool IsRemote() const override { return true; }
35 
AddChildAt(uint32_t aIdx,Derived * aChild)36   void AddChildAt(uint32_t aIdx, Derived* aChild) {
37     mChildren.InsertElementAt(aIdx, aChild);
38   }
39 
ChildCount()40   virtual uint32_t ChildCount() const override { return mChildren.Length(); }
RemoteChildAt(uint32_t aIdx)41   Derived* RemoteChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
RemoteFirstChild()42   Derived* RemoteFirstChild() const {
43     return mChildren.Length() ? mChildren[0] : nullptr;
44   }
RemoteLastChild()45   Derived* RemoteLastChild() const {
46     return mChildren.Length() ? mChildren[mChildren.Length() - 1] : nullptr;
47   }
RemotePrevSibling()48   Derived* RemotePrevSibling() const {
49     if (IsDoc()) {
50       // The normal code path doesn't work for documents because the parent
51       // might be a local OuterDoc, but IndexInParent() will return 1.
52       // A document is always a single child of an OuterDoc anyway.
53       return nullptr;
54     }
55     int32_t idx = IndexInParent();
56     if (idx == -1) {
57       return nullptr;  // No parent.
58     }
59     return idx > 0 ? RemoteParent()->mChildren[idx - 1] : nullptr;
60   }
RemoteNextSibling()61   Derived* RemoteNextSibling() const {
62     if (IsDoc()) {
63       // The normal code path doesn't work for documents because the parent
64       // might be a local OuterDoc, but IndexInParent() will return 1.
65       // A document is always a single child of an OuterDoc anyway.
66       return nullptr;
67     }
68     int32_t idx = IndexInParent();
69     if (idx == -1) {
70       return nullptr;  // No parent.
71     }
72     MOZ_ASSERT(idx >= 0);
73     size_t newIdx = idx + 1;
74     return newIdx < RemoteParent()->mChildren.Length()
75                ? RemoteParent()->mChildren[newIdx]
76                : nullptr;
77   }
78 
79   // Accessible hierarchy method overrides
80 
Parent()81   virtual Accessible* Parent() const override {
82     if (Derived* parent = RemoteParent()) {
83       return parent;
84     }
85 
86     return OuterDocOfRemoteBrowser();
87   }
88 
ChildAt(uint32_t aIndex)89   virtual Accessible* ChildAt(uint32_t aIndex) const override {
90     return RemoteChildAt(aIndex);
91   }
92 
NextSibling()93   virtual Accessible* NextSibling() const override {
94     return RemoteNextSibling();
95   }
96 
PrevSibling()97   virtual Accessible* PrevSibling() const override {
98     return RemotePrevSibling();
99   }
100 
101   // XXX evaluate if this is fast enough.
IndexInParent()102   virtual int32_t IndexInParent() const override {
103     Derived* parent = RemoteParent();
104     if (!parent) {
105       return -1;
106     }
107     return parent->mChildren.IndexOf(static_cast<const Derived*>(this));
108   }
109   uint32_t EmbeddedChildCount() const;
110   int32_t IndexOfEmbeddedChild(const Derived* aChild);
111   Derived* EmbeddedChildAt(size_t aChildIdx);
112 
113   void Shutdown();
114 
115   void SetChildDoc(DocAccessibleParent* aChildDoc);
116   void ClearChildDoc(DocAccessibleParent* aChildDoc);
117 
118   /**
119    * Remove The given child.
120    */
RemoveChild(Derived * aChild)121   void RemoveChild(Derived* aChild) { mChildren.RemoveElement(aChild); }
122 
123   /**
124    * Return the proxy for the parent of the wrapped accessible.
125    */
126   Derived* RemoteParent() const;
127 
128   LocalAccessible* OuterDocOfRemoteBrowser() const;
129 
130   /**
131    * Get the role of the accessible we're proxying.
132    */
Role()133   virtual role Role() const override { return mRole; }
134 
135   /**
136    * Return true if this is an embedded object.
137    */
IsEmbeddedObject()138   bool IsEmbeddedObject() const {
139     role role = Role();
140     return role != roles::TEXT_LEAF && role != roles::WHITESPACE &&
141            role != roles::STATICTEXT;
142   }
143 
IsLink()144   virtual bool IsLink() const override {
145     if (IsHTMLLink()) {
146       // XXX: HTML links always return true for IsLink.
147       return true;
148     }
149 
150     if (IsText()) {
151       return false;
152     }
153 
154     if (Accessible* parent = Parent()) {
155       return parent->IsHyperText();
156     }
157 
158     return false;
159   }
160 
HasNumericValue()161   virtual bool HasNumericValue() const override {
162     // XXX: We combine the aria and native "has numeric value" field
163     // when we serialize the local accessible into eNumericValue.
164     return HasGenericType(eNumericValue);
165   }
166 
167   /**
168    * Allow the platform to store a pointers worth of data on us.
169    */
GetWrapper()170   uintptr_t GetWrapper() const { return mWrapper; }
SetWrapper(uintptr_t aWrapper)171   void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
172 
173   /*
174    * Return the ID of the accessible being proxied.
175    */
ID()176   uint64_t ID() const { return mID; }
177 
178   /**
179    * Return the document containing this proxy, or the proxy itself if it is a
180    * document.
181    */
Document()182   DocAccessibleParent* Document() const { return mDoc; }
183 
AsDoc()184   DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; }
185 
186  protected:
RemoteAccessibleBase(uint64_t aID,Derived * aParent,DocAccessibleParent * aDoc,role aRole,AccType aType,AccGenericType aGenericTypes,uint8_t aRoleMapEntryIndex)187   RemoteAccessibleBase(uint64_t aID, Derived* aParent,
188                        DocAccessibleParent* aDoc, role aRole, AccType aType,
189                        AccGenericType aGenericTypes, uint8_t aRoleMapEntryIndex)
190       : Accessible(aType, aGenericTypes, aRoleMapEntryIndex),
191         mParent(aParent->ID()),
192         mDoc(aDoc),
193         mWrapper(0),
194         mID(aID),
195         mRole(aRole) {}
196 
RemoteAccessibleBase(DocAccessibleParent * aThisAsDoc)197   explicit RemoteAccessibleBase(DocAccessibleParent* aThisAsDoc)
198       : Accessible(),
199         mParent(kNoParent),
200         mDoc(aThisAsDoc),
201         mWrapper(0),
202         mID(0),
203         mRole(roles::DOCUMENT) {
204     mGenericTypes = eDocument | eHyperText;
205   }
206 
207  protected:
208   void SetParent(Derived* aParent);
209 
210  private:
211   uintptr_t mParent;
212   static const uintptr_t kNoParent = UINTPTR_MAX;
213 
214   friend Derived;
215 
216   nsTArray<Derived*> mChildren;
217   DocAccessibleParent* mDoc;
218   uintptr_t mWrapper;
219   uint64_t mID;
220 
221  protected:
222   // XXX DocAccessibleParent gets to change this to change the role of
223   // documents.
224   role mRole : 27;
225 };
226 
227 extern template class RemoteAccessibleBase<RemoteAccessible>;
228 
229 }  // namespace a11y
230 }  // namespace mozilla
231 
232 #endif
233