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_relation_h_
8 #define mozilla_a11y_relation_h_
9 
10 #include "AccIterator.h"
11 
12 #include <memory>
13 
14 namespace mozilla {
15 namespace a11y {
16 
17 /**
18  * A collection of relation targets of a certain type.  Targets are computed
19  * lazily while enumerating.
20  */
21 class Relation {
22  public:
Relation()23   Relation() : mFirstIter(nullptr), mLastIter(nullptr) {}
24 
Relation(AccIterable * aIter)25   explicit Relation(AccIterable* aIter) : mFirstIter(aIter), mLastIter(aIter) {}
26 
Relation(LocalAccessible * aAcc)27   explicit Relation(LocalAccessible* aAcc)
28       : mFirstIter(nullptr), mLastIter(nullptr) {
29     AppendTarget(aAcc);
30   }
31 
Relation(DocAccessible * aDocument,nsIContent * aContent)32   Relation(DocAccessible* aDocument, nsIContent* aContent)
33       : mFirstIter(nullptr), mLastIter(nullptr) {
34     AppendTarget(aDocument, aContent);
35   }
36 
Relation(Relation && aOther)37   Relation(Relation&& aOther)
38       : mFirstIter(std::move(aOther.mFirstIter)), mLastIter(aOther.mLastIter) {
39     aOther.mLastIter = nullptr;
40   }
41 
42   Relation& operator=(Relation&& aRH) {
43     mFirstIter = std::move(aRH.mFirstIter);
44     mLastIter = aRH.mLastIter;
45     aRH.mLastIter = nullptr;
46     return *this;
47   }
48 
AppendIter(AccIterable * aIter)49   inline void AppendIter(AccIterable* aIter) {
50     if (mLastIter) {
51       mLastIter->mNextIter.reset(aIter);
52     } else {
53       mFirstIter.reset(aIter);
54     }
55 
56     mLastIter = aIter;
57   }
58 
59   /**
60    * Append the given accessible to the set of related accessibles.
61    */
AppendTarget(LocalAccessible * aAcc)62   inline void AppendTarget(LocalAccessible* aAcc) {
63     if (aAcc) AppendIter(new SingleAccIterator(aAcc));
64   }
65 
66   /**
67    * Append the one accessible for this content node to the set of related
68    * accessibles.
69    */
AppendTarget(DocAccessible * aDocument,nsIContent * aContent)70   void AppendTarget(DocAccessible* aDocument, nsIContent* aContent) {
71     if (aContent) AppendTarget(aDocument->GetAccessible(aContent));
72   }
73 
74   /**
75    * compute and return the next related accessible.
76    */
Next()77   inline LocalAccessible* Next() {
78     LocalAccessible* target = nullptr;
79 
80     while (mFirstIter && !(target = mFirstIter->Next())) {
81       mFirstIter = std::move(mFirstIter->mNextIter);
82     }
83 
84     if (!mFirstIter) mLastIter = nullptr;
85 
86     return target;
87   }
88 
89  private:
90   Relation& operator=(const Relation&) = delete;
91   Relation(const Relation&) = delete;
92 
93   std::unique_ptr<AccIterable> mFirstIter;
94   AccIterable* mLastIter;
95 };
96 
97 }  // namespace a11y
98 }  // namespace mozilla
99 
100 #endif
101