diff options
Diffstat (limited to 'accessible/base/TextRange.cpp')
-rw-r--r-- | accessible/base/TextRange.cpp | 380 |
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 |