mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1878805 - Fix a crash which a caret frame misses a MarkNeedsDisplayItemRebuild() call r=emilio
Generally, we mark a caret frame for display first, and then nsCaret tracks this frame in nsCaret::SchedulePaint to call MarkNeedsDisplayItemRebuild() accordingly. However, it's possible for nsCaret::SchedulePaint fails to find the caret frame (i.e, selection changes), so we end up not calling MarkNeedsDisplayItemRebuild() on this frame. This patch improves this case by manually setting this caret frame to nsCaret, so that it's always tracked. Differential Revision: https://phabricator.services.mozilla.com/D200880
This commit is contained in:
parent
ce3defc7e2
commit
e4f25caa82
@ -413,7 +413,7 @@ void nsCaret::SchedulePaint(Selection* aSelection) {
|
||||
nsIFrame* frame = GetFrameAndOffset(selection, mOverrideContent,
|
||||
mOverrideOffset, &frameOffset);
|
||||
if (!frame) {
|
||||
mLastCaretFrame = nullptr;
|
||||
SetLastCaretFrame(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -421,7 +421,7 @@ void nsCaret::SchedulePaint(Selection* aSelection) {
|
||||
frame = cb;
|
||||
}
|
||||
|
||||
mLastCaretFrame = frame;
|
||||
SetLastCaretFrame(frame);
|
||||
frame->SchedulePaint();
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,10 @@ class nsCaret final : public nsISelectionListener {
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
void SetLastCaretFrame(nsIFrame* aLastCaretFrame) {
|
||||
mLastCaretFrame = aLastCaretFrame;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void CaretBlinkCallback(nsITimer* aTimer, void* aClosure);
|
||||
|
||||
|
34
layout/generic/crashtests/1878805.html
Normal file
34
layout/generic/crashtests/1878805.html
Normal file
@ -0,0 +1,34 @@
|
||||
<html class="reftest-wait">
|
||||
<style>
|
||||
* { translate: 0px }
|
||||
</style>
|
||||
<script>
|
||||
addEventListener("MozReftestInvalidate", () => {
|
||||
o.setAttribute("volume", "-68")
|
||||
document.designMode = "on"
|
||||
document.execCommand("selectAll", false)
|
||||
document.execCommand("insertText", false, "AAA")
|
||||
requestAnimationFrame(function() {
|
||||
requestAnimationFrame(function() {
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
});
|
||||
});
|
||||
})
|
||||
function go() {
|
||||
window.find("A")
|
||||
let a = new MutationObserver(() => {
|
||||
document.designMode = "off"
|
||||
window.requestAnimationFrame(() => {
|
||||
window.parent.document.designMode = "on"
|
||||
document.execCommand("indent", false)
|
||||
document.designMode = "off"
|
||||
})
|
||||
document.onselectionchange = go
|
||||
})
|
||||
a.observe(o, {attributeOldValue: false})
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<input autofocus="" onfocusin="go()">
|
||||
<bgsound id="o">
|
||||
</html>
|
@ -823,3 +823,4 @@ load 1816574.html
|
||||
load 1821603.html
|
||||
load 1822118.html
|
||||
load 1825434.html
|
||||
load 1878805.html
|
||||
|
@ -1119,6 +1119,14 @@ void nsDisplayListBuilder::EnterPresShell(const nsIFrame* aReferenceFrame,
|
||||
// instead.
|
||||
if (state->mCaretFrame) {
|
||||
MOZ_ASSERT(state->mCaretFrame->PresShell() == state->mPresShell);
|
||||
// Generally, nsCaret sets the last caret frame in
|
||||
// nsCaret::SchedulePaint to call MarkNeedsDisplayItemRebuild()
|
||||
// on the frame accordingly, so we shouldn't need do to this manually.
|
||||
// However, it's possible for nsCaret::SchedulePaint fails to find
|
||||
// the caret frame (i.e, selection changes), we end up not calling
|
||||
// MarkNeedsDisplayItemRebuild() on this frame. This is not good,
|
||||
// so we are manually setting the last caret frame here.
|
||||
caret->SetLastCaretFrame(state->mCaretFrame);
|
||||
MarkFrameForDisplay(state->mCaretFrame, aReferenceFrame);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user