Backed out changeset 1b8515b4548c (bug 1666998) for bustages on HyperTextAccessible.cpp. CLOSED TREE

This commit is contained in:
Cosmin Sabou 2020-10-01 14:56:38 +03:00
parent 212db4fb3c
commit 1fa6714a17
3 changed files with 36 additions and 196 deletions

View File

@ -8,7 +8,6 @@
#include "Accessible-inl.h"
#include "nsAccessibilityService.h"
#include "nsAccessiblePivot.h"
#include "nsIAccessibleTypes.h"
#include "DocAccessible.h"
#include "HTMLListAccessible.h"
@ -51,73 +50,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(AccessibleOrProxy& aSkipSubtreeFor)
: mSkipSubtreeFor(aSkipSubtreeFor) {}
ParagraphBoundaryRule() : mSkipSubtreeFor(nullptr) {}
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override {
MOZ_ASSERT(aAccOrProxy.IsAccessible());
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
// If there is a child passed to the rule class, this means a special
// case where the caller doesn't want to go into the sub tree for the end
// offset, for example, line breaks inside embedded objects.
if (aAccOrProxy == mSkipSubtreeFor) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
// First, deal with the case that we encountered a line break, for example,
// a br in a paragraph.
if (aAccOrProxy.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 = aAccOrProxy.AsAccessible()->GetFrame();
if (frame && frame->IsBlockFrame()) {
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
}
return result;
}
private:
AccessibleOrProxy mSkipSubtreeFor;
};
/**
* 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(AccessibleOrProxy& aBoundary)
: mBoundary(aBoundary) {}
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override {
MOZ_ASSERT(aAccOrProxy.IsAccessible());
// If matching the boundary, skip its sub tree.
if (aAccOrProxy == mBoundary) {
return nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
return nsIAccessibleTraversalRule::FILTER_MATCH;
}
private:
AccessibleOrProxy& mBoundary;
};
////////////////////////////////////////////////////////////////////////////////
// HyperTextAccessible
////////////////////////////////////////////////////////////////////////////////
@ -481,6 +413,7 @@ uint32_t HyperTextAccessible::FindOffset(uint32_t aOffset,
switch (aAmount) {
case eSelectLine:
case eSelectEndLine:
case eSelectParagraph:
// Ask a text leaf next (if not empty) to the bullet for an offset
// since list item may be multiline.
return nextOffset < CharacterCount()
@ -542,11 +475,13 @@ uint32_t HyperTextAccessible::FindOffset(uint32_t aOffset,
uint32_t hyperTextOffset = DOMPointToOffset(
pos.mResultContent, pos.mContentOffset, aDirection == eDirNext);
if (fallBackToSelectEndLine && IsLineEndCharAt(hyperTextOffset)) {
if ((fallBackToSelectEndLine || aAmount == eSelectParagraph) &&
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.
// Or, we were asked for the paragraph.
// If there's a '\n' at the end of the line, eSelectEndLine and
// eSelectParagraph 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;
}
@ -556,7 +491,8 @@ uint32_t HyperTextAccessible::FindOffset(uint32_t aOffset,
if (hyperTextOffset == CharacterCount()) return 0;
// PeekOffset stops right before bullet so return 0 to workaround it.
if (IsHTMLListItem() && aAmount == eSelectBeginLine &&
if (IsHTMLListItem() &&
(aAmount == eSelectBeginLine || aAmount == eSelectParagraph) &&
hyperTextOffset > 0) {
Accessible* prevOffsetChild = GetChildAtOffset(hyperTextOffset - 1);
if (prevOffsetChild == AsHTMLListItem()->Bullet()) return 0;
@ -727,85 +663,6 @@ uint32_t HyperTextAccessible::FindLineBoundary(
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.
Accessible* 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();
AccessibleOrProxy wrappedChild = AccessibleOrProxy(child);
AccessibleOrProxy match = p.Prev(wrappedChild, boundaryRule, true);
if (match.IsNull() || match.AsAccessible() == 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 == wrappedChild) {
// 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.IsNull() || match.AsAccessible() == this) {
// Same as before, we landed on the root, so offset is definitely 0.
return 0;
}
} else {
// The match is a block element, which is always a starting point, so
// just return its offset.
return TransformOffset(match.AsAccessible(), 0, 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.IsNull());
return TransformOffset(match.AsAccessible(), 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.
Accessible* child = GetChildAtOffset(aOffset);
if (!child) {
return -1; // invalid offset
}
// Use the pivot class to search for the end offset.
Pivot p = Pivot(this);
AccessibleOrProxy wrappedChild = AccessibleOrProxy(child);
// In order to encompass all paragraphs inside embedded objects, not just
// the first, pass the child to the rule constructor to skip its subtree.
ParagraphBoundaryRule boundaryRule = ParagraphBoundaryRule(wrappedChild);
// Search forward for the end offset, including wrappedChild. We don't want
// to go beyond this point if this offset indicates a paragraph boundary.
AccessibleOrProxy match = p.Next(wrappedChild, boundaryRule, true);
if (!match.IsNull()) {
// Found something of relevance, adjust end offset.
Accessible* matchAcc = match.AsAccessible();
return TransformOffset(matchAcc, nsAccUtils::TextLength(matchAcc), true);
}
// Didn't find anything, end offset is character count.
return CharacterCount();
}
void HyperTextAccessible::TextBeforeOffset(int32_t aOffset,
AccessibleTextBoundary aBoundaryType,
int32_t* aStartOffset,
@ -958,8 +815,33 @@ void HyperTextAccessible::TextAtOffset(int32_t aOffset,
break;
}
*aStartOffset = FindParagraphStartOffset(adjustedOffset);
*aEndOffset = FindParagraphEndOffset(adjustedOffset);
if (IsLineEndCharAt(adjustedOffset)) {
// Layout gives us different results for a paragraph with line breaks.
// For the text, we get the text, for the line break, we get the text
// with the line break included. We adjust for the former case in
// FindOffset. However, querying on the whitespace also gives us text
// from the next chunk, which is never what we want. So, adjust the
// offset to make sure we always get the text with the '\n' included.
if (adjustedOffset == 0 || IsLineEndCharAt(adjustedOffset - 1)) {
// However, if the line break is at the start of the enclosing
// paragraph, or the character before this is also a line break, we
// want this to be only '\n'. In addition, layout would still
// give us the text of the next chunk here, too, which is still
// not what we want, either.
*aStartOffset = adjustedOffset;
*aEndOffset = adjustedOffset + 1;
TextSubstring(*aStartOffset, *aEndOffset, aText);
break;
}
// We're on a non-line-end character, adjust the offset and
// calculate the paragraph text and offsets as usual.
adjustedOffset--;
}
*aStartOffset =
FindOffset(adjustedOffset, eDirPrevious, eSelectParagraph);
*aEndOffset = FindOffset(adjustedOffset, eDirNext, eSelectParagraph);
TextSubstring(*aStartOffset, *aEndOffset, aText);
break;
}

View File

@ -468,18 +468,6 @@ class HyperTextAccessible : public AccessibleWrap {
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.

View File

@ -45,12 +45,6 @@
testTextAtOffset("link", BOUNDARY_PARAGRAPH,
[[0, 2, "bc", 0, 2]]);
// Paragraph with link that contains a line break.
testTextAtOffset("pWithLinkWithBr", BOUNDARY_PARAGRAPH,
[[0, 0, "a" + kEmbedChar, 0, 2],
[1, 1, "a" + kEmbedChar + "d", 0, 3],
[2, 3, kEmbedChar + "d", 1, 3]]);
// Test a list and list item
testTextAtOffset("ul", BOUNDARY_PARAGRAPH,
[[0, 0, kEmbedChar, 0, 1],
@ -64,25 +58,6 @@
[[0, 15, "This is a test.\n", 0, 16],
[16, 16, "", 16, 16]]);
// Paragraph with a presentational line break.
testTextAtOffset("presentational_br", BOUNDARY_PARAGRAPH,
[[0, 3, "a b", 0, 3]]);
// Two paragraphs in a div, non-editable case.
testTextAtOffset("two_paragraphs", BOUNDARY_PARAGRAPH,
[[0, 0, kEmbedChar, 0, 1],
[1, 2, kEmbedChar, 1, 2]]);
// Div containing a paragraph containing a link
testTextAtOffset("divWithParaWithLink", BOUNDARY_PARAGRAPH,
[[0, 0, kEmbedChar, 0, 1],
[1, 2, "b", 1, 2]]);
// Two text nodes and a br
testTextAtOffset("twoTextNodesAndBr", BOUNDARY_PARAGRAPH,
[[0, 2, "ab\n", 0, 3],
[3, 3, "", 3, 3]]);
SimpleTest.finish();
}
@ -111,13 +86,8 @@
<p id="forced_br">a<br>b<br><br>c</p>
<p id="br_at_beginning"><br>a<br>b</p>
<p id="pWithLink">a<a id="link" href="https://example.com/">bc</a>d</p>
<p id="pWithLinkWithBr">a<a href="#">b<br>c</a>d</p>
<ul id="ul"><li id="li1">a</li><li>b</li></ul>
<textarea id="textarea_with_br">This is a test.
</textarea> <!-- This must be outdented for a correct test case -->
<p id="presentational_br" style="white-space: pre-wrap;">a<span> <br role="presentation"></span>b</p>
<div id="two_paragraphs"><p>a</p><p>b</p></div>
<div id ="divWithParaWithLink"><p><a href="#">a</a></p>b</div>
<p id="twoTextNodesAndBr">a<span>b</span><br></p>
</body>
</html>