Bug 1384606 - part 4: Make `nsIFrame::GetFrameFromDirection` allow to return content in different native anonymous subtree if the caller wants r=emilio

The a11y module wants to traverse frames in native anonymous subtrees.
Therefore, this patch adds new option for allowing it, makes
`nsIFrame::GetFrameFromDirection` check it before comparing native anonymous
subtree root nodes, and makes `HyperTextAccessible::FindOffset` use the
option.

Differential Revision: https://phabricator.services.mozilla.com/D172759
This commit is contained in:
Masayuki Nakano 2023-03-18 04:18:53 +00:00
Родитель 01d2fe15e1
Коммит 5b59e4aeae
6 изменённых файлов: 55 добавлений и 46 удалений

Просмотреть файл

@ -534,7 +534,8 @@ uint32_t HyperTextAccessible::FindOffset(uint32_t aOffset,
PeekOffsetStruct pos(
aAmount, aDirection, innerContentOffset, nsPoint(0, 0),
{PeekOffsetOption::JumpLines, PeekOffsetOption::IsKeyboardSelect,
PeekOffsetOption::PreserveSpaces},
PeekOffsetOption::PreserveSpaces,
PeekOffsetOption::AllowContentInDifferentNativeAnonymousSubtreeRoot},
aWordMovementType);
nsresult rv = frameAtOffset->PeekOffset(&pos);

Просмотреть файл

@ -730,7 +730,8 @@ TextPoint HyperTextAccessibleWrap::FindTextPoint(
PeekOffsetStruct pos(
aAmount, aDirection, innerContentOffset, nsPoint(0, 0),
{PeekOffsetOption::JumpLines, PeekOffsetOption::IsKeyboardSelect,
PeekOffsetOption::PreserveSpaces},
PeekOffsetOption::PreserveSpaces,
PeekOffsetOption::AllowContentInDifferentNativeAnonymousSubtreeRoot},
aWordMovementType);
nsresult rv = frameAtOffset->PeekOffset(&pos);

Просмотреть файл

@ -977,10 +977,12 @@ nsPrevNextBidiLevels nsFrameSelection::GetPrevNextBidiLevels(
return levels;
}
PeekOffsetOptions peekOffsetOptions{PeekOffsetOption::ScrollViewStop};
if (aJumpLines) {
peekOffsetOptions += PeekOffsetOption::JumpLines;
}
nsIFrame* newFrame =
currentFrame
->GetFrameFromDirection(direction, false, aJumpLines, true, false)
.mFrame;
currentFrame->GetFrameFromDirection(direction, peekOffsetOptions).mFrame;
FrameBidiData currentBidi = currentFrame->GetBidiData();
mozilla::intl::BidiEmbeddingLevel currentLevel = currentBidi.embeddingLevel;

Просмотреть файл

@ -101,6 +101,10 @@ enum class PeekOffsetOption : uint8_t {
// If true, the offset has to end up in an editable node, otherwise we'll keep
// searching.
ForceEditableRegion,
// If set, the result's native anonymous subtree root may be different from
// the scan start content's root.
AllowContentInDifferentNativeAnonymousSubtreeRoot,
};
using PeekOffsetOptions = EnumSet<PeekOffsetOption>;

Просмотреть файл

@ -9523,19 +9523,19 @@ Result<bool, nsresult> nsIFrame::IsLogicallyAtLineEdge(
}
nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
nsDirection aDirection, bool aVisual, bool aJumpLines, bool aScrollViewStop,
bool aForceEditableRegion) {
nsDirection aDirection, const PeekOffsetOptions& aOptions) {
SelectablePeekReport result;
nsPresContext* presContext = PresContext();
bool needsVisualTraversal = aVisual && presContext->BidiEnabled();
const bool needsVisualTraversal =
aOptions.contains(PeekOffsetOption::Visual) && presContext->BidiEnabled();
nsCOMPtr<nsIFrameEnumerator> frameTraversal;
MOZ_TRY(NS_NewFrameTraversal(getter_AddRefs(frameTraversal), presContext,
this, eLeaf, needsVisualTraversal,
aScrollViewStop,
true, // aFollowOOFs
false // aSkipPopupChecks
));
MOZ_TRY(NS_NewFrameTraversal(
getter_AddRefs(frameTraversal), presContext, this, eLeaf,
needsVisualTraversal, aOptions.contains(PeekOffsetOption::ScrollViewStop),
true, // aFollowOOFs
false // aSkipPopupChecks
));
// Find the prev/next selectable frame
bool selectable = false;
@ -9544,8 +9544,8 @@ nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
const nsIContent* const nativeAnonymousSubtreeContent =
GetClosestNativeAnonymousSubtreeRoot();
while (!selectable) {
auto [blockFrame, lineFrame] =
traversedFrame->GetContainingBlockForLine(aScrollViewStop);
auto [blockFrame, lineFrame] = traversedFrame->GetContainingBlockForLine(
aOptions.contains(PeekOffsetOption::ScrollViewStop));
if (!blockFrame) {
return result;
}
@ -9564,7 +9564,7 @@ nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
: traversedFrame->IsLogicallyAtLineEdge(it, thisLine, aDirection));
if (atLineEdge) {
result.mJumpedLine = true;
if (!aJumpLines) {
if (!aOptions.contains(PeekOffsetOption::JumpLines)) {
return result; // we are done. cannot jump lines
}
int32_t lineToCheckWrap =
@ -9580,19 +9580,24 @@ nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
return result;
}
auto IsSelectable = [aForceEditableRegion, nativeAnonymousSubtreeContent](
const nsIFrame* aFrame) {
if (!aFrame->IsSelectable(nullptr)) {
return false;
}
// If the new frame is in a native anonymous subtree, we should treat it
// as not selectable unless the frame and found frame are in same subtree.
if (aFrame->GetClosestNativeAnonymousSubtreeRoot() !=
nativeAnonymousSubtreeContent) {
return false;
}
return !aForceEditableRegion || aFrame->GetContent()->IsEditable();
};
auto IsSelectable =
[aOptions, nativeAnonymousSubtreeContent](const nsIFrame* aFrame) {
if (!aFrame->IsSelectable(nullptr)) {
return false;
}
// If the new frame is in a native anonymous subtree, we should treat
// it as not selectable unless the frame and found frame are in same
// subtree.
if (!aOptions.contains(
PeekOffsetOption::
AllowContentInDifferentNativeAnonymousSubtreeRoot) &&
aFrame->GetClosestNativeAnonymousSubtreeRoot() !=
nativeAnonymousSubtreeContent) {
return false;
}
return !aOptions.contains(PeekOffsetOption::ForceEditableRegion) ||
aFrame->GetContent()->IsEditable();
};
// Skip br frames, but only if we can select something before hitting the
// end of the line or a non-selectable region.
@ -9623,7 +9628,8 @@ nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
result.mOffset = (aDirection == eDirNext) ? 0 : -1;
if (aVisual && nsBidiPresUtils::IsReversedDirectionFrame(traversedFrame)) {
if (aOptions.contains(PeekOffsetOption::Visual) &&
nsBidiPresUtils::IsReversedDirectionFrame(traversedFrame)) {
// The new frame is reverse-direction, go to the other end
result.mOffset = -1 - result.mOffset;
}
@ -9633,11 +9639,7 @@ nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
const PeekOffsetStruct& aPos) {
return GetFrameFromDirection(
aPos.mDirection, aPos.mOptions.contains(PeekOffsetOption::Visual),
aPos.mOptions.contains(PeekOffsetOption::JumpLines),
aPos.mOptions.contains(PeekOffsetOption::ScrollViewStop),
aPos.mOptions.contains(PeekOffsetOption::ForceEditableRegion));
return GetFrameFromDirection(aPos.mDirection, aPos.mOptions);
}
nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const {

Просмотреть файл

@ -55,6 +55,7 @@
#include "mozilla/AspectRatio.h"
#include "mozilla/Attributes.h"
#include "mozilla/Baseline.h"
#include "mozilla/EnumSet.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Maybe.h"
#include "mozilla/RelativeTo.h"
@ -129,6 +130,7 @@ struct CharacterDataChangeInfo;
namespace mozilla {
enum class PeekOffsetOption : uint8_t;
enum class PseudoStyleType : uint8_t;
enum class TableSelectionMode : uint32_t;
@ -3877,17 +3879,14 @@ class nsIFrame : public nsQueryFrame {
* Called to find the previous/next non-anonymous selectable leaf frame.
*
* @param aDirection the direction to move in (eDirPrevious or eDirNext)
* @param aVisual whether bidi caret behavior is visual (true) or logical
* (false)
* @param aJumpLines whether to allow jumping across line boundaries
* @param aScrollViewStop whether to stop when reaching a scroll frame
* boundary
* @param aOptions the other options which is same as
* PeekOffsetStruct::mOptions.
* FIXME: Due to the include hell, we cannot use the alias, PeekOffsetOptions
* is not available in this header file.
*/
SelectablePeekReport GetFrameFromDirection(nsDirection aDirection,
bool aVisual, bool aJumpLines,
bool aScrollViewStop,
bool aForceEditableRegion);
SelectablePeekReport GetFrameFromDirection(
nsDirection aDirection,
const mozilla::EnumSet<mozilla::PeekOffsetOption>& aOptions);
SelectablePeekReport GetFrameFromDirection(
const mozilla::PeekOffsetStruct& aPos);