summaryrefslogtreecommitdiffstats
path: root/accessible/base/TextRange.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/base/TextRange.cpp')
-rw-r--r--accessible/base/TextRange.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/accessible/base/TextRange.cpp b/accessible/base/TextRange.cpp
new file mode 100644
index 000000000..30474d2fa
--- /dev/null
+++ b/accessible/base/TextRange.cpp
@@ -0,0 +1,380 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TextRange-inl.h"
+
+#include "Accessible-inl.h"
+#include "nsAccUtils.h"
+
+namespace mozilla {
+namespace a11y {
+
+////////////////////////////////////////////////////////////////////////////////
+// TextPoint
+
+bool
+TextPoint::operator <(const TextPoint& aPoint) const
+{
+ if (mContainer == aPoint.mContainer)
+ return mOffset < aPoint.mOffset;
+
+ // Build the chain of parents
+ Accessible* p1 = mContainer;
+ Accessible* p2 = aPoint.mContainer;
+ AutoTArray<Accessible*, 30> parents1, parents2;
+ do {
+ parents1.AppendElement(p1);
+ p1 = p1->Parent();
+ } while (p1);
+ do {
+ parents2.AppendElement(p2);
+ p2 = p2->Parent();
+ } while (p2);
+
+ // Find where the parent chain differs
+ uint32_t pos1 = parents1.Length(), pos2 = parents2.Length();
+ for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
+ Accessible* child1 = parents1.ElementAt(--pos1);
+ Accessible* child2 = parents2.ElementAt(--pos2);
+ if (child1 != child2)
+ return child1->IndexInParent() < child2->IndexInParent();
+ }
+
+ NS_ERROR("Broken tree?!");
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TextRange
+
+TextRange::TextRange(HyperTextAccessible* aRoot,
+ HyperTextAccessible* aStartContainer, int32_t aStartOffset,
+ HyperTextAccessible* aEndContainer, int32_t aEndOffset) :
+ mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer),
+ mStartOffset(aStartOffset), mEndOffset(aEndOffset)
+{
+}
+
+void
+TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
+{
+ if (mStartContainer == mEndContainer) {
+ int32_t startIdx = mStartContainer->GetChildIndexAtOffset(mStartOffset);
+ int32_t endIdx = mStartContainer->GetChildIndexAtOffset(mEndOffset);
+ for (int32_t idx = startIdx; idx <= endIdx; idx++) {
+ Accessible* child = mStartContainer->GetChildAt(idx);
+ if (!child->IsText()) {
+ aChildren->AppendElement(child);
+ }
+ }
+ return;
+ }
+
+ Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
+ Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
+
+ uint32_t pos1 = 0, pos2 = 0;
+ AutoTArray<Accessible*, 30> parents1, parents2;
+ Accessible* container =
+ CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
+
+ // Traverse the tree up to the container and collect embedded objects.
+ for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
+ Accessible* parent = parents1[idx + 1];
+ Accessible* child = parents1[idx];
+ uint32_t childCount = parent->ChildCount();
+ for (uint32_t childIdx = child->IndexInParent(); childIdx < childCount; childIdx++) {
+ Accessible* next = parent->GetChildAt(childIdx);
+ if (!next->IsText()) {
+ aChildren->AppendElement(next);
+ }
+ }
+ }
+
+ // Traverse through direct children in the container.
+ int32_t endIdx = parents2[pos2 - 1]->IndexInParent();
+ int32_t childIdx = parents1[pos1 - 1]->IndexInParent() + 1;
+ for (; childIdx < endIdx; childIdx++) {
+ Accessible* next = container->GetChildAt(childIdx);
+ if (!next->IsText()) {
+ aChildren->AppendElement(next);
+ }
+ }
+
+ // Traverse down from the container to end point.
+ for (int32_t idx = pos2 - 2; idx > 0; idx--) {
+ Accessible* parent = parents2[idx];
+ Accessible* child = parents2[idx - 1];
+ int32_t endIdx = child->IndexInParent();
+ for (int32_t childIdx = 0; childIdx < endIdx; childIdx++) {
+ Accessible* next = parent->GetChildAt(childIdx);
+ if (!next->IsText()) {
+ aChildren->AppendElement(next);
+ }
+ }
+ }
+}
+
+void
+TextRange::Text(nsAString& aText) const
+{
+ Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset);
+ uint32_t startIntlOffset =
+ mStartOffset - mStartContainer->GetChildOffset(current);
+
+ while (current && TextInternal(aText, current, startIntlOffset)) {
+ current = current->Parent();
+ if (!current)
+ break;
+
+ current = current->NextSibling();
+ }
+}
+
+void
+TextRange::Bounds(nsTArray<nsIntRect> aRects) const
+{
+
+}
+
+void
+TextRange::Normalize(ETextUnit aUnit)
+{
+
+}
+
+bool
+TextRange::Crop(Accessible* aContainer)
+{
+ uint32_t boundaryPos = 0, containerPos = 0;
+ AutoTArray<Accessible*, 30> boundaryParents, containerParents;
+
+ // Crop the start boundary.
+ Accessible* container = nullptr;
+ Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
+ if (boundary != aContainer) {
+ CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
+ &containerParents, &containerPos);
+
+ if (boundaryPos == 0) {
+ if (containerPos != 0) {
+ // The container is contained by the start boundary, reduce the range to
+ // the point starting at the container.
+ aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
+ static_cast<Accessible*>(mStartContainer)->AddRef();
+ }
+ else {
+ // The start boundary and the container are siblings.
+ container = aContainer;
+ }
+ }
+ else if (containerPos != 0) {
+ // The container does not contain the start boundary.
+ boundary = boundaryParents[boundaryPos];
+ container = containerParents[containerPos];
+ }
+
+ if (container) {
+ // If the range start is after the container, then make the range invalid.
+ if (boundary->IndexInParent() > container->IndexInParent()) {
+ return !!(mRoot = nullptr);
+ }
+
+ // If the range starts before the container, then reduce the range to
+ // the point starting at the container.
+ if (boundary->IndexInParent() < container->IndexInParent()) {
+ container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
+ mStartContainer.get()->AddRef();
+ }
+ }
+
+ boundaryParents.SetLengthAndRetainStorage(0);
+ containerParents.SetLengthAndRetainStorage(0);
+ }
+
+ boundary = mEndContainer->GetChildAtOffset(mEndOffset);
+ if (boundary == aContainer) {
+ return true;
+ }
+
+ // Crop the end boundary.
+ container = nullptr;
+ CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
+ &containerParents, &containerPos);
+
+ if (boundaryPos == 0) {
+ if (containerPos != 0) {
+ aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
+ static_cast<Accessible*>(mEndContainer)->AddRef();
+ }
+ else {
+ container = aContainer;
+ }
+ }
+ else if (containerPos != 0) {
+ boundary = boundaryParents[boundaryPos];
+ container = containerParents[containerPos];
+ }
+
+ if (!container) {
+ return true;
+ }
+
+ if (boundary->IndexInParent() < container->IndexInParent()) {
+ return !!(mRoot = nullptr);
+ }
+
+ if (boundary->IndexInParent() > container->IndexInParent()) {
+ container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
+ static_cast<Accessible*>(mEndContainer)->AddRef();
+ }
+
+ return true;
+}
+
+void
+TextRange::FindText(const nsAString& aText, EDirection aDirection,
+ nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
+{
+
+}
+
+void
+TextRange::FindAttr(EAttr aAttr, nsIVariant* aValue, EDirection aDirection,
+ TextRange* aFoundRange) const
+{
+
+}
+
+void
+TextRange::AddToSelection() const
+{
+
+}
+
+void
+TextRange::RemoveFromSelection() const
+{
+
+}
+
+void
+TextRange::Select() const
+{
+}
+
+void
+TextRange::ScrollIntoView(EHowToAlign aHow) const
+{
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// pivate
+
+void
+TextRange::Set(HyperTextAccessible* aRoot,
+ HyperTextAccessible* aStartContainer, int32_t aStartOffset,
+ HyperTextAccessible* aEndContainer, int32_t aEndOffset)
+{
+ mRoot = aRoot;
+ mStartContainer = aStartContainer;
+ mEndContainer = aEndContainer;
+ mStartOffset = aStartOffset;
+ mEndOffset = aEndOffset;
+}
+
+bool
+TextRange::TextInternal(nsAString& aText, Accessible* aCurrent,
+ uint32_t aStartIntlOffset) const
+{
+ bool moveNext = true;
+ int32_t endIntlOffset = -1;
+ if (aCurrent->Parent() == mEndContainer &&
+ mEndContainer->GetChildAtOffset(mEndOffset) == aCurrent) {
+
+ uint32_t currentStartOffset = mEndContainer->GetChildOffset(aCurrent);
+ endIntlOffset = mEndOffset - currentStartOffset;
+ if (endIntlOffset == 0)
+ return false;
+
+ moveNext = false;
+ }
+
+ if (aCurrent->IsTextLeaf()) {
+ aCurrent->AppendTextTo(aText, aStartIntlOffset,
+ endIntlOffset - aStartIntlOffset);
+ if (!moveNext)
+ return false;
+ }
+
+ Accessible* next = aCurrent->FirstChild();
+ if (next) {
+ if (!TextInternal(aText, next, 0))
+ return false;
+ }
+
+ next = aCurrent->NextSibling();
+ if (next) {
+ if (!TextInternal(aText, next, 0))
+ return false;
+ }
+
+ return moveNext;
+}
+
+
+void
+TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
+ HyperTextAccessible& aContainer, int32_t aOffset,
+ HyperTextAccessible* aStopContainer, int32_t aStopOffset)
+{
+
+}
+
+Accessible*
+TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
+ nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
+ nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
+{
+ if (aAcc1 == aAcc2) {
+ return aAcc1;
+ }
+
+ MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
+ "Wrong arguments");
+
+ // Build the chain of parents.
+ Accessible* p1 = aAcc1;
+ Accessible* p2 = aAcc2;
+ do {
+ aParents1->AppendElement(p1);
+ p1 = p1->Parent();
+ } while (p1);
+ do {
+ aParents2->AppendElement(p2);
+ p2 = p2->Parent();
+ } while (p2);
+
+ // Find where the parent chain differs
+ *aPos1 = aParents1->Length();
+ *aPos2 = aParents2->Length();
+ Accessible* parent = nullptr;
+ uint32_t len = 0;
+ for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
+ Accessible* child1 = aParents1->ElementAt(--(*aPos1));
+ Accessible* child2 = aParents2->ElementAt(--(*aPos2));
+ if (child1 != child2)
+ break;
+
+ parent = child1;
+ }
+
+ return parent;
+}
+
+} // namespace a11y
+} // namespace mozilla