зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1767256 - Include elements with display:contents when calculating range bounding rect r=emilio
Elements with display:contents does not participate in layout, but it's children does. When calculating the bounding rect of a range, those children have to be taken into account. Differential Revision: https://phabricator.services.mozilla.com/D151229
This commit is contained in:
Родитель
bc86581122
Коммит
2dff9781d9
|
@ -27,11 +27,12 @@
|
|||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/ContentIterator.h"
|
||||
#include "mozilla/dom/CharacterData.h"
|
||||
#include "mozilla/dom/ChildIterator.h"
|
||||
#include "mozilla/dom/DOMRect.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/DocumentType.h"
|
||||
#include "mozilla/dom/RangeBinding.h"
|
||||
#include "mozilla/dom/DOMRect.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/dom/Text.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
@ -2695,6 +2696,50 @@ static nsresult GetPartialTextRect(RectCallback* aCallback,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static void CollectClientRectsForSubtree(
|
||||
nsINode* aNode, RectCallback* aCollector, Sequence<nsString>* aTextList,
|
||||
nsINode* aStartContainer, uint32_t aStartOffset, nsINode* aEndContainer,
|
||||
uint32_t aEndOffset, bool aClampToEdge, bool aFlushLayout) {
|
||||
auto* content = nsIContent::FromNode(aNode);
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (content->IsText()) {
|
||||
if (aNode == aStartContainer) {
|
||||
int32_t offset = aStartContainer == aEndContainer
|
||||
? static_cast<int32_t>(aEndOffset)
|
||||
: content->AsText()->TextDataLength();
|
||||
GetPartialTextRect(aCollector, aTextList, content,
|
||||
static_cast<int32_t>(aStartOffset), offset,
|
||||
aClampToEdge, aFlushLayout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aNode == aEndContainer) {
|
||||
GetPartialTextRect(aCollector, aTextList, content, 0,
|
||||
static_cast<int32_t>(aEndOffset), aClampToEdge,
|
||||
aFlushLayout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (aNode->IsElement() && aNode->AsElement()->IsDisplayContents()) {
|
||||
FlattenedChildIterator childIter(content);
|
||||
|
||||
for (nsIContent* child = childIter.GetNextChild(); child;
|
||||
child = childIter.GetNextChild()) {
|
||||
CollectClientRectsForSubtree(child, aCollector, aTextList,
|
||||
aStartContainer, aStartOffset, aEndContainer,
|
||||
aEndOffset, aClampToEdge, aFlushLayout);
|
||||
}
|
||||
} else if (nsIFrame* frame = content->GetPrimaryFrame()) {
|
||||
nsLayoutUtils::GetAllInFlowRectsAndTexts(
|
||||
frame, nsLayoutUtils::GetContainingBlockForClientRect(frame),
|
||||
aCollector, aTextList, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsRange::CollectClientRectsAndText(
|
||||
RectCallback* aCollector, Sequence<nsString>* aTextList, nsRange* aRange,
|
||||
|
@ -2756,31 +2801,10 @@ void nsRange::CollectClientRectsAndText(
|
|||
do {
|
||||
nsCOMPtr<nsINode> node = iter.GetCurrentNode();
|
||||
iter.Next();
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
if (!content) continue;
|
||||
if (content->IsText()) {
|
||||
if (node == startContainer) {
|
||||
int32_t offset = startContainer == endContainer
|
||||
? static_cast<int32_t>(aEndOffset)
|
||||
: content->AsText()->TextDataLength();
|
||||
GetPartialTextRect(aCollector, aTextList, content,
|
||||
static_cast<int32_t>(aStartOffset), offset,
|
||||
aClampToEdge, aFlushLayout);
|
||||
continue;
|
||||
} else if (node == endContainer) {
|
||||
GetPartialTextRect(aCollector, aTextList, content, 0,
|
||||
static_cast<int32_t>(aEndOffset), aClampToEdge,
|
||||
aFlushLayout);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsLayoutUtils::GetAllInFlowRectsAndTexts(
|
||||
frame, nsLayoutUtils::GetContainingBlockForClientRect(frame),
|
||||
aCollector, aTextList, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
}
|
||||
CollectClientRectsForSubtree(node, aCollector, aTextList, aStartContainer,
|
||||
aStartOffset, aEndContainer, aEndOffset,
|
||||
aClampToEdge, aFlushLayout);
|
||||
} while (!iter.IsDone());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Include display:contents elements recursively when calculating bounding rect for a ranges</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/cssom-view-1/#dom-range-getboundingclientrect">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="container">
|
||||
<div id="spacerBefore">spacer before</div>
|
||||
<div style="display:contents">
|
||||
<div style="height:30px; background:lightblue">
|
||||
HEIGHT: 30px
|
||||
</div>
|
||||
<div style="display:contents">
|
||||
<div style="display:contents">
|
||||
<div style="height:30px; background:lightblue">
|
||||
HEIGHT: 30px
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="spacerAfter">spacer after</div>
|
||||
</div>
|
||||
<script>
|
||||
test(function () {
|
||||
const spacerBefore = document.getElementById("spacerBefore");
|
||||
const spacerAfter = document.getElementById("spacerAfter");
|
||||
|
||||
const expected = spacerAfter.getBoundingClientRect().top - spacerBefore.getBoundingClientRect().bottom;
|
||||
|
||||
const rangeBetweenSpacers = document.createRange();
|
||||
rangeBetweenSpacers.setStartAfter(spacerBefore);
|
||||
rangeBetweenSpacers.setEndBefore(spacerAfter);
|
||||
|
||||
const actual = rangeBetweenSpacers.getBoundingClientRect().height;
|
||||
|
||||
assert_true(actual > 0, "range has vertical height");
|
||||
assert_equals(expected, actual, "range.getBoundingClientRect().height");
|
||||
}, "the space between elements using a range should be the same as using another method")
|
||||
</script>
|
Загрузка…
Ссылка в новой задаче