Bug 1900426 - Implement DnD for shadow-crossing selection r=jjaschke,smaug,dom-core

This patches allows
  1. when the selection is shadow-crossing, dragging it will have the
  correct the drag image correctly displayed. It's hard to test, so
  no tests for this.

  2. The selection can now be serialized and dropped.
  `test_drag_drop_shadow_crossing_selection.html` is the test for
  this.

Differential Revision: https://phabricator.services.mozilla.com/D217318
This commit is contained in:
Sean Feng
2024-09-03 15:42:58 +00:00
parent f54eb90df0
commit c6e6d73a26
12 changed files with 219 additions and 38 deletions

View File

@@ -231,7 +231,6 @@ PresShell::CapturingContentInfo PresShell::sCapturingContentInfo;
// RangePaintInfo is used to paint ranges to offscreen buffers
struct RangePaintInfo {
RefPtr<nsRange> mRange;
nsDisplayListBuilder mBuilder;
nsDisplayList mList;
@@ -243,9 +242,8 @@ struct RangePaintInfo {
// to paint them at this resolution.
float mResolution = 1.0;
RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
: mRange(aRange),
mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false),
explicit RangePaintInfo(nsIFrame* aFrame)
: mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false),
mList(&mBuilder) {
MOZ_COUNT_CTOR(RangePaintInfo);
mBuilder.BeginFrame();
@@ -4777,24 +4775,27 @@ nsRect PresShell::ClipListToRange(nsDisplayListBuilder* aBuilder,
nsIFrame* frame = i->Frame();
nsIContent* content = frame->GetContent();
if (content) {
bool atStart = (content == aRange->GetStartContainer());
bool atEnd = (content == aRange->GetEndContainer());
bool atStart =
content == aRange->GetMayCrossShadowBoundaryStartContainer();
bool atEnd = content == aRange->GetMayCrossShadowBoundaryEndContainer();
if ((atStart || atEnd) && frame->IsTextFrame()) {
auto [frameStartOffset, frameEndOffset] = frame->GetOffsets();
int32_t hilightStart =
atStart ? std::max(static_cast<int32_t>(aRange->StartOffset()),
int32_t highlightStart =
atStart ? std::max(static_cast<int32_t>(
aRange->MayCrossShadowBoundaryStartOffset()),
frameStartOffset)
: frameStartOffset;
int32_t hilightEnd =
atEnd ? std::min(static_cast<int32_t>(aRange->EndOffset()),
int32_t highlightEnd =
atEnd ? std::min(static_cast<int32_t>(
aRange->MayCrossShadowBoundaryEndOffset()),
frameEndOffset)
: frameEndOffset;
if (hilightStart < hilightEnd) {
if (highlightStart < highlightEnd) {
// determine the location of the start and end edges of the range.
nsPoint startPoint, endPoint;
frame->GetPointFromOffset(hilightStart, &startPoint);
frame->GetPointFromOffset(hilightEnd, &endPoint);
frame->GetPointFromOffset(highlightStart, &startPoint);
frame->GetPointFromOffset(highlightEnd, &endPoint);
// The clip rectangle is determined by taking the the start and
// end points of the range, offset from the reference frame.
@@ -4828,8 +4829,9 @@ nsRect PresShell::ClipListToRange(nsDisplayListBuilder* aBuilder,
// Don't try to descend into subdocuments.
// If this ever changes we'd need to add handling for subdocuments with
// different zoom levels.
else if (content->GetUncomposedDoc() ==
aRange->GetStartContainer()->GetUncomposedDoc()) {
else if (content->GetComposedDoc() ==
aRange->GetMayCrossShadowBoundaryStartContainer()
->GetComposedDoc()) {
// if the node is within the range, append it to the temporary list
bool before, after;
nsresult rv =
@@ -4874,14 +4876,18 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
// If the start or end of the range is the document, just use the root
// frame, otherwise get the common ancestor of the two endpoints of the
// range.
nsINode* startContainer = aRange->GetStartContainer();
nsINode* endContainer = aRange->GetEndContainer();
nsINode* startContainer = aRange->GetMayCrossShadowBoundaryStartContainer();
nsINode* endContainer = aRange->GetMayCrossShadowBoundaryEndContainer();
Document* doc = startContainer->GetComposedDoc();
if (startContainer == doc || endContainer == doc) {
ancestorFrame = rootFrame;
} else {
nsINode* ancestor = nsContentUtils::GetClosestCommonInclusiveAncestor(
startContainer, endContainer);
nsINode* ancestor =
StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()
? nsContentUtils::GetClosestCommonShadowIncludingInclusiveAncestor(
startContainer, endContainer)
: nsContentUtils::GetClosestCommonInclusiveAncestor(startContainer,
endContainer);
NS_ASSERTION(!ancestor || ancestor->IsContent(),
"common ancestor is not content");
@@ -4906,7 +4912,7 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
}
// get a display list containing the range
auto info = MakeUnique<RangePaintInfo>(aRange, ancestorFrame);
auto info = MakeUnique<RangePaintInfo>(ancestorFrame);
info->mBuilder.SetIncludeAllOutOfFlows();
if (aForPrimarySelection) {
info->mBuilder.SetSelectedFramesOnly();
@@ -4914,7 +4920,9 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
info->mBuilder.EnterPresShell(ancestorFrame);
ContentSubtreeIterator subtreeIter;
nsresult rv = subtreeIter.Init(aRange);
nsresult rv = StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()
? subtreeIter.InitWithAllowCrossShadowBoundary(aRange)
: subtreeIter.Init(aRange);
if (NS_FAILED(rv)) {
return nullptr;
}