TextRange.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "TextRange-inl.h"
  6. #include "Accessible-inl.h"
  7. #include "nsAccUtils.h"
  8. namespace mozilla {
  9. namespace a11y {
  10. ////////////////////////////////////////////////////////////////////////////////
  11. // TextPoint
  12. bool
  13. TextPoint::operator <(const TextPoint& aPoint) const
  14. {
  15. if (mContainer == aPoint.mContainer)
  16. return mOffset < aPoint.mOffset;
  17. // Build the chain of parents
  18. Accessible* p1 = mContainer;
  19. Accessible* p2 = aPoint.mContainer;
  20. AutoTArray<Accessible*, 30> parents1, parents2;
  21. do {
  22. parents1.AppendElement(p1);
  23. p1 = p1->Parent();
  24. } while (p1);
  25. do {
  26. parents2.AppendElement(p2);
  27. p2 = p2->Parent();
  28. } while (p2);
  29. // Find where the parent chain differs
  30. uint32_t pos1 = parents1.Length(), pos2 = parents2.Length();
  31. for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
  32. Accessible* child1 = parents1.ElementAt(--pos1);
  33. Accessible* child2 = parents2.ElementAt(--pos2);
  34. if (child1 != child2)
  35. return child1->IndexInParent() < child2->IndexInParent();
  36. }
  37. NS_ERROR("Broken tree?!");
  38. return false;
  39. }
  40. ////////////////////////////////////////////////////////////////////////////////
  41. // TextRange
  42. TextRange::TextRange(HyperTextAccessible* aRoot,
  43. HyperTextAccessible* aStartContainer, int32_t aStartOffset,
  44. HyperTextAccessible* aEndContainer, int32_t aEndOffset) :
  45. mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer),
  46. mStartOffset(aStartOffset), mEndOffset(aEndOffset)
  47. {
  48. }
  49. void
  50. TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
  51. {
  52. if (mStartContainer == mEndContainer) {
  53. int32_t startIdx = mStartContainer->GetChildIndexAtOffset(mStartOffset);
  54. int32_t endIdx = mStartContainer->GetChildIndexAtOffset(mEndOffset);
  55. for (int32_t idx = startIdx; idx <= endIdx; idx++) {
  56. Accessible* child = mStartContainer->GetChildAt(idx);
  57. if (!child->IsText()) {
  58. aChildren->AppendElement(child);
  59. }
  60. }
  61. return;
  62. }
  63. Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
  64. Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
  65. uint32_t pos1 = 0, pos2 = 0;
  66. AutoTArray<Accessible*, 30> parents1, parents2;
  67. Accessible* container =
  68. CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
  69. // Traverse the tree up to the container and collect embedded objects.
  70. for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
  71. Accessible* parent = parents1[idx + 1];
  72. Accessible* child = parents1[idx];
  73. uint32_t childCount = parent->ChildCount();
  74. for (uint32_t childIdx = child->IndexInParent(); childIdx < childCount; childIdx++) {
  75. Accessible* next = parent->GetChildAt(childIdx);
  76. if (!next->IsText()) {
  77. aChildren->AppendElement(next);
  78. }
  79. }
  80. }
  81. // Traverse through direct children in the container.
  82. int32_t endIdx = parents2[pos2 - 1]->IndexInParent();
  83. int32_t childIdx = parents1[pos1 - 1]->IndexInParent() + 1;
  84. for (; childIdx < endIdx; childIdx++) {
  85. Accessible* next = container->GetChildAt(childIdx);
  86. if (!next->IsText()) {
  87. aChildren->AppendElement(next);
  88. }
  89. }
  90. // Traverse down from the container to end point.
  91. for (int32_t idx = pos2 - 2; idx > 0; idx--) {
  92. Accessible* parent = parents2[idx];
  93. Accessible* child = parents2[idx - 1];
  94. int32_t endIdx = child->IndexInParent();
  95. for (int32_t childIdx = 0; childIdx < endIdx; childIdx++) {
  96. Accessible* next = parent->GetChildAt(childIdx);
  97. if (!next->IsText()) {
  98. aChildren->AppendElement(next);
  99. }
  100. }
  101. }
  102. }
  103. void
  104. TextRange::Text(nsAString& aText) const
  105. {
  106. Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset);
  107. uint32_t startIntlOffset =
  108. mStartOffset - mStartContainer->GetChildOffset(current);
  109. while (current && TextInternal(aText, current, startIntlOffset)) {
  110. current = current->Parent();
  111. if (!current)
  112. break;
  113. current = current->NextSibling();
  114. }
  115. }
  116. void
  117. TextRange::Bounds(nsTArray<nsIntRect> aRects) const
  118. {
  119. }
  120. void
  121. TextRange::Normalize(ETextUnit aUnit)
  122. {
  123. }
  124. bool
  125. TextRange::Crop(Accessible* aContainer)
  126. {
  127. uint32_t boundaryPos = 0, containerPos = 0;
  128. AutoTArray<Accessible*, 30> boundaryParents, containerParents;
  129. // Crop the start boundary.
  130. Accessible* container = nullptr;
  131. Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
  132. if (boundary != aContainer) {
  133. CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
  134. &containerParents, &containerPos);
  135. if (boundaryPos == 0) {
  136. if (containerPos != 0) {
  137. // The container is contained by the start boundary, reduce the range to
  138. // the point starting at the container.
  139. aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
  140. static_cast<Accessible*>(mStartContainer)->AddRef();
  141. }
  142. else {
  143. // The start boundary and the container are siblings.
  144. container = aContainer;
  145. }
  146. }
  147. else if (containerPos != 0) {
  148. // The container does not contain the start boundary.
  149. boundary = boundaryParents[boundaryPos];
  150. container = containerParents[containerPos];
  151. }
  152. if (container) {
  153. // If the range start is after the container, then make the range invalid.
  154. if (boundary->IndexInParent() > container->IndexInParent()) {
  155. return !!(mRoot = nullptr);
  156. }
  157. // If the range starts before the container, then reduce the range to
  158. // the point starting at the container.
  159. if (boundary->IndexInParent() < container->IndexInParent()) {
  160. container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
  161. mStartContainer.get()->AddRef();
  162. }
  163. }
  164. boundaryParents.SetLengthAndRetainStorage(0);
  165. containerParents.SetLengthAndRetainStorage(0);
  166. }
  167. boundary = mEndContainer->GetChildAtOffset(mEndOffset);
  168. if (boundary == aContainer) {
  169. return true;
  170. }
  171. // Crop the end boundary.
  172. container = nullptr;
  173. CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
  174. &containerParents, &containerPos);
  175. if (boundaryPos == 0) {
  176. if (containerPos != 0) {
  177. aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
  178. static_cast<Accessible*>(mEndContainer)->AddRef();
  179. }
  180. else {
  181. container = aContainer;
  182. }
  183. }
  184. else if (containerPos != 0) {
  185. boundary = boundaryParents[boundaryPos];
  186. container = containerParents[containerPos];
  187. }
  188. if (!container) {
  189. return true;
  190. }
  191. if (boundary->IndexInParent() < container->IndexInParent()) {
  192. return !!(mRoot = nullptr);
  193. }
  194. if (boundary->IndexInParent() > container->IndexInParent()) {
  195. container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
  196. static_cast<Accessible*>(mEndContainer)->AddRef();
  197. }
  198. return true;
  199. }
  200. void
  201. TextRange::FindText(const nsAString& aText, EDirection aDirection,
  202. nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
  203. {
  204. }
  205. void
  206. TextRange::FindAttr(EAttr aAttr, nsIVariant* aValue, EDirection aDirection,
  207. TextRange* aFoundRange) const
  208. {
  209. }
  210. void
  211. TextRange::AddToSelection() const
  212. {
  213. }
  214. void
  215. TextRange::RemoveFromSelection() const
  216. {
  217. }
  218. void
  219. TextRange::Select() const
  220. {
  221. }
  222. void
  223. TextRange::ScrollIntoView(EHowToAlign aHow) const
  224. {
  225. }
  226. ////////////////////////////////////////////////////////////////////////////////
  227. // pivate
  228. void
  229. TextRange::Set(HyperTextAccessible* aRoot,
  230. HyperTextAccessible* aStartContainer, int32_t aStartOffset,
  231. HyperTextAccessible* aEndContainer, int32_t aEndOffset)
  232. {
  233. mRoot = aRoot;
  234. mStartContainer = aStartContainer;
  235. mEndContainer = aEndContainer;
  236. mStartOffset = aStartOffset;
  237. mEndOffset = aEndOffset;
  238. }
  239. bool
  240. TextRange::TextInternal(nsAString& aText, Accessible* aCurrent,
  241. uint32_t aStartIntlOffset) const
  242. {
  243. bool moveNext = true;
  244. int32_t endIntlOffset = -1;
  245. if (aCurrent->Parent() == mEndContainer &&
  246. mEndContainer->GetChildAtOffset(mEndOffset) == aCurrent) {
  247. uint32_t currentStartOffset = mEndContainer->GetChildOffset(aCurrent);
  248. endIntlOffset = mEndOffset - currentStartOffset;
  249. if (endIntlOffset == 0)
  250. return false;
  251. moveNext = false;
  252. }
  253. if (aCurrent->IsTextLeaf()) {
  254. aCurrent->AppendTextTo(aText, aStartIntlOffset,
  255. endIntlOffset - aStartIntlOffset);
  256. if (!moveNext)
  257. return false;
  258. }
  259. Accessible* next = aCurrent->FirstChild();
  260. if (next) {
  261. if (!TextInternal(aText, next, 0))
  262. return false;
  263. }
  264. next = aCurrent->NextSibling();
  265. if (next) {
  266. if (!TextInternal(aText, next, 0))
  267. return false;
  268. }
  269. return moveNext;
  270. }
  271. void
  272. TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
  273. HyperTextAccessible& aContainer, int32_t aOffset,
  274. HyperTextAccessible* aStopContainer, int32_t aStopOffset)
  275. {
  276. }
  277. Accessible*
  278. TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
  279. nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
  280. nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
  281. {
  282. if (aAcc1 == aAcc2) {
  283. return aAcc1;
  284. }
  285. MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
  286. "Wrong arguments");
  287. // Build the chain of parents.
  288. Accessible* p1 = aAcc1;
  289. Accessible* p2 = aAcc2;
  290. do {
  291. aParents1->AppendElement(p1);
  292. p1 = p1->Parent();
  293. } while (p1);
  294. do {
  295. aParents2->AppendElement(p2);
  296. p2 = p2->Parent();
  297. } while (p2);
  298. // Find where the parent chain differs
  299. *aPos1 = aParents1->Length();
  300. *aPos2 = aParents2->Length();
  301. Accessible* parent = nullptr;
  302. uint32_t len = 0;
  303. for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
  304. Accessible* child1 = aParents1->ElementAt(--(*aPos1));
  305. Accessible* child2 = aParents2->ElementAt(--(*aPos2));
  306. if (child1 != child2)
  307. break;
  308. parent = child1;
  309. }
  310. return parent;
  311. }
  312. } // namespace a11y
  313. } // namespace mozilla