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( PeekOffsetStruct pos(
aAmount, aDirection, innerContentOffset, nsPoint(0, 0), aAmount, aDirection, innerContentOffset, nsPoint(0, 0),
{PeekOffsetOption::JumpLines, PeekOffsetOption::IsKeyboardSelect, {PeekOffsetOption::JumpLines, PeekOffsetOption::IsKeyboardSelect,
PeekOffsetOption::PreserveSpaces}, PeekOffsetOption::PreserveSpaces,
PeekOffsetOption::AllowContentInDifferentNativeAnonymousSubtreeRoot},
aWordMovementType); aWordMovementType);
nsresult rv = frameAtOffset->PeekOffset(&pos); nsresult rv = frameAtOffset->PeekOffset(&pos);

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

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

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

@ -977,10 +977,12 @@ nsPrevNextBidiLevels nsFrameSelection::GetPrevNextBidiLevels(
return levels; return levels;
} }
PeekOffsetOptions peekOffsetOptions{PeekOffsetOption::ScrollViewStop};
if (aJumpLines) {
peekOffsetOptions += PeekOffsetOption::JumpLines;
}
nsIFrame* newFrame = nsIFrame* newFrame =
currentFrame currentFrame->GetFrameFromDirection(direction, peekOffsetOptions).mFrame;
->GetFrameFromDirection(direction, false, aJumpLines, true, false)
.mFrame;
FrameBidiData currentBidi = currentFrame->GetBidiData(); FrameBidiData currentBidi = currentFrame->GetBidiData();
mozilla::intl::BidiEmbeddingLevel currentLevel = currentBidi.embeddingLevel; 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 // If true, the offset has to end up in an editable node, otherwise we'll keep
// searching. // searching.
ForceEditableRegion, 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>; using PeekOffsetOptions = EnumSet<PeekOffsetOption>;

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

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

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

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