☠☠ backed out by 3ade5772804d ☠ ☠ | |
author | Alexander Surkov <surkov.alexander@gmail.com> |
Thu, 22 May 2014 15:55:11 -0400 | |
changeset 203784 | 6c37e11551d8a1c668bbe4309432d4fa81dfc5d9 |
parent 203783 | eb24106356d9348e09f36eacac9bd8b367b4c01f |
child 203785 | f1068bf18e64b3aa4d16e9f9a006d3882a8b6595 |
push id | 3741 |
push user | asasaki@mozilla.com |
push date | Mon, 21 Jul 2014 20:25:18 +0000 |
treeherder | mozilla-beta@4d6f46f5af68 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | davidb |
bugs | 1011496 |
milestone | 32.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/public/nsIAccessibleTextRange.idl +++ b/accessible/public/nsIAccessibleTextRange.idl @@ -1,25 +1,154 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /* 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 "nsISupports.idl" interface nsIAccessible; +interface nsIAccessibleText; +interface nsIArray; +interface nsIVariant; /** * A range representing a piece of text in the document. */ -[scriptable, uuid(6fe17c33-6709-4d7a-9ba0-3d448c4b3ef4)] +[scriptable, uuid(525b3401-8a67-4822-b35d-661065767cd8)] interface nsIAccessibleTextRange : nsISupports { - readonly attribute nsIAccessible startContainer; + readonly attribute nsIAccessibleText startContainer; readonly attribute long startOffset; - readonly attribute nsIAccessible endContainer; + readonly attribute nsIAccessibleText endContainer; readonly attribute long endOffset; /** + * Return an accessible containing the whole range + */ + readonly attribute nsIAccessible container; + + /** + * Return embedded children within the range. + */ + readonly attribute nsIArray embeddedChildren; + + /** + * Return true if this range has the same end points of the given range. + */ + boolean compare(in nsIAccessibleTextRange aOtherRange); + + /** + * The two endpoints of the range (starting and ending). + */ + const unsigned long EndPoint_Start = 1; + const unsigned long EndPoint_End = 2; + + /** + * Compare this and given ranges end points. + * + * @return -1/0/1 if this range end point is before/equal/after the given + * range end point. + */ + long compareEndPoints(in unsigned long aEndPoint, + in nsIAccessibleTextRange aOtherRange, + in unsigned long aOtherRangeEndPoint); + + /** * Return text within the range. */ readonly attribute AString text; + + /** + * Return list of rects of the range. + */ + readonly attribute nsIArray bounds; + + const unsigned long FormatUnit = 0; + const unsigned long WordUnit = 1; + const unsigned long LineUnit = 2; + const unsigned long ParagraphUnit = 3; + const unsigned long PageUnit = 4; + const unsigned long DocumentUnit = 5; + + /** + * Move the boundary(ies) by the given number of the unit. + */ + void move(in unsigned long aUnit, in long aCount); + void moveStart(in unsigned long aUnit, in long aCount); + void moveEnd(in unsigned long aUnit, in long aCount); + + /** + * Normalize the range to the closest unit of the given type. + */ + void normalize(in unsigned long aUnit); + + /** + * Return range enclosing the found text. + */ + nsIAccessibleTextRange findText(in AString aText, in boolean aIsBackward, + in boolean aIsIgnoreCase); + + /** + * Text attributes. Used in conjunction with findAttrs(). + */ + const unsigned long AnimationStyleAttr = 0; + const unsigned long AnnotationObjectsAttr = 1; + const unsigned long AnnotationTypesAttr = 2; + const unsigned long BackgroundColorAttr = 3; + const unsigned long BulletStyleAttr = 4; + const unsigned long CapStyleAttr = 5; + const unsigned long CaretBidiModeAttr = 6; + const unsigned long CaretPositionAttr = 7; + const unsigned long CultureAttr = 8; + const unsigned long FontNameAttr = 9; + const unsigned long FontSizeAttr = 10; + const unsigned long FontWeightAttr = 11; + const unsigned long ForegroundColorAttr = 12; + const unsigned long HorizontalTextAlignmentAttr = 13; + const unsigned long IndentationFirstLineAttr = 14; + const unsigned long IndentationLeadingAttr = 15; + const unsigned long IndentationTrailingAttr = 16; + const unsigned long IsActiveAttr = 17; + const unsigned long IsHiddenAttr = 18; + const unsigned long IsItalicAttr = 19; + const unsigned long IsReadOnlyAttr = 20; + const unsigned long IsSubscriptAttr = 21; + const unsigned long IsSuperscriptAttr = 22; + const unsigned long LinkAttr = 23; + const unsigned long MarginBottomAttr = 24; + const unsigned long MarginLeadingAttr = 25; + const unsigned long MarginTopAttr = 26; + const unsigned long MarginTrailingAttr = 27; + const unsigned long OutlineStylesAttr = 28; + const unsigned long OverlineColorAttr = 29; + const unsigned long OverlineStyleAttr = 30; + const unsigned long SelectionActiveEndAttr = 31; + const unsigned long StrikethroughColorAttr = 32; + const unsigned long StrikethroughStyleAttr = 33; + const unsigned long StyleIdAttr = 34; + const unsigned long StyleNameAttr = 35; + const unsigned long TabsAttr = 36; + const unsigned long TextFlowDirectionsAttr = 37; + const unsigned long UnderlineColorAttr = 38; + const unsigned long UnderlineStyleAttr = 39; + + /** + * Return range enslosing the text having requested attribute. + */ + nsIAccessibleTextRange findAttr(in unsigned long aAttr, in nsIVariant aValue, + in boolean aIsBackward); + + /** + * Add/remove the text range from selection. + */ + void addToSelection(); + void removeFromSelection(); + void select(); + + const unsigned long AlignToTop = 0; + const unsigned long AlignToBottom = 1; + + /** + * Scroll the range into view. + */ + void scrollIntoView(in unsigned long aHow); };
--- a/accessible/src/base/TextRange.cpp +++ b/accessible/src/base/TextRange.cpp @@ -2,36 +2,294 @@ /* 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.h" #include "HyperTextAccessible.h" +#include "nsAccUtils.h" using namespace mozilla::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; + nsAutoTArray<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, - Accessible* aStartContainer, int32_t aStartOffset, - Accessible* aEndContainer, int32_t aEndOffset) : + HyperTextAccessible* aStartContainer, int32_t aStartOffset, + HyperTextAccessible* aEndContainer, int32_t aEndOffset) : mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer), mStartOffset(aStartOffset), mEndOffset(aEndOffset) { } +Accessible* +TextRange::Container() const +{ + if (mStartContainer == mEndContainer) + return mStartContainer; + + // Build the chain of parents + Accessible* p1 = mStartContainer; + Accessible* p2 = mEndContainer; + nsAutoTArray<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(); + uint32_t pos2 = parents2.Length(); + Accessible* parent = nullptr; + uint32_t len = 0; + for (len = std::min(pos1, pos2); len > 0; --len) { + Accessible* child1 = parents1.ElementAt(--pos1); + Accessible* child2 = parents2.ElementAt(--pos2); + if (child1 != child2) + break; + + parent = child1; + } + + return parent; +} + +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 (nsAccUtils::IsEmbeddedObject(child)) + aChildren->AppendElement(child); + } + return; + } + + Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset); + Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset); + nsAutoTArray<Accessible*, 30> parents1, parents2; + do { + parents1.AppendElement(p1); + p1 = p1->Parent(); + } while (p1); + do { + parents2.AppendElement(p2); + p2 = p2->Parent(); + } while (p2); + + // Find deepest common container. + uint32_t pos1 = parents1.Length(); + uint32_t pos2 = parents2.Length(); + Accessible* container = nullptr; + for (uint32_t len = std::min(pos1, pos2); len > 0; --len) { + Accessible* child1 = parents1.ElementAt(--pos1); + Accessible* child2 = parents2.ElementAt(--pos2); + if (child1 != child2) + break; + + container = child1; + } + + // 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 (nsAccUtils::IsEmbeddedObject(next)) + 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 (nsAccUtils::IsEmbeddedObject(next)) + 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 (nsAccUtils::IsEmbeddedObject(next)) + 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) +{ + +} + +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, - Accessible* aStartContainer, int32_t aStartOffset, - Accessible* aEndContainer, int32_t aEndOffset) + 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) +{ + +}
--- a/accessible/src/base/TextRange.h +++ b/accessible/src/base/TextRange.h @@ -4,77 +4,253 @@ * 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/. */ #ifndef mozilla_a11y_TextRange_h__ #define mozilla_a11y_TextRange_h__ #include "mozilla/Move.h" #include "nsAutoPtr.h" +#include "nsCaseTreatment.h" +#include "nsRect.h" +#include "nsTArray.h" + + class nsIVariant; namespace mozilla { namespace a11y { class Accessible; class HyperTextAccessible; /** + * A text point (hyper text + offset), represents a boundary of text range. + */ +struct TextPoint MOZ_FINAL +{ + TextPoint(HyperTextAccessible* aContainer, int32_t aOffset) : + mContainer(aContainer), mOffset(aOffset) { } + TextPoint(const TextPoint& aPoint) : + mContainer(aPoint.mContainer), mOffset(aPoint.mOffset) { } + + HyperTextAccessible* mContainer; + int32_t mOffset; + + bool operator ==(const TextPoint& aPoint) const + { return mContainer == aPoint.mContainer && mOffset == aPoint.mOffset; } + bool operator <(const TextPoint& aPoint) const; +}; + +/** * Represents a text range within the text control or document. */ class TextRange MOZ_FINAL { public: TextRange(HyperTextAccessible* aRoot, - Accessible* aStartContainer, int32_t aStartOffset, - Accessible* aEndContainer, int32_t aEndOffset); + HyperTextAccessible* aStartContainer, int32_t aStartOffset, + HyperTextAccessible* aEndContainer, int32_t aEndOffset); TextRange() {} TextRange(TextRange&& aRange) : - mRoot(Move(aRange.mRoot)), mStartContainer(Move(aRange.mStartContainer)), - mEndContainer(Move(aRange.mEndContainer)), + mRoot(mozilla::Move(aRange.mRoot)), + mStartContainer(mozilla::Move(aRange.mStartContainer)), + mEndContainer(mozilla::Move(aRange.mEndContainer)), mStartOffset(aRange.mStartOffset), mEndOffset(aRange.mEndOffset) {} TextRange& operator= (TextRange&& aRange) { - mRoot = Move(aRange.mRoot); - mStartContainer = Move(aRange.mStartContainer); - mEndContainer = Move(aRange.mEndContainer); + mRoot = mozilla::Move(aRange.mRoot); + mStartContainer = mozilla::Move(aRange.mStartContainer); + mEndContainer = mozilla::Move(aRange.mEndContainer); mStartOffset = aRange.mStartOffset; mEndOffset = aRange.mEndOffset; return *this; } - Accessible* StartContainer() const { return mStartContainer; } + HyperTextAccessible* StartContainer() const { return mStartContainer; } int32_t StartOffset() const { return mStartOffset; } - Accessible* EndContainer() const { return mEndContainer; } + HyperTextAccessible* EndContainer() const { return mEndContainer; } int32_t EndOffset() const { return mEndOffset; } + bool operator ==(const TextRange& aRange) const + { + return mStartContainer == aRange.mStartContainer && + mStartOffset == aRange.mStartOffset && + mEndContainer == aRange.mEndContainer && mEndOffset == aRange.mEndOffset; + } + + TextPoint StartPoint() const { return TextPoint(mStartContainer, mStartOffset); } + TextPoint EndPoint() const { return TextPoint(mEndContainer, mEndOffset); } + + /** + * Return a container containing both start and end points. + */ + Accessible* Container() const; + + /** + * Return a list of embedded objects enclosed by the text range (includes + * partially overlapped objects). + */ + void EmbeddedChildren(nsTArray<Accessible*>* aChildren) const; + /** * Return text enclosed by the range. */ void Text(nsAString& aText) const; /** + * Return list of bounding rects of the text range by lines. + */ + void Bounds(nsTArray<nsIntRect> aRects) const; + + enum ETextUnit { + eFormat, + eWord, + eLine, + eParagraph, + ePage, + eDocument + }; + + /** + * Move the range or its points on specified amount of given units. + */ + void Move(ETextUnit aUnit, int32_t aCount) + { + MoveEnd(aUnit, aCount); + MoveStart(aUnit, aCount); + } + void MoveStart(ETextUnit aUnit, int32_t aCount) + { + MoveInternal(aUnit, aCount, *mStartContainer, mStartOffset, + mEndContainer, mEndOffset); + } + void MoveEnd(ETextUnit aUnit, int32_t aCount) + { MoveInternal(aUnit, aCount, *mEndContainer, mEndOffset); } + + /** + * Move the range points to the closest unit boundaries. + */ + void Normalize(ETextUnit aUnit); + + enum EDirection { + eBackward, + eForward + }; + + /** + * Return range enclosing the found text. + */ + void FindText(const nsAString& aText, EDirection aDirection, + nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const; + + enum EAttr { + eAnimationStyleAttr, + eAnnotationObjectsAttr, + eAnnotationTypesAttr, + eBackgroundColorAttr, + eBulletStyleAttr, + eCapStyleAttr, + eCaretBidiModeAttr, + eCaretPositionAttr, + eCultureAttr, + eFontNameAttr, + eFontSizeAttr, + eFontWeightAttr, + eForegroundColorAttr, + eHorizontalTextAlignmentAttr, + eIndentationFirstLineAttr, + eIndentationLeadingAttr, + eIndentationTrailingAttr, + eIsActiveAttr, + eIsHiddenAttr, + eIsItalicAttr, + eIsReadOnlyAttr, + eIsSubscriptAttr, + eIsSuperscriptAttr, + eLinkAttr, + eMarginBottomAttr, + eMarginLeadingAttr, + eMarginTopAttr, + eMarginTrailingAttr, + eOutlineStylesAttr, + eOverlineColorAttr, + eOverlineStyleAttr, + eSelectionActiveEndAttr, + eStrikethroughColorAttr, + eStrikethroughStyleAttr, + eStyleIdAttr, + eStyleNameAttr, + eTabsAttr, + eTextFlowDirectionsAttr, + eUnderlineColorAttr, + eUnderlineStyleAttr + }; + + /** + * Return range enclosing text having requested attribute. + */ + void FindAttr(EAttr aAttr, nsIVariant* aValue, EDirection aDirection, + TextRange* aFoundRange) const; + + /** + * Add/remove the text range from selection. + */ + void AddToSelection() const; + void RemoveFromSelection() const; + void Select() const; + + /** + * Scroll the text range into view. + */ + enum EHowToAlign { + eAlignToTop, + eAlignToBottom + }; + void ScrollIntoView(EHowToAlign aHow) const; + + /** * Return true if this TextRange object represents an actual range of text. */ bool IsValid() const { return mRoot; } + void SetStartPoint(HyperTextAccessible* aContainer, int32_t aOffset) + { mStartContainer = aContainer; mStartOffset = aOffset; } + void SetEndPoint(HyperTextAccessible* aContainer, int32_t aOffset) + { mStartContainer = aContainer; mStartOffset = aOffset; } + private: TextRange(const TextRange& aRange) MOZ_DELETE; TextRange& operator=(const TextRange& aRange) MOZ_DELETE; friend class HyperTextAccessible; friend class xpcAccessibleTextRange; void Set(HyperTextAccessible* aRoot, - Accessible* aStartContainer, int32_t aStartOffset, - Accessible* aEndContainer, int32_t aEndOffset); + HyperTextAccessible* aStartContainer, int32_t aStartOffset, + HyperTextAccessible* aEndContainer, int32_t aEndOffset); + + /** + * Text() method helper. + * @param aText [in,out] calculated text + * @param aCurrent [in] currently traversed node + * @param aStartIntlOffset [in] start offset if current node is a text node + * @return true if calculation is not finished yet + */ + bool TextInternal(nsAString& aText, Accessible* aCurrent, + uint32_t aStartIntlOffset) const; + + void MoveInternal(ETextUnit aUnit, int32_t aCount, + HyperTextAccessible& aContainer, int32_t aOffset, + HyperTextAccessible* aStopContainer = nullptr, + int32_t aStopOffset = 0); nsRefPtr<HyperTextAccessible> mRoot; - nsRefPtr<Accessible> mStartContainer; - nsRefPtr<Accessible> mEndContainer; + nsRefPtr<HyperTextAccessible> mStartContainer; + nsRefPtr<HyperTextAccessible> mEndContainer; int32_t mStartOffset; int32_t mEndOffset; }; } // namespace a11y } // namespace mozilla
--- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -115,17 +115,17 @@ Accessible::Accessible(nsIContent* aCont mContent(aContent), mDoc(aDoc), mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized), mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0), mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr) { #ifdef NS_DEBUG_X { nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell)); - printf(">>> %p Created Acc - DOM: %p PS: %p", + printf(">>> %p Created Acc - DOM: %p PS: %p", (void*)static_cast<nsIAccessible*>(this), (void*)aNode, (void*)shell.get()); nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); if (content) { printf(" Con: %s@%p", NS_ConvertUTF16toUTF8(content->NodeInfo()->QualifiedName()).get(), (void *)content.get()); nsAutoString buf; @@ -262,17 +262,17 @@ Accessible::GetDescription(nsAString& aD void Accessible::Description(nsString& aDescription) { // There are 4 conditions that make an accessible have no accDescription: // 1. it's a text node; or // 2. It has no DHTML describedby property // 3. it doesn't have an accName; or - // 4. its title attribute already equals to its accName nsAutoString name; + // 4. its title attribute already equals to its accName nsAutoString name; if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT)) return; nsTextEquivUtils:: GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby, aDescription); @@ -545,27 +545,27 @@ NS_IMETHODIMP Accessible::GetIndexInParent(int32_t* aIndexInParent) { NS_ENSURE_ARG_POINTER(aIndexInParent); *aIndexInParent = IndexInParent(); return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE; } -void +void Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut) { nsCOMPtr<nsIStringBundleService> stringBundleService = services::GetStringBundleService(); if (!stringBundleService) return; nsCOMPtr<nsIStringBundle> stringBundle; stringBundleService->CreateBundle( - "chrome://global-platform/locale/accessible.properties", + "chrome://global-platform/locale/accessible.properties", getter_AddRefs(stringBundle)); if (!stringBundle) return; nsXPIDLString xsValue; nsresult rv = stringBundle->GetStringFromName(aKey.get(), getter_Copies(xsValue)); if (NS_SUCCEEDED(rv)) aStringOut.Assign(xsValue); @@ -1099,17 +1099,17 @@ Accessible::XULElmName(DocAccessible* aD if (labeledEl) { labeledEl->GetLabel(aName); } else { nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl = do_QueryInterface(aElm); if (itemEl) { itemEl->GetLabel(aName); } else { nsCOMPtr<nsIDOMXULSelectControlElement> select = do_QueryInterface(aElm); - // Use label if this is not a select control element which + // Use label if this is not a select control element which // uses label attribute to indicate which option is selected if (!select) { nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aElm)); if (xulEl) xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName); } } } @@ -1573,17 +1573,17 @@ Accessible::ApplyARIAState(uint64_t* aSt nsIContent *ancestorContent = mContent; while ((ancestorContent = ancestorContent->GetParent()) != nullptr) { if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled, nsGkAtoms::_true, eCaseMatters)) { // ancestor has aria-disabled property, this is disabled *aState |= states::UNAVAILABLE; break; } - } + } } // special case: A native button element whose role got transformed by ARIA to a toggle button if (IsButton()) aria::MapToState(aria::eARIAPressed, element, aState); if (!mRoleMapEntry) return; @@ -2446,17 +2446,17 @@ Accessible::AppendTextTo(nsAString& aTex } else { aText += kEmbeddedObjectChar; } } void Accessible::Shutdown() { - // Mark the accessible as defunct, invalidate the child count and pointers to + // Mark the accessible as defunct, invalidate the child count and pointers to // other accessibles, also make sure none of its children point to this parent mStateFlags |= eIsDefunct; InvalidateChildren(); if (mParent) mParent->RemoveChild(this); mContent = nullptr; @@ -3053,17 +3053,17 @@ Accessible::TestChildCache(Accessible* a Accessible* child = nullptr; for (int32_t childIdx = 0; childIdx < childCount; childIdx++) { child = mChildren[childIdx]; if (child == aCachedChild) break; } NS_ASSERTION(child == aCachedChild, - "[TestChildCache] cached accessible wasn't found. Wrong accessible tree!"); + "[TestChildCache] cached accessible wasn't found. Wrong accessible tree!"); #endif } // Accessible public bool Accessible::EnsureChildren() { if (IsDefunct()) { @@ -3130,17 +3130,17 @@ Accessible::GetActionRule() if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup)) return eClickAction; // Has registered 'click' event handler. bool isOnclick = nsCoreUtils::HasClickListener(mContent); if (isOnclick) return eClickAction; - + // Get an action based on ARIA role. if (mRoleMapEntry && mRoleMapEntry->actionRule != eNoAction) return mRoleMapEntry->actionRule; // Get an action based on ARIA attribute. if (nsAccUtils::HasDefinedARIAToken(mContent, nsGkAtoms::aria_expanded))
--- a/accessible/src/generic/HyperTextAccessible.cpp +++ b/accessible/src/generic/HyperTextAccessible.cpp @@ -1546,19 +1546,19 @@ HyperTextAccessible::ScrollSubstringToPo } } void HyperTextAccessible::EnclosingRange(a11y::TextRange& aRange) const { if (IsTextField()) { aRange.Set(mDoc, const_cast<HyperTextAccessible*>(this), 0, - const_cast<HyperTextAccessible*>(this), ChildCount()); + const_cast<HyperTextAccessible*>(this), CharacterCount()); } else { - aRange.Set(mDoc, mDoc, 0, mDoc, mDoc->ChildCount()); + aRange.Set(mDoc, mDoc, 0, mDoc, mDoc->CharacterCount()); } } void HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const { NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty"); @@ -1594,26 +1594,56 @@ void HyperTextAccessible::VisibleRanges(nsTArray<a11y::TextRange>* aRanges) const { } void HyperTextAccessible::RangeByChild(Accessible* aChild, a11y::TextRange& aRange) const { - aRange.Set(mDoc, aChild, 0, aChild, aChild->ChildCount()); + HyperTextAccessible* ht = aChild->AsHyperText(); + if (ht) { + aRange.Set(mDoc, ht, 0, ht, ht->CharacterCount()); + return; + } + + Accessible* child = aChild; + Accessible* parent = nullptr; + while ((parent = child->Parent()) && !(ht = parent->AsHyperText())) + child = parent; + + // If no text then return collapsed text range, otherwise return a range + // containing the text enclosed by the given child. + if (ht) { + int32_t childIdx = child->IndexInParent(); + int32_t startOffset = ht->GetChildOffset(childIdx); + int32_t endOffset = child->IsTextLeaf() ? + ht->GetChildOffset(childIdx + 1) : startOffset; + aRange.Set(mDoc, ht, startOffset, ht, endOffset); + } } void HyperTextAccessible::RangeAtPoint(int32_t aX, int32_t aY, a11y::TextRange& aRange) const { Accessible* child = mDoc->ChildAtPoint(aX, aY, eDeepestChild); - if (child) - aRange.Set(mDoc, child, 0, child, child->ChildCount()); + if (!child) + return; + + Accessible* parent = nullptr; + while ((parent = child->Parent()) && !parent->IsHyperText()) + child = parent; + + // Return collapsed text range for the point. + if (parent) { + HyperTextAccessible* ht = parent->AsHyperText(); + int32_t offset = ht->GetChildOffset(child); + aRange.Set(mDoc, ht, offset, ht, offset); + } } //////////////////////////////////////////////////////////////////////////////// // Accessible public // Accessible protected ENameValueFlag HyperTextAccessible::NativeName(nsString& aName)
--- a/accessible/src/xpcom/xpcAccessibleTextRange.cpp +++ b/accessible/src/xpcom/xpcAccessibleTextRange.cpp @@ -4,69 +4,206 @@ * 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 "xpcAccessibleTextRange.h" #include "HyperTextAccessible.h" #include "TextRange.h" + #include "nsIMutableArray.h" + using namespace mozilla; using namespace mozilla::a11y; // nsISupports and cycle collection NS_IMPL_CYCLE_COLLECTION(xpcAccessibleTextRange, mRange.mRoot, mRange.mStartContainer, mRange.mEndContainer) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleTextRange) NS_INTERFACE_MAP_ENTRY(nsIAccessibleTextRange) + NS_INTERFACE_MAP_ENTRY(xpcAccessibleTextRange) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleTextRange) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAccessibleTextRange) NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleTextRange) // nsIAccessibleTextRange NS_IMETHODIMP -xpcAccessibleTextRange::GetStartContainer(nsIAccessible** aAnchor) +xpcAccessibleTextRange::GetStartContainer(nsIAccessibleText** aAnchor) { NS_ENSURE_ARG_POINTER(aAnchor); - NS_IF_ADDREF(*aAnchor = static_cast<nsIAccessible*>(mRange.StartContainer())); + NS_IF_ADDREF(*aAnchor = static_cast<nsIAccessibleText*>(mRange.StartContainer())); return NS_OK; } NS_IMETHODIMP xpcAccessibleTextRange::GetStartOffset(int32_t* aOffset) { NS_ENSURE_ARG_POINTER(aOffset); *aOffset = mRange.StartOffset(); return NS_OK; } NS_IMETHODIMP -xpcAccessibleTextRange::GetEndContainer(nsIAccessible** aAnchor) +xpcAccessibleTextRange::GetEndContainer(nsIAccessibleText** aAnchor) { NS_ENSURE_ARG_POINTER(aAnchor); - NS_IF_ADDREF(*aAnchor = static_cast<nsIAccessible*>(mRange.EndContainer())); + NS_IF_ADDREF(*aAnchor = static_cast<nsIAccessibleText*>(mRange.EndContainer())); return NS_OK; } NS_IMETHODIMP xpcAccessibleTextRange::GetEndOffset(int32_t* aOffset) { NS_ENSURE_ARG_POINTER(aOffset); *aOffset = mRange.EndOffset(); return NS_OK; } NS_IMETHODIMP +xpcAccessibleTextRange::GetContainer(nsIAccessible** aContainer) +{ + NS_ENSURE_ARG_POINTER(aContainer); + NS_IF_ADDREF(*aContainer = static_cast<nsIAccessible*>(mRange.Container())); + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::GetEmbeddedChildren(nsIArray** aList) +{ + nsresult rv = NS_OK; + nsCOMPtr<nsIMutableArray> xpcList = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsTArray<Accessible*> objects; + mRange.EmbeddedChildren(&objects); + + uint32_t len = objects.Length(); + for (uint32_t idx = 0; idx < len; idx++) + xpcList->AppendElement(static_cast<nsIAccessible*>(objects[idx]), false); + + xpcList.forget(aList); + + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::Compare(nsIAccessibleTextRange* aOtherRange, + bool* aResult) +{ + + nsRefPtr<xpcAccessibleTextRange> xpcRange(do_QueryObject(aOtherRange)); + if (!xpcRange || !aResult) + return NS_ERROR_INVALID_ARG; + + *aResult = (mRange == xpcRange->mRange); + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::CompareEndPoints(uint32_t aEndPoint, + nsIAccessibleTextRange* aOtherRange, + uint32_t aOtherRangeEndPoint, + int32_t* aResult) +{ + nsRefPtr<xpcAccessibleTextRange> xpcRange(do_QueryObject(aOtherRange)); + if (!xpcRange || !aResult) + return NS_ERROR_INVALID_ARG; + + TextPoint p = (aEndPoint == EndPoint_Start) ? + mRange.StartPoint() : mRange.EndPoint(); + TextPoint otherPoint = (aOtherRangeEndPoint == EndPoint_Start) ? + xpcRange->mRange.StartPoint() : xpcRange->mRange.EndPoint(); + + if (p == otherPoint) + *aResult = 0; + else + *aResult = p < otherPoint ? -1 : 1; + + return NS_OK; +} + +NS_IMETHODIMP xpcAccessibleTextRange::GetText(nsAString& aText) { nsAutoString text; mRange.Text(text); aText.Assign(text); return NS_OK; } + +NS_IMETHODIMP +xpcAccessibleTextRange::GetBounds(nsIArray** aRectList) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::Move(uint32_t aUnit, int32_t aCount) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::MoveStart(uint32_t aUnit, int32_t aCount) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::MoveEnd(uint32_t aUnit, int32_t aCount) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::Normalize(uint32_t aUnit) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::FindText(const nsAString& aText, bool aIsBackward, + bool aIsIgnoreCase, + nsIAccessibleTextRange** aRange) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::FindAttr(uint32_t aAttr, nsIVariant* aVal, + bool aIsBackward, + nsIAccessibleTextRange** aRange) +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::AddToSelection() +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::RemoveFromSelection() +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::Select() +{ + return NS_OK; +} + +NS_IMETHODIMP +xpcAccessibleTextRange::ScrollIntoView(uint32_t aHow) +{ + return NS_OK; +}
--- a/accessible/src/xpcom/xpcAccessibleTextRange.h +++ b/accessible/src/xpcom/xpcAccessibleTextRange.h @@ -13,36 +13,69 @@ #include "mozilla/Move.h" #include "nsCycleCollectionParticipant.h" namespace mozilla { namespace a11y { class TextRange; +#define NS_ACCESSIBLETEXTRANGE_IMPL_IID \ +{ /* 133c8bf4-4913-4355-bd50-426bd1d6e1ad */ \ + 0xb17652d9, \ + 0x4f54, \ + 0x4c56, \ + { 0xbb, 0x62, 0x6d, 0x5b, 0xf1, 0xef, 0x91, 0x0c } \ +} + class xpcAccessibleTextRange MOZ_FINAL : public nsIAccessibleTextRange { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(xpcAccessibleTextRange) - NS_IMETHOD GetStartContainer(nsIAccessible** aAnchor) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD GetStartContainer(nsIAccessibleText** aAnchor) MOZ_FINAL MOZ_OVERRIDE; NS_IMETHOD GetStartOffset(int32_t* aOffset) MOZ_FINAL MOZ_OVERRIDE; - NS_IMETHOD GetEndContainer(nsIAccessible** aAnchor) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD GetEndContainer(nsIAccessibleText** aAnchor) MOZ_FINAL MOZ_OVERRIDE; NS_IMETHOD GetEndOffset(int32_t* aOffset) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD GetContainer(nsIAccessible** aContainer) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD GetEmbeddedChildren(nsIArray** aList) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD Compare(nsIAccessibleTextRange* aOtherRange, bool* aResult) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD CompareEndPoints(uint32_t aEndPoint, + nsIAccessibleTextRange* aOtherRange, + uint32_t aOtherRangeEndPoint, + int32_t* aResult) MOZ_FINAL MOZ_OVERRIDE; NS_IMETHOD GetText(nsAString& aText) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD GetBounds(nsIArray** aRectList) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD Move(uint32_t aUnit, int32_t aCount) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD MoveStart(uint32_t aUnit, int32_t aCount) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD MoveEnd(uint32_t aUnit, int32_t aCount) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD Normalize(uint32_t aUnit) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD FindText(const nsAString& aText, bool aIsBackward, bool aIsIgnoreCase, + nsIAccessibleTextRange** aRange) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD FindAttr(uint32_t aAttr, nsIVariant* aVal, bool aIsBackward, + nsIAccessibleTextRange** aRange) MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD AddToSelection() MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD RemoveFromSelection() MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD Select() MOZ_FINAL MOZ_OVERRIDE; + NS_IMETHOD ScrollIntoView(uint32_t aHow) MOZ_FINAL MOZ_OVERRIDE; + + NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCESSIBLETEXTRANGE_IMPL_IID) private: xpcAccessibleTextRange(TextRange&& aRange) : mRange(Forward<TextRange>(aRange)) {} xpcAccessibleTextRange() {} friend class xpcAccessibleHyperText; xpcAccessibleTextRange(const xpcAccessibleTextRange&) MOZ_DELETE; xpcAccessibleTextRange& operator =(const xpcAccessibleTextRange&) MOZ_DELETE; TextRange mRange; }; +NS_DEFINE_STATIC_IID_ACCESSOR(xpcAccessibleTextRange, + NS_ACCESSIBLETEXTRANGE_IMPL_IID) + } // namespace a11y } // namespace mozilla #endif
--- a/accessible/tests/mochitest/common.js +++ b/accessible/tests/mochitest/common.js @@ -14,16 +14,17 @@ const nsIAccessibleVirtualCursorChangeEv Components.interfaces.nsIAccessibleVirtualCursorChangeEvent; const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates; const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole; const nsIAccessibleScrollType = Components.interfaces.nsIAccessibleScrollType; const nsIAccessibleCoordinateType = Components.interfaces.nsIAccessibleCoordinateType; const nsIAccessibleRelation = Components.interfaces.nsIAccessibleRelation; +const nsIAccessibleTextRange = Components.interfaces.nsIAccessibleTextRange; const nsIAccessible = Components.interfaces.nsIAccessible; const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument; const nsIAccessibleApplication = Components.interfaces.nsIAccessibleApplication; const nsIAccessibleText = Components.interfaces.nsIAccessibleText; const nsIAccessibleEditableText = Components.interfaces.nsIAccessibleEditableText; @@ -429,17 +430,17 @@ function testAccessibleTree(aAccOrElmOrI if (prevOffset != -1) { var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount; var attrs = accTree[prop][prevOffset]; testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true); } break; - } + } default: if (prop.indexOf("todo_") == 0) todo(false, msg); else if (prop != "children") is(acc[prop], accTree[prop], msg); } }
--- a/accessible/tests/mochitest/text.js +++ b/accessible/tests/mochitest/text.js @@ -5,16 +5,19 @@ const BOUNDARY_CHAR = nsIAccessibleText. const BOUNDARY_WORD_START = nsIAccessibleText.BOUNDARY_WORD_START; const BOUNDARY_WORD_END = nsIAccessibleText.BOUNDARY_WORD_END; const BOUNDARY_LINE_START = nsIAccessibleText.BOUNDARY_LINE_START; const BOUNDARY_LINE_END = nsIAccessibleText.BOUNDARY_LINE_END; const kTextEndOffset = nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT; const kCaretOffset = nsIAccessibleText.TEXT_OFFSET_CARET; +const EndPoint_Start = nsIAccessibleTextRange.EndPoint_Start; +const EndPoint_End = nsIAccessibleTextRange.EndPoint_End; + const kTodo = 1; // a test is expected to fail const kOk = 2; // a test doesn't fail /** * Test characterCount for the given array of accessibles. * * @param aCount [in] the expected character count * @param aIDs [in] array of accessible identifiers to test @@ -388,18 +391,18 @@ function testTextAddSelection(aID, aStar */ function testTextRemoveSelection(aID, aSelectionIndex, aSelectionsCount) { var acc = getAccessible(aID, [nsIAccessibleText]); var text = acc.getText(0, -1); acc.removeSelection(aSelectionIndex); - ok(acc.selectionCount, aSelectionsCount, - text + ": failed to remove selection at index '" + + ok(acc.selectionCount, aSelectionsCount, + text + ": failed to remove selection at index '" + aSelectionIndex + "': selectionCount after"); } /** * Test setSelectionBounds method. * * @param aID [in] Id, DOM node, or acc obj * @param aStartOffset [in] new start offset for the selection @@ -411,18 +414,18 @@ function testTextRemoveSelection(aID, aS function testTextSetSelection(aID, aStartOffset, aEndOffset, aSelectionIndex, aSelectionsCount) { var acc = getAccessible(aID, [nsIAccessibleText]); var text = acc.getText(0, -1); acc.setSelectionBounds(aSelectionIndex, aStartOffset, aEndOffset); - is(acc.selectionCount, aSelectionsCount, - text + ": failed to set selection at index '" + + is(acc.selectionCount, aSelectionsCount, + text + ": failed to set selection at index '" + aSelectionIndex + "': selectionCount after"); } /** * Test selectionCount method. * * @param aID [in] Id, DOM node, or acc obj * @param aCount [in] expected selection count @@ -452,27 +455,46 @@ function testTextGetSelection(aID, aStar acc.getSelectionBounds(aSelectionIndex, startObj, endObj); is(startObj.value, aStartOffset, text + ": wrong start offset for index '" + aSelectionIndex + "'"); is(endObj.value, aEndOffset, text + ": wrong end offset for index '" + aSelectionIndex + "'"); } -function testTextRange(aRange, aStartContainer, aStartOffset, - aEndContainer, aEndOffset) +function testTextRange(aRange, aRangeDescr, aStartContainer, aStartOffset, + aEndContainer, aEndOffset, aText, + aCommonContainer, aChildren) { - is(aRange.startContainer, getAccessible(aStartContainer), - "Wrong start container"); + isObject(aRange.startContainer, getAccessible(aStartContainer), + "Wrong start container of " + aRangeDescr); is(aRange.startOffset, aStartOffset, - "Wrong start offset"); - is(aRange.endContainer, getAccessible(aEndContainer), - "Wrong end container"); + "Wrong start offset of " + aRangeDescr); + isObject(aRange.endContainer, getAccessible(aEndContainer), + "Wrong end container of " + aRangeDescr); is(aRange.endOffset, aEndOffset, - "Wrong end offset"); + "Wrong end offset of " + aRangeDescr); + + is(aRange.text, aText, "Wrong text of " + aRangeDescr); + + var children = aRange.embeddedChildren; + is(children ? children.length : 0, aChildren ? aChildren.length : 0, + "Wrong embedded children count of " + aRangeDescr); + + isObject(aRange.container, getAccessible(aCommonContainer), + "Wrong container of " + aRangeDescr); + + if (aChildren) { + for (var i = 0; i < aChildren.length; i++) { + var expectedChild = getAccessible(aChildren[i]); + var actualChild = children.queryElementAt(i, nsIAccessible); + isObject(actualChild, expectedChild, + "Wrong child at index '" + i + "' of " + aRangeDescr); + } + } } //////////////////////////////////////////////////////////////////////////////// // Private function testTextSuperHelper(aFuncName, aArgs) { // List of tests.
--- a/accessible/tests/mochitest/textrange/test_general.html +++ b/accessible/tests/mochitest/textrange/test_general.html @@ -6,29 +6,85 @@ href="chrome://mochikit/content/tests/SimpleTest/test.css" /> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="../common.js"></script> <script type="application/javascript" src="../text.js"></script> + <script type="application/javascript" + src="../layout.js"></script> <script type="application/javascript"> function doTest() { + // enclosingRange var input = getAccessible("input", [ nsIAccessibleText ]); - testTextRange(input.enclosingRange, input, 0, input, 1); + testTextRange(input.enclosingRange, "enclosing range for 'input'", + input, 0, input, 5, "hello", input); var ta = getAccessible("textarea", [ nsIAccessibleText ]); - testTextRange(ta.enclosingRange, ta, 0, ta, 1); + testTextRange(ta.enclosingRange, "enclosing range for 'textarea'", + ta, 0, ta, 5, "hello", textarea); + + var iframeDocNode = getNode("iframe").contentDocument; + var iframeDoc = getAccessible(iframeDocNode, [ nsIAccessibleText ]); + testTextRange(iframeDoc.enclosingRange, "enclosing range for iframe doc", + iframeDoc, 0, iframeDoc, 1, "hello", + iframeDoc, [ getNode("p", iframeDocNode) ]); + + // getRangeByChild + var docacc = getAccessible(document, [ nsIAccessibleText ]); + var p1 = getAccessible("p1"); + var p1Range = docacc.getRangeByChild(p1); + testTextRange(p1Range, "range by 'p1' child", + p1, 0, "p1", 11, "text text", + p1, ["p1_img"]); + + testTextRange(docacc.getRangeByChild(getAccessible("p1_img")), + "range by 'p1_img' child", + "p1", 5, "p1", 5, "", + "p1", ["p1_img"]); + + var p2 = getAccessible("p2"); + var p2Range = docacc.getRangeByChild(p2); + testTextRange(p2Range, "range by 'p2' child", + p2, 0, "p2", 11, "text link text", + p2, ["p2_a"]); - var iframeDoc = getAccessible(getNode("iframe").contentDocument, - [ nsIAccessibleText ]); - testTextRange(iframeDoc.enclosingRange, iframeDoc, 0, iframeDoc, 1); + testTextRange(docacc.getRangeByChild(getAccessible("p2_a")), + "range by 'p2_a' child", + "p2_a", 0, "p2_a", 5, "link", + "p2_a", ["p2_img"]); + + // getRangeAtPoint + getNode("p2_a").scrollIntoView(true); + var [x, y] = getPos("p2_a"); + testTextRange(docacc.getRangeAtPoint(x + 1, y + 1), + "range at 'p2_a' top-left edge", + "p2_a", 0, "p2_a", 0, "", + "p2_a"); + + // TextRange::compare + ok(input.enclosingRange.compare(input.enclosingRange), + "input enclosing ranges should be equal"); + + ok(!input.enclosingRange.compare(ta.enclosingRange), + "input and textarea enclosing ranges can't be equal"); + + // TextRange::compareEndPoints + var res = p1Range.compareEndPoints(EndPoint_End, p2Range, EndPoint_Start); + is(res, -1, "p1 range must be lesser with p2 range"); + + res = p2Range.compareEndPoints(EndPoint_Start, p1Range, EndPoint_End); + is(res, 1, "p2 range must be greater with p1 range"); + + res = p1Range.compareEndPoints(EndPoint_Start, p1Range, EndPoint_Start); + is(res, 0, "p1 range must be equal with p1 range"); SimpleTest.finish(); } SimpleTest.waitForExplicitFinish(); addA11yLoadEvent(doTest); </script> </head> @@ -39,12 +95,14 @@ href="https://bugzilla.mozilla.org/show_bug.cgi?id=975065">Bug 975065</a> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"> </pre> <input id="input" value="hello"> <textarea id="textarea">hello</textarea> - <iframe id="iframe" src="data:text/html,<p>hello</p>"></iframe> + <iframe id="iframe" src="data:text/html,<html><body><p id='p'>hello</p></body></html>"></iframe> + <p id="p1">text <img id="p1_img", src="../moz.png"> text</p> + <p id="p2">text <a id="p2_a" href="www">link<img id="p2_img", src="../moz.png"></a> text</p> </body> </html>