Index: Source/core/accessibility/AXObject.cpp |
diff --git a/Source/core/accessibility/AXObject.cpp b/Source/core/accessibility/AXObject.cpp |
index c296ddfbda8c8dcc53211a281e49abb716bcb372..fdc942a5c53ca2774b7c5a8f44d26726cba6bf35 100644 |
--- a/Source/core/accessibility/AXObject.cpp |
+++ b/Source/core/accessibility/AXObject.cpp |
@@ -654,23 +654,47 @@ void AXObject::scrollToMakeVisible() const |
// logic is the same. The goal is to compute the best scroll offset |
// in order to make an object visible within a viewport. |
// |
+// If the object is already fully visible, returns the same scroll |
+// offset. |
+// |
// In case the whole object cannot fit, you can specify a |
// subfocus - a smaller region within the object that should |
// be prioritized. If the whole object can fit, the subfocus is |
// ignored. |
// |
-// Example: the viewport is scrolled to the right just enough |
-// that the object is in view. |
+// If possible, the object and subfocus are centered within the |
+// viewport. |
+// |
+// Example 1: the object is already visible, so nothing happens. |
+// +----------Viewport---------+ |
+// +---Object---+ |
+// +--SubFocus--+ |
+// |
+// Example 2: the object is not fully visible, so it's centered |
+// within the viewport. |
// Before: |
// +----------Viewport---------+ |
// +---Object---+ |
// +--SubFocus--+ |
// |
// After: |
-// +----------Viewport---------+ |
+// +----------Viewport---------+ |
// +---Object---+ |
// +--SubFocus--+ |
// |
+// Example 3: the object is larger than the viewport, so the |
+// viewport moves to show as much of the object as possible, |
+// while also trying to center the subfocus. |
+// Before: |
+// +----------Viewport---------+ |
+// +---------------Object--------------+ |
+// +-SubFocus-+ |
+// |
+// After: |
+// +----------Viewport---------+ |
+// +---------------Object--------------+ |
+// +-SubFocus-+ |
+// |
// When constraints cannot be fully satisfied, the min |
// (left/top) position takes precedence over the max (right/bottom). |
// |
@@ -681,8 +705,9 @@ static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int |
{ |
int viewportSize = viewportMax - viewportMin; |
- // If the focus size is larger than the viewport size, shrink it in the |
- // direction of subfocus. |
+ // If the object size is larger than the viewport size, consider |
+ // only a portion that's as large as the viewport, centering on |
+ // the subfocus as much as possible. |
if (objectMax - objectMin > viewportSize) { |
// Subfocus must be within focus: |
subfocusMin = std::max(subfocusMin, objectMin); |
@@ -692,12 +717,12 @@ static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int |
if (subfocusMax - subfocusMin > viewportSize) |
subfocusMax = subfocusMin + viewportSize; |
- if (subfocusMin + viewportSize > objectMax) { |
- objectMin = objectMax - viewportSize; |
- } else { |
- objectMin = subfocusMin; |
- objectMax = subfocusMin + viewportSize; |
- } |
+ // Compute the size of an object centered on the subfocus, the size of the viewport. |
+ int centeredObjectMin = (subfocusMin + subfocusMax - viewportSize) / 2; |
+ int centeredObjectMax = centeredObjectMin + viewportSize; |
+ |
+ objectMin = std::max(objectMin, centeredObjectMin); |
+ objectMax = std::min(objectMax, centeredObjectMax); |
} |
// Exit now if the focus is already within the viewport. |
@@ -705,18 +730,8 @@ static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int |
&& objectMax - currentScrollOffset <= viewportMax) |
return currentScrollOffset; |
- // Scroll left if we're too far to the right. |
- if (objectMax - currentScrollOffset > viewportMax) |
- return objectMax - viewportMax; |
- |
- // Scroll right if we're too far to the left. |
- if (objectMin - currentScrollOffset < viewportMin) |
- return objectMin - viewportMin; |
- |
- ASSERT_NOT_REACHED(); |
- |
- // This shouldn't happen. |
- return currentScrollOffset; |
+ // Center the object in the viewport. |
+ return (objectMin + objectMax - viewportMin - viewportMax) / 2; |
} |
void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const |
@@ -750,9 +765,16 @@ void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const |
scrollParent->scrollTo(IntPoint(desiredX, desiredY)); |
+ // Convert the subfocus into the coordinates of the scroll parent. |
+ IntRect newSubfocus = subfocus; |
+ IntRect newElementRect = pixelSnappedIntRect(elementRect()); |
+ IntRect scrollParentRect = pixelSnappedIntRect(scrollParent->elementRect()); |
+ newSubfocus.move(newElementRect.x(), newElementRect.y()); |
+ newSubfocus.move(-scrollParentRect.x(), -scrollParentRect.y()); |
+ |
// Recursively make sure the scroll parent itself is visible. |
if (scrollParent->parentObject()) |
- scrollParent->scrollToMakeVisible(); |
+ scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus); |
} |
void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const |