From 1786366bc424f04e30461a81ca5f7efa96eed28c Mon Sep 17 00:00:00 2001 From: James Teh Date: Sun, 21 May 2023 10:15:05 +0000 Subject: [PATCH] Bug 1821951 part 1: Remove HyperTextAccessible methods that are no longer needed now that the cache is always used. r=morgan,taskgraph-reviewers,bhearsum Differential Revision: https://phabricator.services.mozilla.com/D177744 --- .../basetypes/HyperTextAccessibleBase.h | 52 +- accessible/generic/HyperTextAccessible-inl.h | 11 - accessible/generic/HyperTextAccessible.cpp | 1222 ----------------- accessible/generic/HyperTextAccessible.h | 129 -- accessible/mac/HyperTextAccessibleWrap.h | 1 + 5 files changed, 27 insertions(+), 1388 deletions(-) diff --git a/accessible/basetypes/HyperTextAccessibleBase.h b/accessible/basetypes/HyperTextAccessibleBase.h index a49bcdd693f0..8d1d157b89e5 100644 --- a/accessible/basetypes/HyperTextAccessibleBase.h +++ b/accessible/basetypes/HyperTextAccessibleBase.h @@ -8,6 +8,7 @@ #include "AccAttributes.h" #include "nsIAccessibleText.h" +#include "nsIAccessibleTypes.h" namespace mozilla::a11y { class Accessible; @@ -75,7 +76,7 @@ class HyperTextAccessibleBase { /** * Return character count within the hypertext accessible. */ - virtual uint32_t CharacterCount() const; + uint32_t CharacterCount() const; /** * Get/set caret offset, if no caret then -1. @@ -97,8 +98,8 @@ class HyperTextAccessibleBase { /** * Return text between given offsets. */ - virtual void TextSubstring(int32_t aStartOffset, int32_t aEndOffset, - nsAString& aText) const; + void TextSubstring(int32_t aStartOffset, int32_t aEndOffset, + nsAString& aText) const; /** * Get a character at the given offset (don't support magic offsets). @@ -106,7 +107,7 @@ class HyperTextAccessibleBase { bool CharAt(int32_t aOffset, nsAString& aChar, int32_t* aStartOffset = nullptr, int32_t* aEndOffset = nullptr); - virtual char16_t CharAt(int32_t aOffset) { + char16_t CharAt(int32_t aOffset) { nsAutoString charAtOffset; CharAt(aOffset, charAtOffset); return charAtOffset.CharAt(0); @@ -116,15 +117,16 @@ class HyperTextAccessibleBase { * Return a rect (in dev pixels) for character at given offset relative * given coordinate system. */ - virtual LayoutDeviceIntRect CharBounds(int32_t aOffset, uint32_t aCoordType); + LayoutDeviceIntRect CharBounds(int32_t aOffset, uint32_t aCoordType); /** * Return a rect (in dev pixels) of the given text range relative given * coordinate system. */ - virtual LayoutDeviceIntRect TextBounds(int32_t aStartOffset, - int32_t aEndOffset, - uint32_t aCoordType); + LayoutDeviceIntRect TextBounds( + int32_t aStartOffset, int32_t aEndOffset, + uint32_t aCoordType = + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE); /** * Return the offset of the char that contains the given coordinates. @@ -143,18 +145,15 @@ class HyperTextAccessibleBase { * Return text before/at/after the given offset corresponding to * the boundary type. */ - virtual void TextBeforeOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, int32_t* aEndOffset, - nsAString& aText); - virtual void TextAtOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, int32_t* aEndOffset, - nsAString& aText); - virtual void TextAfterOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, int32_t* aEndOffset, - nsAString& aText); + void TextBeforeOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType, + int32_t* aStartOffset, int32_t* aEndOffset, + nsAString& aText); + void TextAtOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType, + int32_t* aStartOffset, int32_t* aEndOffset, + nsAString& aText); + void TextAfterOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType, + int32_t* aStartOffset, int32_t* aEndOffset, + nsAString& aText); /** * Return true if the given offset/range is valid. @@ -188,10 +187,10 @@ class HyperTextAccessibleBase { /** * Return text attributes for the given text range. */ - virtual already_AddRefed TextAttributes(bool aIncludeDefAttrs, - int32_t aOffset, - int32_t* aStartOffset, - int32_t* aEndOffset); + already_AddRefed TextAttributes(bool aIncludeDefAttrs, + int32_t aOffset, + int32_t* aStartOffset, + int32_t* aEndOffset); /** * Return text attributes applied to the accessible. @@ -242,8 +241,9 @@ class HyperTextAccessibleBase { /** * Scroll the given text range into view. */ - MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void ScrollSubstringTo( - int32_t aStartOffset, int32_t aEndOffset, uint32_t aScrollType); + MOZ_CAN_RUN_SCRIPT_BOUNDARY void ScrollSubstringTo(int32_t aStartOffset, + int32_t aEndOffset, + uint32_t aScrollType); protected: virtual const Accessible* Acc() const = 0; diff --git a/accessible/generic/HyperTextAccessible-inl.h b/accessible/generic/HyperTextAccessible-inl.h index ba7d441c56f3..64a56212ad16 100644 --- a/accessible/generic/HyperTextAccessible-inl.h +++ b/accessible/generic/HyperTextAccessible-inl.h @@ -89,17 +89,6 @@ inline void HyperTextAccessible::PasteText(int32_t aPosition) { } } -inline uint32_t HyperTextAccessible::AdjustCaretOffset(uint32_t aOffset) const { - // It is the same character offset when the caret is visually at the very - // end of a line or the start of a new line (soft line break). Getting text - // at the line should provide the line with the visual caret, otherwise - // screen readers will announce the wrong line as the user presses up or - // down arrow and land at the end of a line. - if (aOffset > 0 && IsCaretAtEndOfLine()) return aOffset - 1; - - return aOffset; -} - inline bool HyperTextAccessible::IsCaretAtEndOfLine() const { RefPtr frameSelection = FrameSelection(); return frameSelection && frameSelection->GetHint() == CARET_ASSOCIATE_BEFORE; diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp index e8671fbfb35c..ed4b0203e23e 100644 --- a/accessible/generic/HyperTextAccessible.cpp +++ b/accessible/generic/HyperTextAccessible.cpp @@ -53,117 +53,6 @@ using namespace mozilla; using namespace mozilla::a11y; -/** - * This class is used in HyperTextAccessible to search for paragraph - * boundaries. - */ -class ParagraphBoundaryRule : public PivotRule { - public: - explicit ParagraphBoundaryRule(LocalAccessible* aAnchor, - uint32_t aAnchorTextoffset, - nsDirection aDirection, - bool aSkipAnchorSubtree = false) - : mAnchor(aAnchor), - mAnchorTextOffset(aAnchorTextoffset), - mDirection(aDirection), - mSkipAnchorSubtree(aSkipAnchorSubtree), - mLastMatchTextOffset(0) {} - - virtual uint16_t Match(Accessible* aAcc) override { - MOZ_ASSERT(aAcc && aAcc->IsLocal()); - LocalAccessible* acc = aAcc->AsLocal(); - if (acc->IsOuterDoc()) { - // The child document might be remote and we can't (and don't want to) - // handle remote documents. Also, iframes are inline anyway and thus - // can't be paragraph boundaries. Therefore, skip this unconditionally. - return nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE; - } - - uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE; - if (mSkipAnchorSubtree && acc == mAnchor) { - result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE; - } - - // First, deal with the case that we encountered a line break, for example, - // a br in a paragraph. - if (acc->Role() == roles::WHITESPACE) { - result |= nsIAccessibleTraversalRule::FILTER_MATCH; - return result; - } - - // Now, deal with the case that we encounter a new block level accessible. - // This also means a new paragraph boundary start. - nsIFrame* frame = acc->GetFrame(); - if (frame && frame->IsBlockFrame() && - acc->Role() != roles::LISTITEM_MARKER) { - result |= nsIAccessibleTraversalRule::FILTER_MATCH; - return result; - } - - // A text leaf can contain a line break if it's pre-formatted text. - if (acc->IsTextLeaf()) { - nsAutoString name; - acc->Name(name); - int32_t offset; - if (mDirection == eDirPrevious) { - if (acc == mAnchor && mAnchorTextOffset == 0) { - // We're already at the start of this node, so there can be no line - // break before. - return result; - } - // If we began on a line break, we don't want to match it, so search - // from 1 before our anchor offset. - offset = - name.RFindChar('\n', acc == mAnchor ? mAnchorTextOffset - 1 : -1); - } else { - offset = name.FindChar('\n', acc == mAnchor ? mAnchorTextOffset : 0); - } - if (offset != -1) { - // Line ebreak! - mLastMatchTextOffset = offset; - result |= nsIAccessibleTraversalRule::FILTER_MATCH; - } - } - - return result; - } - - // This is only valid if the last match was a text leaf. It returns the - // offset of the line break character in that text leaf. - uint32_t GetLastMatchTextOffset() { return mLastMatchTextOffset; } - - private: - LocalAccessible* mAnchor; - uint32_t mAnchorTextOffset; - nsDirection mDirection; - bool mSkipAnchorSubtree; - uint32_t mLastMatchTextOffset; -}; - -/** - * This class is used in HyperTextAccessible::FindParagraphStartOffset to - * search forward exactly one step from a match found by the above. - * It should only be initialized with a boundary, and it will skip that - * boundary's sub tree if it is a block element boundary. - */ -class SkipParagraphBoundaryRule : public PivotRule { - public: - explicit SkipParagraphBoundaryRule(Accessible* aBoundary) - : mBoundary(aBoundary) {} - - virtual uint16_t Match(Accessible* aAcc) override { - MOZ_ASSERT(aAcc && aAcc->IsLocal()); - // If matching the boundary, skip its sub tree. - if (aAcc == mBoundary) { - return nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE; - } - return nsIAccessibleTraversalRule::FILTER_MATCH; - } - - private: - Accessible* mBoundary; -}; - //////////////////////////////////////////////////////////////////////////////// // HyperTextAccessible //////////////////////////////////////////////////////////////////////////////// @@ -212,73 +101,6 @@ bool HyperTextAccessible::IsEditable() const { return mContent->AsElement()->State().HasState(dom::ElementState::READWRITE); } -LayoutDeviceIntRect HyperTextAccessible::GetBoundsInFrame( - nsIFrame* aFrame, uint32_t aStartRenderedOffset, - uint32_t aEndRenderedOffset) { - nsPresContext* presContext = mDoc->PresContext(); - if (!aFrame->IsTextFrame()) { - return LayoutDeviceIntRect::FromAppUnitsToNearest( - aFrame->GetScreenRectInAppUnits(), presContext->AppUnitsPerDevPixel()); - } - - // Substring must be entirely within the same text node. - int32_t startContentOffset, endContentOffset; - nsresult rv = RenderedToContentOffset(aFrame, aStartRenderedOffset, - &startContentOffset); - NS_ENSURE_SUCCESS(rv, LayoutDeviceIntRect()); - rv = RenderedToContentOffset(aFrame, aEndRenderedOffset, &endContentOffset); - NS_ENSURE_SUCCESS(rv, LayoutDeviceIntRect()); - - nsIFrame* frame; - int32_t startContentOffsetInFrame; - // Get the right frame continuation -- not really a child, but a sibling of - // the primary frame passed in - rv = aFrame->GetChildFrameContainingOffset( - startContentOffset, false, &startContentOffsetInFrame, &frame); - NS_ENSURE_SUCCESS(rv, LayoutDeviceIntRect()); - - nsRect screenRect; - while (frame && startContentOffset < endContentOffset) { - // Start with this frame's screen rect, which we will shrink based on - // the substring we care about within it. We will then add that frame to - // the total screenRect we are returning. - nsRect frameScreenRect = frame->GetScreenRectInAppUnits(); - - // Get the length of the substring in this frame that we want the bounds for - auto [startFrameTextOffset, endFrameTextOffset] = frame->GetOffsets(); - int32_t frameTotalTextLength = endFrameTextOffset - startFrameTextOffset; - int32_t seekLength = endContentOffset - startContentOffset; - int32_t frameSubStringLength = - std::min(frameTotalTextLength - startContentOffsetInFrame, seekLength); - - // Add the point where the string starts to the frameScreenRect - nsPoint frameTextStartPoint; - rv = frame->GetPointFromOffset(startContentOffset, &frameTextStartPoint); - NS_ENSURE_SUCCESS(rv, LayoutDeviceIntRect()); - - // Use the point for the end offset to calculate the width - nsPoint frameTextEndPoint; - rv = frame->GetPointFromOffset(startContentOffset + frameSubStringLength, - &frameTextEndPoint); - NS_ENSURE_SUCCESS(rv, LayoutDeviceIntRect()); - - frameScreenRect.SetRectX( - frameScreenRect.X() + - std::min(frameTextStartPoint.x, frameTextEndPoint.x), - mozilla::Abs(frameTextStartPoint.x - frameTextEndPoint.x)); - - screenRect.UnionRect(frameScreenRect, screenRect); - - // Get ready to loop back for next frame continuation - startContentOffset += frameSubStringLength; - startContentOffsetInFrame = 0; - frame = frame->GetNextContinuation(); - } - - return LayoutDeviceIntRect::FromAppUnitsToNearest( - screenRect, presContext->AppUnitsPerDevPixel()); -} - uint32_t HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset, bool aIsEndOffset) const { @@ -451,805 +273,6 @@ DOMPoint HyperTextAccessible::OffsetToDOMPoint(int32_t aOffset) const { : DOMPoint(); } -uint32_t HyperTextAccessible::FindOffset(uint32_t aOffset, - nsDirection aDirection, - nsSelectionAmount aAmount, - EWordMovementType aWordMovementType) { - NS_ASSERTION(aDirection == eDirPrevious || aAmount != eSelectBeginLine, - "eSelectBeginLine should only be used with eDirPrevious"); - - // Find a leaf accessible frame to start with. PeekOffset wants this. - HyperTextAccessible* text = this; - LocalAccessible* child = nullptr; - int32_t innerOffset = aOffset; - - do { - int32_t childIdx = text->GetChildIndexAtOffset(innerOffset); - - // We can have an empty text leaf as our only child. Since empty text - // leaves are not accessible we then have no children, but 0 is a valid - // innerOffset. - if (childIdx == -1) { - NS_ASSERTION(innerOffset == 0 && !text->ChildCount(), "No childIdx?"); - return DOMPointToOffset(text->GetNode(), 0, aDirection == eDirNext); - } - - child = text->LocalChildAt(childIdx); - - // HTML list items may need special processing because PeekOffset doesn't - // work with list bullets. - if (text->IsHTMLListItem()) { - HTMLLIAccessible* li = text->AsHTMLListItem(); - if (child == li->Bullet()) { - // XXX: the logic is broken for multichar bullets in moving by - // char/cluster/word cases. - if (text != this) { - return aDirection == eDirPrevious ? TransformOffset(text, 0, false) - : TransformOffset(text, 1, true); - } - if (aDirection == eDirPrevious) return 0; - - uint32_t nextOffset = GetChildOffset(1); - if (nextOffset == 0) return 0; - - switch (aAmount) { - case eSelectLine: - case eSelectEndLine: - // Ask a text leaf next (if not empty) to the bullet for an offset - // since list item may be multiline. - return nextOffset < CharacterCount() - ? FindOffset(nextOffset, aDirection, aAmount, - aWordMovementType) - : nextOffset; - - default: - return nextOffset; - } - } - } - - innerOffset -= text->GetChildOffset(childIdx); - - text = child->AsHyperText(); - } while (text); - - nsIFrame* childFrame = child->GetFrame(); - if (!childFrame) { - NS_ERROR("No child frame"); - return 0; - } - - int32_t innerContentOffset = innerOffset; - if (child->IsTextLeaf()) { - NS_ASSERTION(childFrame->IsTextFrame(), "Wrong frame!"); - RenderedToContentOffset(childFrame, innerOffset, &innerContentOffset); - } - - nsIFrame* frameAtOffset = childFrame; - int32_t unusedOffsetInFrame = 0; - childFrame->GetChildFrameContainingOffset( - innerContentOffset, true, &unusedOffsetInFrame, &frameAtOffset); - - PeekOffsetStruct pos( - aAmount, aDirection, innerContentOffset, nsPoint(0, 0), - {PeekOffsetOption::JumpLines, PeekOffsetOption::IsKeyboardSelect, - PeekOffsetOption::PreserveSpaces, - PeekOffsetOption::AllowContentInDifferentNativeAnonymousSubtreeRoot}, - aWordMovementType); - nsresult rv = frameAtOffset->PeekOffset(&pos); - - // PeekOffset fails on last/first lines of the text in certain cases. - bool fallBackToSelectEndLine = false; - if (NS_FAILED(rv) && aAmount == eSelectLine) { - fallBackToSelectEndLine = aDirection == eDirNext; - pos.mAmount = fallBackToSelectEndLine ? eSelectEndLine : eSelectBeginLine; - frameAtOffset->PeekOffset(&pos); - } - if (!pos.mResultContent) { - NS_ERROR("No result content!"); - return 0; - } - - // Turn the resulting DOM point into an offset. - uint32_t hyperTextOffset = DOMPointToOffset( - pos.mResultContent, pos.mContentOffset, aDirection == eDirNext); - - if (fallBackToSelectEndLine && IsLineEndCharAt(hyperTextOffset)) { - // We used eSelectEndLine, but the caller requested eSelectLine. - // If there's a '\n' at the end of the line, eSelectEndLine will stop on - // it rather than after it. This is not what we want, since the caller - // wants the next line, not the same line. - ++hyperTextOffset; - } - - if (aDirection == eDirPrevious) { - // If we reached the end during search, this means we didn't find the DOM - // point and we're actually at the start of the paragraph - if (hyperTextOffset == CharacterCount()) return 0; - - // PeekOffset stops right before bullet so return 0 to workaround it. - if (IsHTMLListItem() && aAmount == eSelectBeginLine && - hyperTextOffset > 0) { - LocalAccessible* prevOffsetChild = GetChildAtOffset(hyperTextOffset - 1); - if (prevOffsetChild == AsHTMLListItem()->Bullet()) return 0; - } - } - - return hyperTextOffset; -} - -uint32_t HyperTextAccessible::FindWordBoundary( - uint32_t aOffset, nsDirection aDirection, - EWordMovementType aWordMovementType) { - uint32_t orig = - FindOffset(aOffset, aDirection, eSelectWord, aWordMovementType); - if (aWordMovementType != eStartWord) { - return orig; - } - if (aDirection == eDirPrevious) { - // When layout.word_select.stop_at_punctuation is true (the default), - // for a word beginning with punctuation, layout treats the punctuation - // as the start of the word when moving next. However, when moving - // previous, layout stops *after* the punctuation. We want to be - // consistent regardless of movement direction and always treat punctuation - // as the start of a word. - if (!StaticPrefs::layout_word_select_stop_at_punctuation()) { - return orig; - } - // Case 1: Example: "a @" - // If aOffset is 2 or 3, orig will be 0, but it should be 2. That is, - // previous word moved back too far. - LocalAccessible* child = GetChildAtOffset(orig); - if (child && child->IsHyperText()) { - // For a multi-word embedded object, previous word correctly goes back - // to the start of the word (the embedded object). Next word (below) - // incorrectly stops after the embedded object in this case, so return - // the already correct result. - // Example: "a x y b", where "x y" is an embedded link - // If aOffset is 4, orig will be 2, which is correct. - // If we get the next word (below), we'll end up returning 3 instead. - return orig; - } - uint32_t next = FindOffset(orig, eDirNext, eSelectWord, eStartWord); - if (next < aOffset) { - // Next word stopped on punctuation. - return next; - } - // case 2: example: "a @@b" - // If aOffset is 2, 3 or 4, orig will be 4, but it should be 2. That is, - // previous word didn't go back far enough. - if (orig == 0) { - return orig; - } - // Walk backwards by offset, getting the next word. - // In the loop, o is unsigned, so o >= 0 will always be true and won't - // prevent us from decrementing at 0. Instead, we check that o doesn't - // wrap around. - for (uint32_t o = orig - 1; o < orig; --o) { - next = FindOffset(o, eDirNext, eSelectWord, eStartWord); - if (next == orig) { - // Next word and previous word were consistent. This - // punctuation problem isn't applicable here. - break; - } - if (next < orig) { - // Next word stopped on punctuation. - return next; - } - } - } else { - // When layout.word_select.stop_at_punctuation is true (the default), - // when positioned on punctuation in the middle of a word, next word skips - // the rest of the word. However, when positioned before the punctuation, - // next word moves just after the punctuation. We want to be consistent - // regardless of starting position and always stop just after the - // punctuation. - // Next word can move too far when positioned on white space too. - // Example: "a b@c" - // If aOffset is 3, orig will be 5, but it should be 4. That is, next word - // moved too far. - if (aOffset == 0) { - return orig; - } - uint32_t prev = FindOffset(orig, eDirPrevious, eSelectWord, eStartWord); - if (prev <= aOffset) { - // orig definitely isn't too far forward. - return orig; - } - // Walk backwards by offset, getting the next word. - // In the loop, o is unsigned, so o >= 0 will always be true and won't - // prevent us from decrementing at 0. Instead, we check that o doesn't - // wrap around. - for (uint32_t o = aOffset - 1; o < aOffset; --o) { - uint32_t next = FindOffset(o, eDirNext, eSelectWord, eStartWord); - if (next > aOffset && next < orig) { - return next; - } - if (next <= aOffset) { - break; - } - } - } - return orig; -} - -uint32_t HyperTextAccessible::FindLineBoundary( - uint32_t aOffset, EWhichLineBoundary aWhichLineBoundary) { - // Note: empty last line doesn't have own frame (a previous line contains '\n' - // character instead) thus when it makes a difference we need to process this - // case separately (otherwise operations are performed on previous line). - switch (aWhichLineBoundary) { - case ePrevLineBegin: { - // Fetch a previous line and move to its start (as arrow up and home keys - // were pressed). - if (IsEmptyLastLineOffset(aOffset)) { - return FindOffset(aOffset, eDirPrevious, eSelectBeginLine); - } - - uint32_t tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectLine); - return FindOffset(tmpOffset, eDirPrevious, eSelectBeginLine); - } - - case ePrevLineEnd: { - if (IsEmptyLastLineOffset(aOffset)) return aOffset - 1; - - // If offset is at first line then return 0 (first line start). - uint32_t tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectBeginLine); - if (tmpOffset == 0) return 0; - - // Otherwise move to end of previous line (as arrow up and end keys were - // pressed). - tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectLine); - return FindOffset(tmpOffset, eDirNext, eSelectEndLine); - } - - case eThisLineBegin: { - if (IsEmptyLastLineOffset(aOffset)) return aOffset; - - // Move to begin of the current line (as home key was pressed). - uint32_t thisLineBeginOffset = - FindOffset(aOffset, eDirPrevious, eSelectBeginLine); - if (IsCharAt(thisLineBeginOffset, kEmbeddedObjectChar)) { - // We landed on an embedded character, don't mess with possible embedded - // line breaks, and assume the offset is correct. - return thisLineBeginOffset; - } - - // Sometimes, there is the possibility layout returned an - // offset smaller than it should. Sanity-check by moving to the end of the - // previous line and see if that has a greater offset. - uint32_t tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectLine); - tmpOffset = FindOffset(tmpOffset, eDirNext, eSelectEndLine); - if (tmpOffset > thisLineBeginOffset && tmpOffset < aOffset) { - // We found a previous line offset. Return the next character after it - // as our start offset if it points to a line end char. - return IsLineEndCharAt(tmpOffset) ? tmpOffset + 1 : tmpOffset; - } - return thisLineBeginOffset; - } - - case eThisLineEnd: - if (IsEmptyLastLineOffset(aOffset)) return aOffset; - - // Move to end of the current line (as end key was pressed). - return FindOffset(aOffset, eDirNext, eSelectEndLine); - - case eNextLineBegin: { - if (IsEmptyLastLineOffset(aOffset)) return aOffset; - - // Move to begin of the next line if any (arrow down and home keys), - // otherwise end of the current line (arrow down only). - uint32_t tmpOffset = FindOffset(aOffset, eDirNext, eSelectLine); - uint32_t characterCount = CharacterCount(); - if (tmpOffset == characterCount) { - return tmpOffset; - } - - // Now, simulate the Home key on the next line to get its real offset. - uint32_t nextLineBeginOffset = - FindOffset(tmpOffset, eDirPrevious, eSelectBeginLine); - // Sometimes, there are line breaks inside embedded characters. If this - // is the case, the cursor is after the line break, but the offset will - // be that of the embedded character, which points to before the line - // break. We definitely want the line break included. - if (IsCharAt(nextLineBeginOffset, kEmbeddedObjectChar)) { - // We can determine if there is a line break by pressing End from - // the queried offset. If there is a line break, the offset will be 1 - // greater, since this line ends with the embed. If there is not, the - // value will be different even if a line break follows right after the - // embed. - uint32_t thisLineEndOffset = - FindOffset(aOffset, eDirNext, eSelectEndLine); - if (thisLineEndOffset == nextLineBeginOffset + 1) { - // If we're querying the offset of the embedded character, we want - // the end offset of the parent line instead. Press End - // once more from the current position, which is after the embed. - if (nextLineBeginOffset == aOffset) { - uint32_t thisLineEndOffset2 = - FindOffset(thisLineEndOffset, eDirNext, eSelectEndLine); - // The above returns an offset exclusive the final line break, so we - // need to add 1 to it to return an inclusive end offset. Make sure - // we don't overshoot if we've started from another embedded - // character that has a line break, or landed on another embedded - // character, or if the result is the very end. - return (thisLineEndOffset2 == characterCount || - (IsCharAt(thisLineEndOffset, kEmbeddedObjectChar) && - thisLineEndOffset2 == thisLineEndOffset + 1) || - IsCharAt(thisLineEndOffset2, kEmbeddedObjectChar)) - ? thisLineEndOffset2 - : thisLineEndOffset2 + 1; - } - - return thisLineEndOffset; - } - return nextLineBeginOffset; - } - - // If the resulting offset is not greater than the offset we started from, - // layout could not find the offset for us. This can happen with certain - // inline-block elements. - if (nextLineBeginOffset <= aOffset) { - // Walk forward from the offset we started from up to tmpOffset, - // stopping after a line end character. - nextLineBeginOffset = aOffset; - while (nextLineBeginOffset < tmpOffset) { - if (IsLineEndCharAt(nextLineBeginOffset)) { - return nextLineBeginOffset + 1; - } - nextLineBeginOffset++; - } - } - - return nextLineBeginOffset; - } - - case eNextLineEnd: { - if (IsEmptyLastLineOffset(aOffset)) return aOffset; - - // Move to next line end (as down arrow and end key were pressed). - uint32_t tmpOffset = FindOffset(aOffset, eDirNext, eSelectLine); - if (tmpOffset == CharacterCount()) return tmpOffset; - - return FindOffset(tmpOffset, eDirNext, eSelectEndLine); - } - } - - return 0; -} - -int32_t HyperTextAccessible::FindParagraphStartOffset(uint32_t aOffset) { - // Because layout often gives us offsets that are incompatible with - // accessibility API requirements, for example when a paragraph contains - // presentational line breaks as found in Google Docs, use the accessibility - // tree to find the start offset instead. - LocalAccessible* child = GetChildAtOffset(aOffset); - if (!child) { - return -1; // Invalid offset - } - - // Use the pivot class to search for the start offset. - Pivot p = Pivot(this); - ParagraphBoundaryRule boundaryRule = ParagraphBoundaryRule( - child, child->IsTextLeaf() ? aOffset - GetChildOffset(child) : 0, - eDirPrevious); - Accessible* match = p.Prev(child, boundaryRule, true); - if (!match || match->AsLocal() == this) { - // Found nothing, or pivot found the root of the search, startOffset is 0. - // This will include all relevant text nodes. - return 0; - } - - if (match == child) { - // We started out on a boundary. - if (match->Role() == roles::WHITESPACE) { - // We are on a line break boundary, so force pivot to find the previous - // boundary. What we want is any text before this, if any. - match = p.Prev(match, boundaryRule); - if (!match || match->AsLocal() == this) { - // Same as before, we landed on the root, so offset is definitely 0. - return 0; - } - } else if (!match->AsLocal()->IsTextLeaf()) { - // The match is a block element, which is always a starting point, so - // just return its offset. - return TransformOffset(match->AsLocal(), 0, false); - } - } - - if (match->AsLocal()->IsTextLeaf()) { - // ParagraphBoundaryRule only returns a text leaf if it contains a line - // break. We want to stop after that. - return TransformOffset(match->AsLocal(), - boundaryRule.GetLastMatchTextOffset() + 1, false); - } - - // This is a previous boundary, we don't want to include it itself. - // So, walk forward one accessible, excluding the descendants of this - // boundary if it is a block element. The below call to Next should always be - // initialized with a boundary. - SkipParagraphBoundaryRule goForwardOneRule = SkipParagraphBoundaryRule(match); - match = p.Next(match, goForwardOneRule); - // We already know that the search skipped over at least one accessible, - // so match can't be null. Get its transformed offset. - MOZ_ASSERT(match); - return TransformOffset(match->AsLocal(), 0, false); -} - -int32_t HyperTextAccessible::FindParagraphEndOffset(uint32_t aOffset) { - // Because layout often gives us offsets that are incompatible with - // accessibility API requirements, for example when a paragraph contains - // presentational line breaks as found in Google Docs, use the accessibility - // tree to find the end offset instead. - LocalAccessible* child = GetChildAtOffset(aOffset); - if (!child) { - return -1; // invalid offset - } - - // Use the pivot class to search for the end offset. - Pivot p = Pivot(this); - ParagraphBoundaryRule boundaryRule = ParagraphBoundaryRule( - child, child->IsTextLeaf() ? aOffset - GetChildOffset(child) : 0, - eDirNext, - // In order to encompass all paragraphs inside embedded objects, not just - // the first, we want to skip the anchor's subtree. - /* aSkipAnchorSubtree */ true); - // Search forward for the end offset, including child. We don't want - // to go beyond this point if this offset indicates a paragraph boundary. - Accessible* match = p.Next(child, boundaryRule, true); - if (match) { - // Found something of relevance, adjust end offset. - LocalAccessible* matchAcc = match->AsLocal(); - uint32_t matchOffset; - if (matchAcc->IsTextLeaf()) { - // ParagraphBoundaryRule only returns a text leaf if it contains a line - // break. - matchOffset = boundaryRule.GetLastMatchTextOffset() + 1; - } else if (matchAcc->Role() != roles::WHITESPACE && matchAcc != child) { - // We found a block boundary that wasn't our origin. We want to stop - // right on it, not after it, since we don't want to include the content - // of the block. - matchOffset = 0; - } else { - matchOffset = nsAccUtils::TextLength(matchAcc); - } - return TransformOffset(matchAcc, matchOffset, true); - } - - // Didn't find anything, end offset is character count. - return CharacterCount(); -} - -void HyperTextAccessible::TextBeforeOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, - int32_t* aEndOffset, - nsAString& aText) { - if (a11y::IsCacheActive()) { - // This isn't strictly related to caching, but this new text implementation - // is being developed to make caching feasible. We put it behind this pref - // to make it easy to test while it's still under development. - return HyperTextAccessibleBase::TextBeforeOffset( - aOffset, aBoundaryType, aStartOffset, aEndOffset, aText); - } - - *aStartOffset = *aEndOffset = 0; - aText.Truncate(); - - if (aBoundaryType == nsIAccessibleText::BOUNDARY_PARAGRAPH) { - // Not supported, bail out with empty text. - return; - } - - index_t convertedOffset = ConvertMagicOffset(aOffset); - if (!convertedOffset.IsValid() || convertedOffset > CharacterCount()) { - NS_ERROR("Wrong in offset!"); - return; - } - - uint32_t adjustedOffset = convertedOffset; - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) { - adjustedOffset = AdjustCaretOffset(adjustedOffset); - } - - switch (aBoundaryType) { - case nsIAccessibleText::BOUNDARY_CHAR: - if (convertedOffset != 0) { - CharAt(convertedOffset - 1, aText, aStartOffset, aEndOffset); - } - break; - - case nsIAccessibleText::BOUNDARY_WORD_START: { - // If the offset is a word start (except text length offset) then move - // backward to find a start offset (end offset is the given offset). - // Otherwise move backward twice to find both start and end offsets. - if (adjustedOffset == CharacterCount()) { - *aEndOffset = - FindWordBoundary(adjustedOffset, eDirPrevious, eStartWord); - *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eStartWord); - } else { - *aStartOffset = - FindWordBoundary(adjustedOffset, eDirPrevious, eStartWord); - *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eStartWord); - if (*aEndOffset != static_cast(adjustedOffset)) { - *aEndOffset = *aStartOffset; - *aStartOffset = - FindWordBoundary(*aEndOffset, eDirPrevious, eStartWord); - } - } - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - } - - case nsIAccessibleText::BOUNDARY_WORD_END: { - // Move word backward twice to find start and end offsets. - *aEndOffset = FindWordBoundary(convertedOffset, eDirPrevious, eEndWord); - *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - } - - case nsIAccessibleText::BOUNDARY_LINE_START: - *aStartOffset = FindLineBoundary(adjustedOffset, ePrevLineBegin); - *aEndOffset = FindLineBoundary(adjustedOffset, eThisLineBegin); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_LINE_END: { - *aEndOffset = FindLineBoundary(adjustedOffset, ePrevLineEnd); - int32_t tmpOffset = *aEndOffset; - // Adjust offset if line is wrapped. - if (*aEndOffset != 0 && !IsLineEndCharAt(*aEndOffset)) tmpOffset--; - - *aStartOffset = FindLineBoundary(tmpOffset, ePrevLineEnd); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - } - } -} - -void HyperTextAccessible::TextAtOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, - int32_t* aEndOffset, nsAString& aText) { - if (a11y::IsCacheActive()) { - // This isn't strictly related to caching, but this new text implementation - // is being developed to make caching feasible. We put it behind this pref - // to make it easy to test while it's still under development. - return HyperTextAccessibleBase::TextAtOffset( - aOffset, aBoundaryType, aStartOffset, aEndOffset, aText); - } - - *aStartOffset = *aEndOffset = 0; - aText.Truncate(); - - uint32_t adjustedOffset = ConvertMagicOffset(aOffset); - if (adjustedOffset == std::numeric_limits::max()) { - NS_ERROR("Wrong given offset!"); - return; - } - - switch (aBoundaryType) { - case nsIAccessibleText::BOUNDARY_CHAR: - // Return no char if caret is at the end of wrapped line (case of no line - // end character). Returning a next line char is confusing for AT. - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET && - IsCaretAtEndOfLine()) { - *aStartOffset = *aEndOffset = adjustedOffset; - } else { - CharAt(adjustedOffset, aText, aStartOffset, aEndOffset); - } - break; - - case nsIAccessibleText::BOUNDARY_WORD_START: - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) { - adjustedOffset = AdjustCaretOffset(adjustedOffset); - } - - *aEndOffset = FindWordBoundary(adjustedOffset, eDirNext, eStartWord); - *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eStartWord); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_WORD_END: - // Ignore the spec and follow what WebKitGtk does because Orca expects it, - // i.e. return a next word at word end offset of the current word - // (WebKitGtk behavior) instead the current word (AKT spec). - *aEndOffset = FindWordBoundary(adjustedOffset, eDirNext, eEndWord); - *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_LINE_START: - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) { - adjustedOffset = AdjustCaretOffset(adjustedOffset); - } - - *aStartOffset = FindLineBoundary(adjustedOffset, eThisLineBegin); - *aEndOffset = FindLineBoundary(adjustedOffset, eNextLineBegin); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_LINE_END: - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) { - adjustedOffset = AdjustCaretOffset(adjustedOffset); - } - - // In contrast to word end boundary we follow the spec here. - *aStartOffset = FindLineBoundary(adjustedOffset, ePrevLineEnd); - *aEndOffset = FindLineBoundary(adjustedOffset, eThisLineEnd); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_PARAGRAPH: { - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) { - adjustedOffset = AdjustCaretOffset(adjustedOffset); - } - - if (IsEmptyLastLineOffset(adjustedOffset)) { - // We are on the last line of a paragraph where there is no text. - // For example, in a textarea where a new line has just been inserted. - // In this case, return offsets for an empty line without text content. - *aStartOffset = *aEndOffset = adjustedOffset; - break; - } - - *aStartOffset = FindParagraphStartOffset(adjustedOffset); - *aEndOffset = FindParagraphEndOffset(adjustedOffset); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - } - } -} - -void HyperTextAccessible::TextAfterOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, - int32_t* aEndOffset, - nsAString& aText) { - if (a11y::IsCacheActive()) { - // This isn't strictly related to caching, but this new text implementation - // is being developed to make caching feasible. We put it behind this pref - // to make it easy to test while it's still under development. - return HyperTextAccessibleBase::TextAfterOffset( - aOffset, aBoundaryType, aStartOffset, aEndOffset, aText); - } - - *aStartOffset = *aEndOffset = 0; - aText.Truncate(); - - if (aBoundaryType == nsIAccessibleText::BOUNDARY_PARAGRAPH) { - // Not supported, bail out with empty text. - return; - } - - index_t convertedOffset = ConvertMagicOffset(aOffset); - if (!convertedOffset.IsValid() || convertedOffset > CharacterCount()) { - NS_ERROR("Wrong in offset!"); - return; - } - - uint32_t adjustedOffset = convertedOffset; - if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) { - adjustedOffset = AdjustCaretOffset(adjustedOffset); - } - - switch (aBoundaryType) { - case nsIAccessibleText::BOUNDARY_CHAR: - // If caret is at the end of wrapped line (case of no line end character) - // then char after the offset is a first char at next line. - if (adjustedOffset >= CharacterCount()) { - *aStartOffset = *aEndOffset = CharacterCount(); - } else { - CharAt(adjustedOffset + 1, aText, aStartOffset, aEndOffset); - } - break; - - case nsIAccessibleText::BOUNDARY_WORD_START: - // Move word forward twice to find start and end offsets. - *aStartOffset = FindWordBoundary(adjustedOffset, eDirNext, eStartWord); - *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eStartWord); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_WORD_END: - // If the offset is a word end (except 0 offset) then move forward to find - // end offset (start offset is the given offset). Otherwise move forward - // twice to find both start and end offsets. - if (convertedOffset == 0) { - *aStartOffset = FindWordBoundary(convertedOffset, eDirNext, eEndWord); - *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eEndWord); - } else { - *aEndOffset = FindWordBoundary(convertedOffset, eDirNext, eEndWord); - *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord); - if (*aStartOffset != static_cast(convertedOffset)) { - *aStartOffset = *aEndOffset; - *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eEndWord); - } - } - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_LINE_START: - *aStartOffset = FindLineBoundary(adjustedOffset, eNextLineBegin); - *aEndOffset = FindLineBoundary(*aStartOffset, eNextLineBegin); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - - case nsIAccessibleText::BOUNDARY_LINE_END: - *aStartOffset = FindLineBoundary(adjustedOffset, eThisLineEnd); - *aEndOffset = FindLineBoundary(adjustedOffset, eNextLineEnd); - TextSubstring(*aStartOffset, *aEndOffset, aText); - break; - } -} - -already_AddRefed HyperTextAccessible::TextAttributes( - bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset, - int32_t* aEndOffset) { - if (a11y::IsCacheActive()) { - // This isn't strictly related to caching, but this new text implementation - // is being developed to make caching feasible. We put it behind this pref - // to make it easy to test while it's still under development. - return HyperTextAccessibleBase::TextAttributes(aIncludeDefAttrs, aOffset, - aStartOffset, aEndOffset); - } - - // 1. Get each attribute and its ranges one after another. - // 2. As we get each new attribute, we pass the current start and end offsets - // as in/out parameters. In other words, as attributes are collected, - // the attribute range itself can only stay the same or get smaller. - - RefPtr attributes = new AccAttributes(); - *aStartOffset = *aEndOffset = 0; - index_t offset = ConvertMagicOffset(aOffset); - if (!offset.IsValid() || offset > CharacterCount()) { - NS_ERROR("Wrong in offset!"); - return attributes.forget(); - } - - LocalAccessible* accAtOffset = GetChildAtOffset(offset); - if (!accAtOffset) { - // Offset 0 is correct offset when accessible has empty text. Include - // default attributes if they were requested, otherwise return empty set. - if (offset == 0) { - if (aIncludeDefAttrs) { - TextAttrsMgr textAttrsMgr(this); - textAttrsMgr.GetAttributes(attributes); - } - } - return attributes.forget(); - } - - int32_t accAtOffsetIdx = accAtOffset->IndexInParent(); - uint32_t startOffset = GetChildOffset(accAtOffsetIdx); - uint32_t endOffset = GetChildOffset(accAtOffsetIdx + 1); - int32_t offsetInAcc = offset - startOffset; - - TextAttrsMgr textAttrsMgr(this, aIncludeDefAttrs, accAtOffset, - accAtOffsetIdx); - textAttrsMgr.GetAttributes(attributes, &startOffset, &endOffset); - - // Compute spelling attributes on text accessible only. - nsIFrame* offsetFrame = accAtOffset->GetFrame(); - if (offsetFrame && offsetFrame->IsTextFrame()) { - int32_t nodeOffset = 0; - RenderedToContentOffset(offsetFrame, offsetInAcc, &nodeOffset); - - // Set 'misspelled' text attribute. - // FYI: Max length of text in a text node is less than INT32_MAX (see - // NS_MAX_TEXT_FRAGMENT_LENGTH) so that nodeOffset should always - // be 0 or greater. - MOZ_DIAGNOSTIC_ASSERT(accAtOffset->GetNode()->IsText()); - MOZ_DIAGNOSTIC_ASSERT(nodeOffset >= 0); - GetSpellTextAttr(accAtOffset->GetNode(), static_cast(nodeOffset), - &startOffset, &endOffset, attributes); - } - - *aStartOffset = startOffset; - *aEndOffset = endOffset; - return attributes.forget(); -} - already_AddRefed HyperTextAccessible::DefaultTextAttributes() { RefPtr attributes = new AccAttributes(); @@ -1484,100 +507,6 @@ int32_t HyperTextAccessible::OffsetAtPoint(int32_t aX, int32_t aY, return -1; // Not found } -LayoutDeviceIntRect HyperTextAccessible::TextBounds(int32_t aStartOffset, - int32_t aEndOffset, - uint32_t aCoordType) { - if (a11y::IsCacheActive()) { - // This isn't strictly related to caching, but this new text implementation - // is being developed to make caching feasible. We put it behind this pref - // to make it easy to test while it's still under development. - return HyperTextAccessibleBase::TextBounds(aStartOffset, aEndOffset, - aCoordType); - } - - index_t startOffset = ConvertMagicOffset(aStartOffset); - index_t endOffset = ConvertMagicOffset(aEndOffset); - if (!startOffset.IsValid() || !endOffset.IsValid() || - startOffset > endOffset || endOffset > CharacterCount()) { - NS_ERROR("Wrong in offset"); - return LayoutDeviceIntRect(); - } - - if (CharacterCount() == 0) { - nsPresContext* presContext = mDoc->PresContext(); - // Empty content, use our own bound to at least get x,y coordinates - nsIFrame* frame = GetFrame(); - if (!frame) { - return LayoutDeviceIntRect(); - } - return LayoutDeviceIntRect::FromAppUnitsToNearest( - frame->GetScreenRectInAppUnits(), presContext->AppUnitsPerDevPixel()); - } - - int32_t childIdx = GetChildIndexAtOffset(startOffset); - if (childIdx == -1) return LayoutDeviceIntRect(); - - LayoutDeviceIntRect bounds; - int32_t prevOffset = GetChildOffset(childIdx); - int32_t offset1 = startOffset - prevOffset; - - while (childIdx < static_cast(ChildCount())) { - nsIFrame* frame = LocalChildAt(childIdx++)->GetFrame(); - if (!frame) { - MOZ_ASSERT_UNREACHABLE("No frame for a child!"); - continue; - } - - int32_t nextOffset = GetChildOffset(childIdx); - if (nextOffset >= static_cast(endOffset)) { - bounds.UnionRect( - bounds, GetBoundsInFrame(frame, offset1, endOffset - prevOffset)); - break; - } - - bounds.UnionRect(bounds, - GetBoundsInFrame(frame, offset1, nextOffset - prevOffset)); - - prevOffset = nextOffset; - offset1 = 0; - } - - // This document may have a resolution set, we will need to multiply - // the document-relative coordinates by that value and re-apply the doc's - // screen coordinates. - nsPresContext* presContext = mDoc->PresContext(); - nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame(); - LayoutDeviceIntRect orgRectPixels = - LayoutDeviceIntRect::FromAppUnitsToNearest( - rootFrame->GetScreenRectInAppUnits(), - presContext->AppUnitsPerDevPixel()); - bounds.MoveBy(-orgRectPixels.X(), -orgRectPixels.Y()); - bounds.ScaleRoundOut(presContext->PresShell()->GetResolution()); - bounds.MoveBy(orgRectPixels.X(), orgRectPixels.Y()); - - auto boundsX = bounds.X(); - auto boundsY = bounds.Y(); - nsAccUtils::ConvertScreenCoordsTo(&boundsX, &boundsY, aCoordType, this); - bounds.MoveTo(boundsX, boundsY); - return bounds; -} - -LayoutDeviceIntRect HyperTextAccessible::CharBounds(int32_t aOffset, - uint32_t aCoordType) { - if (a11y::IsCacheActive()) { - // This isn't strictly related to caching, but this new text implementation - // is being developed to make caching feasible. We put it behind this pref - // to make it easy to test while it's still under development. - return HyperTextAccessibleBase::CharBounds(aOffset, aCoordType); - } - - index_t startOffset = ConvertMagicOffset(aOffset); - int32_t endOffset = startOffset == CharacterCount() - ? static_cast(startOffset) - : static_cast(startOffset) + 1; - return TextBounds(static_cast(startOffset), endOffset, aCoordType); -} - already_AddRefed HyperTextAccessible::GetEditor() const { if (!mContent->HasFlag(NODE_IS_EDITABLE)) { // If we're inside an editable container, then return that container's @@ -2203,154 +1132,3 @@ nsresult HyperTextAccessible::RenderedToContentOffset( return NS_OK; } - -//////////////////////////////////////////////////////////////////////////////// -// HyperTextAccessible protected - -nsresult HyperTextAccessible::GetDOMPointByFrameOffset( - nsIFrame* aFrame, int32_t aOffset, LocalAccessible* aAccessible, - DOMPoint* aPoint) { - NS_ENSURE_ARG(aAccessible); - - if (!aFrame) { - // If the given frame is null then set offset after the DOM node of the - // given accessible. - NS_ASSERTION(!aAccessible->IsDoc(), - "Shouldn't be called on document accessible!"); - - nsIContent* content = aAccessible->GetContent(); - NS_ASSERTION(content, "Shouldn't operate on defunct accessible!"); - - nsIContent* parent = content->GetParent(); - - aPoint->idx = parent->ComputeIndexOf_Deprecated(content) + 1; - aPoint->node = parent; - - } else if (aFrame->IsTextFrame()) { - nsIContent* content = aFrame->GetContent(); - NS_ENSURE_STATE(content); - - nsIFrame* primaryFrame = content->GetPrimaryFrame(); - nsresult rv = - RenderedToContentOffset(primaryFrame, aOffset, &(aPoint->idx)); - NS_ENSURE_SUCCESS(rv, rv); - - aPoint->node = content; - - } else { - nsIContent* content = aFrame->GetContent(); - NS_ENSURE_STATE(content); - - nsIContent* parent = content->GetParent(); - NS_ENSURE_STATE(parent); - - aPoint->idx = parent->ComputeIndexOf_Deprecated(content); - aPoint->node = parent; - } - - return NS_OK; -} - -// HyperTextAccessible -void HyperTextAccessible::GetSpellTextAttr(nsINode* aNode, uint32_t aNodeOffset, - uint32_t* aStartOffset, - uint32_t* aEndOffset, - AccAttributes* aAttributes) { - RefPtr fs = FrameSelection(); - if (!fs) return; - - dom::Selection* domSel = fs->GetSelection(SelectionType::eSpellCheck); - if (!domSel) return; - - const uint32_t rangeCount = domSel->RangeCount(); - if (!rangeCount) { - return; - } - - uint32_t startOffset = 0, endOffset = 0; - for (const uint32_t idx : IntegerRange(rangeCount)) { - MOZ_ASSERT(domSel->RangeCount() == rangeCount); - const nsRange* range = domSel->GetRangeAt(idx); - MOZ_ASSERT(range); - if (range->Collapsed()) continue; - - // See if the point comes after the range in which case we must continue in - // case there is another range after this one. - nsINode* endNode = range->GetEndContainer(); - uint32_t endNodeOffset = range->EndOffset(); - Maybe order = nsContentUtils::ComparePoints( - aNode, aNodeOffset, endNode, endNodeOffset); - if (NS_WARN_IF(!order)) { - continue; - } - - if (*order >= 0) { - continue; - } - - // At this point our point is either in this range or before it but after - // the previous range. So we check to see if the range starts before the - // point in which case the point is in the missspelled range, otherwise it - // must be before the range and after the previous one if any. - nsINode* startNode = range->GetStartContainer(); - int32_t startNodeOffset = range->StartOffset(); - order = nsContentUtils::ComparePoints(startNode, startNodeOffset, aNode, - aNodeOffset); - if (!order) { - // As (`aNode`, `aNodeOffset`) is comparable to the end of the range, it - // should also be comparable to the range's start. Returning here - // prevents crashes in release builds. - MOZ_ASSERT_UNREACHABLE(); - return; - } - - if (*order <= 0) { - startOffset = DOMPointToOffset(startNode, startNodeOffset); - - endOffset = DOMPointToOffset(endNode, endNodeOffset); - - if (startOffset > *aStartOffset) *aStartOffset = startOffset; - - if (endOffset < *aEndOffset) *aEndOffset = endOffset; - - aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::spelling); - - return; - } - - // This range came after the point. - endOffset = DOMPointToOffset(startNode, startNodeOffset); - - if (idx > 0) { - const nsRange* prevRange = domSel->GetRangeAt(idx - 1); - startOffset = DOMPointToOffset(prevRange->GetEndContainer(), - prevRange->EndOffset()); - } - - // The previous range might not be within this accessible. In that case, - // DOMPointToOffset returns length as a fallback. We don't want to use - // that offset if so, hence the startOffset < *aEndOffset check. - if (startOffset > *aStartOffset && startOffset < *aEndOffset) { - *aStartOffset = startOffset; - } - - if (endOffset < *aEndOffset) *aEndOffset = endOffset; - - return; - } - - // We never found a range that ended after the point, therefore we know that - // the point is not in a range, that we do not need to compute an end offset, - // and that we should use the end offset of the last range to compute the - // start offset of the text attribute range. - const nsRange* prevRange = domSel->GetRangeAt(rangeCount - 1); - startOffset = - DOMPointToOffset(prevRange->GetEndContainer(), prevRange->EndOffset()); - - // The previous range might not be within this accessible. In that case, - // DOMPointToOffset returns length as a fallback. We don't want to use - // that offset if so, hence the startOffset < *aEndOffset check. - if (startOffset > *aStartOffset && startOffset < *aEndOffset) { - *aStartOffset = startOffset; - } -} diff --git a/accessible/generic/HyperTextAccessible.h b/accessible/generic/HyperTextAccessible.h index 4ff45205d4b6..ce5b9185e53f 100644 --- a/accessible/generic/HyperTextAccessible.h +++ b/accessible/generic/HyperTextAccessible.h @@ -12,8 +12,6 @@ #include "nsIAccessibleTypes.h" #include "nsIFrame.h" // only for nsSelectionAmount #include "nsISelectionController.h" -#include "nsDirection.h" -#include "WordMovementType.h" class nsFrameSelection; class nsIFrame; @@ -125,37 +123,6 @@ class HyperTextAccessible : public AccessibleWrap, ////////////////////////////////////////////////////////////////////////////// // TextAccessible - using HyperTextAccessibleBase::CharAt; - - /** - * Return true if char at the given offset equals to given char. - */ - bool IsCharAt(int32_t aOffset, char16_t aChar) { - return CharAt(aOffset) == aChar; - } - - /** - * Return true if terminal char is at the given offset. - */ - bool IsLineEndCharAt(int32_t aOffset) { return IsCharAt(aOffset, '\n'); } - - virtual void TextBeforeOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, int32_t* aEndOffset, - nsAString& aText) override; - virtual void TextAtOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, int32_t* aEndOffset, - nsAString& aText) override; - virtual void TextAfterOffset(int32_t aOffset, - AccessibleTextBoundary aBoundaryType, - int32_t* aStartOffset, int32_t* aEndOffset, - nsAString& aText) override; - - virtual already_AddRefed TextAttributes( - bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset, - int32_t* aEndOffset) override; - virtual already_AddRefed DefaultTextAttributes() override; // HyperTextAccessibleBase provides an overload which takes an Accessible. @@ -170,13 +137,6 @@ class HyperTextAccessible : public AccessibleWrap, */ int32_t OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType) override; - LayoutDeviceIntRect TextBounds( - int32_t aStartOffset, int32_t aEndOffset, - uint32_t aCoordType = - nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE) override; - - LayoutDeviceIntRect CharBounds(int32_t aOffset, uint32_t aCoordType) override; - /** * Get/set caret offset, if no caret then -1. */ @@ -269,75 +229,6 @@ class HyperTextAccessible : public AccessibleWrap, // HyperTextAccessible - /** - * Adjust an offset the caret stays at to get a text by line boundary. - */ - uint32_t AdjustCaretOffset(uint32_t aOffset) const; - - /** - * Return true if the given offset points to terminal empty line if any. - */ - bool IsEmptyLastLineOffset(int32_t aOffset) { - return aOffset == static_cast(CharacterCount()) && - IsLineEndCharAt(aOffset - 1); - } - - /** - * Return an offset of the found word boundary. - */ - uint32_t FindWordBoundary(uint32_t aOffset, nsDirection aDirection, - EWordMovementType aWordMovementType); - - /** - * Used to get begin/end of previous/this/next line. Note: end of line - * is an offset right before '\n' character if any, the offset is right after - * '\n' character is begin of line. In case of wrap word breaks these offsets - * are equal. - */ - enum EWhichLineBoundary { - ePrevLineBegin, - ePrevLineEnd, - eThisLineBegin, - eThisLineEnd, - eNextLineBegin, - eNextLineEnd - }; - - /** - * Return an offset for requested line boundary. See constants above. - */ - uint32_t FindLineBoundary(uint32_t aOffset, - EWhichLineBoundary aWhichLineBoundary); - - /** - * Find the start offset for a paragraph , taking into account - * inner block elements and line breaks. - */ - int32_t FindParagraphStartOffset(uint32_t aOffset); - - /** - * Find the end offset for a paragraph , taking into account - * inner block elements and line breaks. - */ - int32_t FindParagraphEndOffset(uint32_t aOffset); - - /** - * Return an offset corresponding to the given direction and selection amount - * relative the given offset. A helper used to find word or line boundaries. - */ - uint32_t FindOffset(uint32_t aOffset, nsDirection aDirection, - nsSelectionAmount aAmount, - EWordMovementType aWordMovementType = eDefaultBehavior); - - /** - * Return the boundaries (in dev pixels) of the substring in case of textual - * frame or frame boundaries in case of non textual frame, offsets are - * ignored. - */ - LayoutDeviceIntRect GetBoundsInFrame(nsIFrame* aFrame, - uint32_t aStartRenderedOffset, - uint32_t aEndRenderedOffset); - // Selection helpers /** @@ -356,26 +247,6 @@ class HyperTextAccessible : public AccessibleWrap, int32_t aEndPos); // Helpers - nsresult GetDOMPointByFrameOffset(nsIFrame* aFrame, int32_t aOffset, - LocalAccessible* aAccessible, - mozilla::a11y::DOMPoint* aPoint); - - /** - * Set 'misspelled' text attribute and return range offsets where the - * attibute is stretched. If the text is not misspelled at the given offset - * then we expose only range offsets where text is not misspelled. The method - * is used by TextAttributes() method. - * - * @param aIncludeDefAttrs [in] points whether text attributes having default - * values of attributes should be included - * @param aSourceNode [in] the node we start to traverse from - * @param aStartOffset [in, out] the start offset - * @param aEndOffset [in, out] the end offset - * @param aAttributes [out, optional] result attributes - */ - void GetSpellTextAttr(nsINode* aNode, uint32_t aNodeOffset, - uint32_t* aStartOffset, uint32_t* aEndOffset, - AccAttributes* aAttributes); /** * Set xml-roles attributes for MathML elements. diff --git a/accessible/mac/HyperTextAccessibleWrap.h b/accessible/mac/HyperTextAccessibleWrap.h index bb418ed179b6..15fbab3cc26b 100644 --- a/accessible/mac/HyperTextAccessibleWrap.h +++ b/accessible/mac/HyperTextAccessibleWrap.h @@ -8,6 +8,7 @@ #include "HyperTextAccessible.h" #include "PlatformExtTypes.h" +#include "WordMovementType.h" namespace mozilla { namespace a11y {