Bug 1526268 Part 2 - Fix the logic to detect whether AccessibleCaret's position is changed. r=mats

This is the main patch to fix bug 1526268.

It is wrong to use the cached rects relative to the root
frame (ViewportFrame) to detect whether AccessibleCaret's position is
changed or not, because it doesn't account the root scroll frame's
scroll offset.

The effect is that we always produce "PositionChangedResult::Changed"
when scrolling on position:static elements, but
"PositionChangedResult::NotChanged" on position:fixed elements.

This patch fixes this by using the rect relative to custom content
container, which is the actually rect to set caret's position, to check
whether the position is changed or not.

Note that even with this patch, the caret on "position:fixed" element is
still jumpy during scrolling due to APZ. Part 3 will fixed this.

Differential Revision: https://phabricator.services.mozilla.com/D51350

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ting-Yu Lin 2019-11-01 22:19:18 +00:00
Родитель 22b2870b5a
Коммит 742cd4bddc
2 изменённых файлов: 28 добавлений и 12 удалений

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

@ -102,8 +102,7 @@ void AccessibleCaret::SetAppearance(Appearance aAppearance) {
// Need to reset rect since the cached rect will be compared in SetPosition.
if (mAppearance == Appearance::None) {
mImaginaryCaretRect = nsRect();
mZoomLevel = 0.0f;
ClearCachedData();
}
}
@ -231,6 +230,12 @@ void AccessibleCaret::RemoveCaretElement(Document* aDocument) {
aDocument->RemoveAnonymousContent(*mCaretElementHolder, IgnoreErrors());
}
void AccessibleCaret::ClearCachedData() {
mImaginaryCaretRect = nsRect();
mImaginaryCaretRectInContainerFrame = nsRect();
mZoomLevel = 0.0f;
}
AccessibleCaret::PositionChangedResult AccessibleCaret::SetPosition(
nsIFrame* aFrame, int32_t aOffset) {
if (!CustomContentContainerFrame()) {
@ -245,27 +250,31 @@ AccessibleCaret::PositionChangedResult AccessibleCaret::SetPosition(
if (imaginaryCaretRectInFrame.IsEmpty()) {
// Don't bother to set the caret position since it's invisible.
mImaginaryCaretRect = nsRect();
mZoomLevel = 0.0f;
ClearCachedData();
return PositionChangedResult::Invisible;
}
nsRect imaginaryCaretRect = imaginaryCaretRectInFrame;
nsLayoutUtils::TransformRect(aFrame, RootFrame(), imaginaryCaretRect);
float zoomLevel = GetZoomLevel();
// SetCaretElementStyle() requires the input rect relative to the custom
// content container frame.
nsRect imaginaryCaretRectInContainerFrame = imaginaryCaretRectInFrame;
nsLayoutUtils::TransformRect(aFrame, CustomContentContainerFrame(),
imaginaryCaretRectInContainerFrame);
const float zoomLevel = GetZoomLevel();
if (imaginaryCaretRect.IsEqualEdges(mImaginaryCaretRect) &&
if (imaginaryCaretRectInContainerFrame.IsEqualEdges(
mImaginaryCaretRectInContainerFrame) &&
FuzzyEqualsMultiplicative(zoomLevel, mZoomLevel)) {
return PositionChangedResult::NotChanged;
}
nsRect imaginaryCaretRect = imaginaryCaretRectInFrame;
nsLayoutUtils::TransformRect(aFrame, RootFrame(), imaginaryCaretRect);
// Cache mImaginaryCaretRect, which is relative to the root frame.
mImaginaryCaretRect = imaginaryCaretRect;
mImaginaryCaretRectInContainerFrame = imaginaryCaretRectInContainerFrame;
mZoomLevel = zoomLevel;
// SetCaretElementStyle() requires the input rect relative to container frame.
nsRect imaginaryCaretRectInContainerFrame = imaginaryCaretRectInFrame;
nsLayoutUtils::TransformRect(aFrame, CustomContentContainerFrame(),
imaginaryCaretRectInContainerFrame);
SetCaretElementStyle(imaginaryCaretRectInContainerFrame, mZoomLevel);
return PositionChangedResult::Changed;

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

@ -168,6 +168,9 @@ class AccessibleCaret {
// Remove caret element from custom content container.
void RemoveCaretElement(dom::Document*);
// Clear the cached rects and zoom level.
void ClearCachedData();
// The top-center of the imaginary caret to which this AccessibleCaret is
// attached.
static nsPoint CaretElementPosition(const nsRect& aRect) {
@ -199,6 +202,10 @@ class AccessibleCaret {
// mImaginaryCaretRect is relative to root frame.
nsRect mImaginaryCaretRect;
// Cached mImaginaryCaretRect relative to the custom content container. This
// is used in SetPosition() to check whether the caret position has changed.
nsRect mImaginaryCaretRectInContainerFrame;
// Cache current zoom level to determine whether position is changed.
float mZoomLevel = 0.0f;