Bug 372797, Convert ScrollFrameIntoView users to use ScrollContentIntoView, r+sr=roc

This commit is contained in:
Olli.Pettay%helsinki.fi 2007-03-07 19:08:36 +00:00
Родитель 66fcf7555c
Коммит baadb13165
14 изменённых файлов: 115 добавлений и 183 удалений

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

@ -363,9 +363,12 @@ nsAccessNode::ScrollTo(PRBool aTopLeft)
nsIFrame *frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
nsCOMPtr<nsIContent> content = frame->GetContent();
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
PRInt32 percent = aTopLeft ? NS_PRESSHELL_SCROLL_TOP :
NS_PRESSHELL_SCROLL_ANYWHERE;
return shell->ScrollFrameIntoView(frame, percent, percent);
return shell->ScrollContentIntoView(content, percent, percent);
}
nsresult

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

@ -1667,31 +1667,29 @@ nsEventListenerManager::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
nsCOMPtr<nsIContent> content(do_QueryInterface(node));
for ( ; content; content = content->GetParent()) {
if (!content->IsNativeAnonymous()) {
// It seems like selCon->ScrollSelectionIntoView should be enough, but it's
// not. The problem is that scrolling the selection into view when it is
// below the current viewport will align the top line of the frame exactly
// with the bottom of the window. This is fine, BUT, the popup event causes
// the control to be re-focused which does this exact call to
// ScrollContentIntoView, which has a one-pixel disagreement of whether the
// frame is actually in view. The result is that the frame is aligned with
// the top of the window, but the menu is still at the bottom.
//
// Doing this call first forces the frame to be in view, eliminating the
// problem. The only difference in the result is that if your cursor is in
// an edit box below the current view, you'll get the edit box aligned with
// the top of the window. This is arguably better behavior anyway.
rv = aShell->ScrollContentIntoView(content,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
frame = aShell->GetPrimaryFrameFor(content);
NS_ASSERTION(frame, "No frame for focused content?");
break;
}
}
// It seems like selCon->ScrollSelectionIntoView should be enough, but it's
// not. The problem is that scrolling the selection into view when it is
// below the current viewport will align the top line of the frame exactly
// with the bottom of the window. This is fine, BUT, the popup event causes
// the control to be re-focused which does this exact call to
// ScrollFrameIntoView, which has a one-pixel disagreement of whether the
// frame is actually in view. The result is that the frame is aligned with
// the top of the window, but the menu is still at the bottom.
//
// Doing this call first forces the frame to be in view, eliminating the
// problem. The only difference in the result is that if your cursor is in
// an edit box below the current view, you'll get the edit box aligned with
// the top of the window. This is arguably better behavior anyway.
if (frame) {
rv = aShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
}
// Actually scroll the selection (ie caret) into view. Note that this must
// be synchronous since we will be checking the caret position on the screen.
//
@ -1744,11 +1742,11 @@ nsEventListenerManager::GetCoordinatesFor(nsIDOMElement *aCurrentEl,
nsPoint& aTargetPt)
{
nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl));
aPresShell->ScrollContentIntoView(focusedContent,
NS_PRESSHELL_SCROLL_ANYWHERE,
NS_PRESSHELL_SCROLL_ANYWHERE);
nsIFrame *frame = aPresShell->GetPrimaryFrameFor(focusedContent);
if (frame) {
aPresShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_ANYWHERE,
NS_PRESSHELL_SCROLL_ANYWHERE);
nsPoint frameOrigin(0, 0);
// Get the frame's origin within its view

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

@ -3233,7 +3233,7 @@ nsEventStateManager::ShiftFocusInternal(PRBool aForward, nsIContent* aStart)
// If in content, navigate from last cursor position rather than last focus
// If we're in UI, selection location will return null
nsIPresShell *presShell = mPresContext->PresShell();
nsCOMPtr<nsIPresShell> presShell = mPresContext->PresShell();
// We might use the selection position, rather than mCurrentFocus, as our position to shift focus from
PRInt32 itemType;
@ -3331,9 +3331,9 @@ nsEventStateManager::ShiftFocusInternal(PRBool aForward, nsIContent* aStart)
if (sub_shell) {
// Make sure to scroll before possibly dispatching focus/blur events.
presShell->ScrollFrameIntoView(nextFocusFrame,
NS_PRESSHELL_SCROLL_ANYWHERE,
NS_PRESSHELL_SCROLL_ANYWHERE);
presShell->ScrollContentIntoView(nextFocus,
NS_PRESSHELL_SCROLL_ANYWHERE,
NS_PRESSHELL_SCROLL_ANYWHERE);
SetContentState(nsnull, NS_EVENT_STATE_FOCUS);

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

@ -1771,7 +1771,7 @@ nsGenericHTMLElement::GetFormControlFrameFor(nsIContent* aContent,
if (aFlushContent) {
// Cause a flush of content, so we get up-to-date frame
// information
aDocument->FlushPendingNotifications(Flush_Frames);
aDocument->FlushPendingNotifications(Flush_Layout);
}
nsIFrame* frame = GetPrimaryFrameFor(aContent, aDocument);
if (frame) {
@ -3039,6 +3039,23 @@ nsGenericHTMLFormElement::IntrinsicState() const
return state;
}
void
nsGenericHTMLFormElement::SetFocusAndScrollIntoView(nsPresContext* aPresContext)
{
nsIEventStateManager *esm = aPresContext->EventStateManager();
if (esm->SetContentState(this, NS_EVENT_STATE_FOCUS)) {
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
nsCOMPtr<nsIPresShell> presShell = aPresContext->GetPresShell();
if (presShell) {
presShell->ScrollContentIntoView(this, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
}
}
}
}
//----------------------------------------------------------------------
nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()

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

@ -830,6 +830,8 @@ protected:
virtual PRInt32 IntrinsicState() const;
void SetFocusAndScrollIntoView(nsPresContext* aPresContext);
/** The form that contains this control */
nsIForm* mForm;
};

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

@ -263,14 +263,7 @@ nsHTMLButtonElement::SetFocus(nsPresContext* aPresContext)
return;
}
nsIEventStateManager *esm = aPresContext->EventStateManager();
if (esm->SetContentState(this, NS_EVENT_STATE_FOCUS)) {
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
nsLayoutUtils::ScrollIntoView(formControlFrame);
}
}
SetFocusAndScrollIntoView(aPresContext);
}
static const nsAttrValue::EnumTable kButtonTypeTable[] = {

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

@ -1173,14 +1173,7 @@ nsHTMLInputElement::SetFocus(nsPresContext* aPresContext)
}
}
nsIEventStateManager *esm = aPresContext->EventStateManager();
if (esm->SetContentState(this, NS_EVENT_STATE_FOCUS)) {
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
nsLayoutUtils::ScrollIntoView(formControlFrame);
}
}
SetFocusAndScrollIntoView(aPresContext);
}
NS_IMETHODIMP

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

@ -1616,14 +1616,7 @@ nsHTMLSelectElement::SetFocus(nsPresContext* aPresContext)
return;
}
nsIEventStateManager *esm = aPresContext->EventStateManager();
if (esm->SetContentState(this, NS_EVENT_STATE_FOCUS)) {
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
nsLayoutUtils::ScrollIntoView(formControlFrame);
}
}
SetFocusAndScrollIntoView(aPresContext);
}
PRBool

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

@ -308,14 +308,7 @@ nsHTMLTextAreaElement::SetFocus(nsPresContext* aPresContext)
}
}
nsIEventStateManager *esm = aPresContext->EventStateManager();
if (esm->SetContentState(this, NS_EVENT_STATE_FOCUS)) {
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
nsLayoutUtils::ScrollIntoView(formControlFrame);
}
}
SetFocusAndScrollIntoView(aPresContext);
}
NS_IMETHODIMP

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

@ -811,19 +811,12 @@ nsSpatialNavigation::setFocusedContent(nsIContent* c)
//#ifdef OLDER_LAYOUT
nsPresContext* presContext = getPresContext(c);
nsIPresShell *presShell = presContext->PresShell();
nsIFrame* frame = presShell->GetPrimaryFrameFor(c);
if (frame) {
presContext->EventStateManager()->SetContentState(c, NS_EVENT_STATE_FOCUS);
presShell->ScrollFrameIntoView(frame,
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
presContext->EventStateManager()->SetContentState(c, NS_EVENT_STATE_FOCUS);
presShell->ScrollContentIntoView(c,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
presContext->EventStateManager()->MoveCaretToFocus();
}
presContext->EventStateManager()->MoveCaretToFocus();
//#else
nsCOMPtr<nsIDOMNSHTMLElement> nsElement = do_QueryInterface(element);

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

@ -98,12 +98,12 @@ class nsIScrollableFrame;
typedef short SelectionType;
// 2fc67850-eb32-404a-8f84-52e2fe8f6356
// c37fd598-ed7f-4f39-bdf9-96642c691c7b
#define NS_IPRESSHELL_IID \
{ 0x2fc67850, 0xeb32, 0x404a, \
{ 0x8f, 0x84, 0x52, 0xe2, 0xfe, 0x8f, 0x63, 0x56 } }
{ 0xc37fd598, 0xed7f, 0x4f39, \
{ 0xbd, 0xf9, 0x96, 0x64, 0x2c, 0x69, 0x1c, 0x7b } }
// Constants for ScrollFrameIntoView() and ScrollContentIntoView() functions.
// Constants for ScrollContentIntoView() function
#define NS_PRESSHELL_SCROLL_TOP 0
#define NS_PRESSHELL_SCROLL_BOTTOM 100
#define NS_PRESSHELL_SCROLL_LEFT 0
@ -405,43 +405,33 @@ public:
NS_IMETHOD GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) = 0;
/**
* Scrolls the view of the document so that the frame is displayed at the
* top of the window.
* Scrolls the view of the document so that the primary frame of the content
* is displayed at the top of the window. Layout is flushed before scrolling.
*
* @param aFrame The frame to scroll into view
* @param aContent The content object of which primary frame should be
* scrolled into view.
* @param aVPercent How to align the frame vertically. A value of 0
* (NS_PRESSHELL_SCROLL_TOP) means the frame's upper edge is
* aligned with the top edge of the visible area. A value of
* 100 (NS_PRESSHELL_SCROLL_BOTTOM) means the frame's bottom
* edge is aligned with the bottom edge of the visible area.
* For values in between, the point "aVPercent" down the frame
* is placed at the point "aVPercent" down the visible area. A
* value of 50 (NS_PRESSHELL_SCROLL_CENTER) centers the frame
* vertically. A value of NS_PRESSHELL_SCROLL_ANYWHERE means move
* the frame the minimum amount necessary in order for the entire
* frame to be visible vertically (if possible)
* (NS_PRESSHELL_SCROLL_TOP) means the frame's upper edge is
* aligned with the top edge of the visible area. A value of
* 100 (NS_PRESSHELL_SCROLL_BOTTOM) means the frame's bottom
* edge is aligned with the bottom edge of the visible area.
* For values in between, the point "aVPercent" down the frame
* is placed at the point "aVPercent" down the visible area. A
* value of 50 (NS_PRESSHELL_SCROLL_CENTER) centers the frame
* vertically. A value of NS_PRESSHELL_SCROLL_ANYWHERE means move
* the frame the minimum amount necessary in order for the entire
* frame to be visible vertically (if possible)
* @param aHPercent How to align the frame horizontally. A value of 0
* (NS_PRESSHELL_SCROLL_LEFT) means the frame's left edge is
* aligned with the left edge of the visible area. A value of
* 100 (NS_PRESSHELL_SCROLL_RIGHT) means the frame's right
* edge is aligned with the right edge of the visible area.
* For values in between, the point "aVPercent" across the frame
* is placed at the point "aVPercent" across the visible area.
* A value of 50 (NS_PRESSHELL_SCROLL_CENTER) centers the frame
* horizontally . A value of NS_PRESSHELL_SCROLL_ANYWHERE means move
* the frame the minimum amount necessary in order for the entire
* frame to be visible horizontally (if possible)
*/
NS_IMETHOD ScrollFrameIntoView(nsIFrame *aFrame,
PRIntn aVPercent,
PRIntn aHPercent) const = 0;
/**
* Otherwise same as the above, but takes an aContent as the first parameter
* and after flushing pending notifications tries to find primary frame
* for that and then call ScrollFrameIntoView.
* @param aContent The content object of which primary frame should be
* scrolled into view.
* (NS_PRESSHELL_SCROLL_LEFT) means the frame's left edge is
* aligned with the left edge of the visible area. A value of
* 100 (NS_PRESSHELL_SCROLL_RIGHT) means the frame's right
* edge is aligned with the right edge of the visible area.
* For values in between, the point "aVPercent" across the frame
* is placed at the point "aVPercent" across the visible area.
* A value of 50 (NS_PRESSHELL_SCROLL_CENTER) centers the frame
* horizontally . A value of NS_PRESSHELL_SCROLL_ANYWHERE means move
* the frame the minimum amount necessary in order for the entire
* frame to be visible horizontally (if possible)
*/
NS_IMETHOD ScrollContentIntoView(nsIContent* aContent,
PRIntn aVPercent,

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

@ -1040,23 +1040,6 @@ nsLayoutUtils::BinarySearchForPosition(nsIRenderingContext* aRendContext,
return PR_FALSE;
}
void
nsLayoutUtils::ScrollIntoView(nsIFormControlFrame* aFormFrame)
{
NS_ASSERTION(aFormFrame, "Null frame passed into ScrollIntoView");
nsIFrame* frame = nsnull;
CallQueryInterface(aFormFrame, &frame);
NS_ASSERTION(frame, "Form frame did not implement nsIFrame.");
if (frame) {
nsIPresShell* presShell = frame->GetPresContext()->GetPresShell();
if (presShell) {
presShell->ScrollFrameIntoView(frame,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
}
}
}
nsRect
nsLayoutUtils::GetAllInFlowBoundingRect(nsIFrame* aFrame)
{

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

@ -449,12 +449,6 @@ public:
PRInt32& aIndex,
PRInt32& aTextWidth);
/**
* Scroll the given form control frame into view.
* @param aFormFrame Frame to scroll into view.
*/
static void ScrollIntoView(nsIFormControlFrame* aFormFrame);
/**
* Get the union of all rects in aFrame and its continuations, relative
* to aFrame's origin. Scrolling is taken into account, but this shouldn't

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

@ -121,7 +121,7 @@
#include "nsILayoutHistoryState.h"
#include "nsIScrollPositionListener.h"
#include "nsICompositeListener.h"
#include "nsILineIterator.h" // for ScrollFrameIntoView
#include "nsILineIterator.h" // for ScrollContentIntoView
#include "nsTimer.h"
#include "nsWeakPtr.h"
#include "plarena.h"
@ -855,10 +855,6 @@ public:
nsIRenderingContext** aContext);
NS_IMETHOD GoToAnchor(const nsAString& aAnchorName, PRBool aScroll);
NS_IMETHOD ScrollFrameIntoView(nsIFrame *aFrame,
PRIntn aVPercent,
PRIntn aHPercent) const;
NS_IMETHOD ScrollContentIntoView(nsIContent* aContent,
PRIntn aVPercent,
PRIntn aHPercent) const;
@ -3926,11 +3922,17 @@ static void ScrollViewToShowRect(nsIScrollableView* aScrollingView,
}
NS_IMETHODIMP
PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
PRIntn aVPercent,
PRIntn aHPercent) const
PresShell::ScrollContentIntoView(nsIContent* aContent,
PRIntn aVPercent,
PRIntn aHPercent) const
{
if (!aFrame) {
nsCOMPtr<nsIContent> content = aContent; // Keep content alive while flushing.
NS_ENSURE_TRUE(content, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDocument> currentDoc = content->GetCurrentDoc();
NS_ENSURE_STATE(currentDoc);
currentDoc->FlushPendingNotifications(Flush_Layout);
nsIFrame* frame = GetPrimaryFrameFor(content);
if (!frame) {
return NS_ERROR_NULL_POINTER;
}
@ -3942,27 +3944,18 @@ PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
// is not for the anchor link to scroll back into view. That is what
// this check is preventing.
// XXX: The dependency on the command dispatcher needs to be fixed.
nsIContent* content = aFrame->GetContent();
if (content) {
nsIDocument* document = content->GetDocument();
if (document){
nsPIDOMWindow *ourWindow = document->GetWindow();
if(ourWindow) {
nsIFocusController *focusController =
ourWindow->GetRootFocusController();
if (focusController) {
PRBool dontScroll;
focusController->GetSuppressFocusScroll(&dontScroll);
if(dontScroll)
return NS_OK;
}
nsPIDOMWindow* ourWindow = currentDoc->GetWindow();
if(ourWindow) {
nsIFocusController *focusController = ourWindow->GetRootFocusController();
if (focusController) {
PRBool dontScroll = PR_FALSE;
focusController->GetSuppressFocusScroll(&dontScroll);
if(dontScroll) {
return NS_OK;
}
}
}
// Flush out pending reflows to make sure we scroll to the right place
mDocument->FlushPendingNotifications(Flush_OnlyReflow);
// This is a two-step process.
// Step 1: Find the bounds of the rect we want to scroll into view. For
// example, for an inline frame we may want to scroll in the whole
@ -3970,10 +3963,10 @@ PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
// Step 2: Walk the views that are parents of the frame and scroll them
// appropriately.
nsRect frameBounds = aFrame->GetRect();
nsRect frameBounds = frame->GetRect();
nsPoint offset;
nsIView* closestView;
aFrame->GetOffsetFromView(offset, &closestView);
frame->GetOffsetFromView(offset, &closestView);
frameBounds.MoveTo(offset);
// If this is an inline frame and either the bounds height is 0 (quirks
@ -3981,20 +3974,20 @@ PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
// change the top of the bounds to include the whole line.
if (frameBounds.height == 0 || aVPercent != NS_PRESSHELL_SCROLL_ANYWHERE) {
nsIAtom* frameType = NULL;
nsIFrame *prevFrame = aFrame;
nsIFrame *frame = aFrame;
nsIFrame *prevFrame = frame;
nsIFrame *f = frame;
while (frame &&
(frameType = frame->GetType()) == nsGkAtoms::inlineFrame) {
prevFrame = frame;
frame = prevFrame->GetParent();
while (f &&
(frameType = f->GetType()) == nsGkAtoms::inlineFrame) {
prevFrame = f;
f = prevFrame->GetParent();
}
if (frame != aFrame &&
frame &&
if (f != frame &&
f &&
frameType == nsGkAtoms::blockFrame) {
// find the line containing aFrame and increase the top of |offset|.
nsCOMPtr<nsILineIterator> lines( do_QueryInterface(frame) );
nsCOMPtr<nsILineIterator> lines(do_QueryInterface(f));
if (lines) {
PRInt32 index = -1;
@ -4009,7 +4002,7 @@ PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
lineBounds, &trash3))) {
nsPoint blockOffset;
nsIView* blockView;
frame->GetOffsetFromView(blockOffset, &blockView);
f->GetOffsetFromView(blockOffset, &blockView);
if (blockView == closestView) {
// XXX If views not equal, this is hard. Do we want to bother?
@ -4047,19 +4040,6 @@ PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
return NS_OK;
}
NS_IMETHODIMP
PresShell::ScrollContentIntoView(nsIContent* aContent,
PRIntn aVPercent,
PRIntn aHPercent) const
{
nsCOMPtr<nsIContent> content = aContent; // Keep content alive while flushing.
NS_ENSURE_TRUE(content, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDocument> currentDoc = content->GetCurrentDoc();
NS_ENSURE_STATE(currentDoc);
currentDoc->FlushPendingNotifications(Flush_Layout);
return ScrollFrameIntoView(GetPrimaryFrameFor(content), aVPercent, aHPercent);
}
// GetLinkLocation: copy link location to clipboard
NS_IMETHODIMP PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString)
{