Bug 675865 backout new dragginf for selection handling code from Mozilla8 r=smaug (backed out patches are: bug 552707, bug 644621, bug 670058, bug 670508, bug 671319)

This commit is contained in:
Masayuki Nakano 2011-08-03 12:39:02 +09:00
Родитель bc87676167
Коммит bfc72b90bf
24 изменённых файлов: 363 добавлений и 2525 удалений

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

@ -6198,14 +6198,6 @@ PresShell::Paint(nsIView* aViewToPaint,
void
nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
{
// If SetCapturingContent() is called during dragging mouse for selection,
// we should abort current transaction.
nsRefPtr<nsFrameSelection> fs =
nsFrameSelection::GetMouseDownFrameSelection();
if (fs) {
fs->AbortDragForSelection();
}
NS_IF_RELEASE(gCaptureInfo.mContent);
// only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag

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

@ -933,6 +933,18 @@ nsFrame::GetChildList(nsIAtom* aListName) const
return nsFrameList::EmptyList();
}
static nsIFrame*
GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
{
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
if (capturingContent) {
nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
return activeFrame ? activeFrame : aFrame;
}
return aFrame;
}
PRInt16
nsFrame::DisplaySelection(nsPresContext* aPresContext, PRBool isOkToTurnOn)
{
@ -2039,147 +2051,6 @@ nsFrame::IsSelectable(PRBool* aSelectable, PRUint8* aSelectStyle) const
return NS_OK;
}
nsFrameSelection*
nsFrame::GetFrameSelectionForSelectingByMouse()
{
PRBool selectable;
PRUint8 selectStyle;
nsresult rv = IsSelectable(&selectable, &selectStyle);
NS_ENSURE_SUCCESS(rv, nsnull);
if (!selectable) {
return nsnull;
}
// When implementing NS_STYLE_USER_SELECT_ELEMENT,
// NS_STYLE_USER_SELECT_ELEMENTS and NS_STYLE_USER_SELECT_TOGGLE, need to
// change this logic
PRBool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
// XXX This is screwy; it really should use the selection frame, not the
// event frame
const nsFrameSelection* frameselection =
(selectStyle == NS_STYLE_USER_SELECT_TEXT) ? GetConstFrameSelection() :
PresContext()->PresShell()->ConstFrameSelection();
return const_cast<nsFrameSelection*>(frameselection);
}
/**
* GetContentToCaptureForSelection() returns a content which should capture
* mouse events for aSelectionRoot. E.g., the result is <input type="text">
* if the aSelectionRoot is anonymous div element in the editor.
*/
static nsIContent*
GetContentToCaptureForSelection(nsIContent* aSelectionRoot)
{
return aSelectionRoot->FindFirstNonNativeAnonymous();
}
/**
* GetSelectionRootContentForCapturingContent() returns a selection root
* content for the capturing content. E.g., the result is anonymous div
* element if aCapturingContent is a <input type="text">.
*/
static nsIContent*
GetSelectionRootContentForCapturingContent(nsIPresShell* aPresShell,
nsIContent* aCapturingContent)
{
if (!aCapturingContent->HasIndependentSelection()) {
return aCapturingContent;
}
return aCapturingContent->GetSelectionRootContent(aPresShell);
}
/**
* FindNearestScrollableFrameForSelection() returns the nearest ancestor
* scrollable frame when user is dragging on aFrame.
*
* @param aFrame A frame which the user is dragging on.
* @param aSelectionRoot When this is not NULL, the result is guaranteed that
* the result belongs to the same selection root.
* For example, when aFrame is in <input type="text">
* but user is selecting outside of the <input>:
* * If aSelectionRoot is NULL, this returns the
* selection root frame of the <input>.
* * Otherwise, e.g., aSelectionRoot is the root
* element of the document, the result is the
* nearest ancestor scrollable element of the
* <input> element.
*
* @return The nearest ancestor scrollable frame for aFrame.
* If it was not found, returns NULL.
*/
static nsIScrollableFrame*
FindNearestScrollableFrameForSelection(nsIFrame* aFrame,
nsIContent* aSelectionRoot = nsnull)
{
#ifdef DEBUG
nsFrameSelection* draggingFrameSelection =
nsFrameSelection::GetMouseDownFrameSelection();
NS_ASSERTION(!draggingFrameSelection ||
draggingFrameSelection == aFrame->GetConstFrameSelection(),
"aFrame must be in dragging nsFrameSelection");
#endif
PRBool foundCapturingContent = PR_FALSE;
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
// If the specified selection root content is capturing content,
// that might be different from the computed selection root. Then, we should
// replace aSelectionRoot with its computed selection root.
if (aSelectionRoot && aSelectionRoot == capturingContent) {
nsIFrame* selectionRootFrame = aSelectionRoot->GetPrimaryFrame();
NS_ENSURE_TRUE(selectionRootFrame, nsnull);
nsIPresShell* ps = selectionRootFrame->PresContext()->PresShell();
aSelectionRoot = aSelectionRoot->GetSelectionRootContent(ps);
}
nsIScrollableFrame* lastScrollableFrame = nsnull;
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
do {
nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame);
if (!scrollableFrame || !scrollableFrame->GetScrolledFrame()) {
break; // non-scrollable frame.
}
if (aSelectionRoot) {
// If aSelectionRoot isn't null, find a scrollable frame whose
// selection root is the same as aSelectionRoot.
nsIContent* content = frame->GetContent();
if (!content) {
break;
}
nsIPresShell* ps = frame->PresContext()->PresShell();
if (content->GetSelectionRootContent(ps) != aSelectionRoot) {
break;
}
}
lastScrollableFrame = scrollableFrame;
// If the scrollable frame has independent selection, we should return it
// even if it's not actually scrollable.
if (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) {
return scrollableFrame;
}
nsRect range = scrollableFrame->GetScrollRange();
if (range.width == 0 && range.height == 0) {
// The scrollable frame cannot scroll actually. We should look for
// another scrollable frame which can scrollable, however, if there is
// no such frame, we should return top most scrollable frame.
break;
}
return scrollableFrame;
} while (0);
if (frame->GetContent() == capturingContent) {
foundCapturingContent = PR_TRUE;
} else if (foundCapturingContent) {
break; // There is no scrollable frame in the capturing content
}
}
return lastScrollableFrame;
}
/**
* Handles the Mouse Press Event for the frame
*/
@ -2189,8 +2060,6 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
nsEventStatus* aEventStatus)
{
NS_ENSURE_ARG_POINTER(aEventStatus);
NS_ASSERTION(aPresContext == PresContext(),
"HandlePress called with different presContext");
if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
return NS_OK;
}
@ -2228,52 +2097,49 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
}
}
nsFrameSelection* fs = GetFrameSelectionForSelectingByMouse();
if (!fs) {
return NS_OK; // maybe, select: none
}
// check whether style allows selection
// if not, don't tell selection the mouse event even occurred.
PRBool selectable;
PRUint8 selectStyle;
rv = IsSelectable(&selectable, &selectStyle);
if (NS_FAILED(rv)) return rv;
// check for select: none
if (!selectable)
return NS_OK;
// If the mouse is dragged outside the selection root's scrollable area
// When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
// NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
PRBool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
// If the mouse is dragged outside the nearest enclosing scrollable area
// while making a selection, the area will be scrolled. To do this, capture
// the mouse on the selection root frame. However, in table selection mode,
// a nearest scrollable frame should be captured the mouse because each
// scrollable frame except the nearest one doesn't need to scroll during
// selection.
// If something else is already capturing the mouse, the current selection
// root must be the capturing content. However, it might be outside of the
// this frame's selection root content. Then, we should do nothing.
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
PRBool captureMouse = !capturingContent;
NS_ASSERTION(mContent, "mContent must not be null");
nsIContent* selectionRootOfThisFrame =
mContent->GetSelectionRootContent(shell);
NS_ASSERTION(selectionRootOfThisFrame,
"mContent must have a selection root content");
if (capturingContent) {
nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
NS_ENSURE_TRUE(capturingFrame, NS_OK);
nsIPresShell* capturedPresShell =
capturingFrame->PresContext()->PresShell();
NS_ASSERTION(capturedPresShell,
"The captured content must have a presShell");
nsIContent* selectionRootOfCapturedContent =
capturingContent->GetSelectionRootContent(capturedPresShell);
NS_ASSERTION(selectionRootOfCapturedContent,
"The captured content must have a selection root content");
if (selectionRootOfThisFrame != selectionRootOfCapturedContent) {
return NS_OK;
// the mouse on the nearest scrollable frame. If there isn't a scrollable
// frame, or something else is already capturing the mouse, there's no
// reason to capture.
if (!nsIPresShell::GetCapturingContent()) {
nsIFrame* checkFrame = this;
nsIScrollableFrame *scrollFrame = nsnull;
while (checkFrame) {
scrollFrame = do_QueryFrame(checkFrame);
if (scrollFrame) {
nsIPresShell::SetCapturingContent(checkFrame->GetContent(), CAPTURE_IGNOREALLOWED);
break;
}
checkFrame = checkFrame->GetParent();
}
} else {
nsIContent* contentToCaptureForSelection =
GetContentToCaptureForSelection(selectionRootOfThisFrame);
nsIPresShell::SetCapturingContent(contentToCaptureForSelection,
CAPTURE_IGNOREALLOWED);
}
if (fs->GetDisplaySelection() == nsISelectionController::SELECTION_OFF) {
// XXX This is screwy; it really should use the selection frame, not the
// event frame
const nsFrameSelection* frameselection = nsnull;
if (useFrameSelection)
frameselection = GetConstFrameSelection();
else
frameselection = shell->ConstFrameSelection();
if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
return NS_OK;//nothing to do we cannot affect selection from here
}
nsMouseEvent *me = (nsMouseEvent *)aEvent;
@ -2285,12 +2151,13 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
PRBool control = me->isControl;
#endif
nsRefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
if (me->clickCount >1 )
{
// These methods aren't const but can't actually delete anything,
// so no need for nsWeakFrame.
fs->SetMouseDownState(PR_TRUE);
fs->SetMouseDoubleDown(PR_TRUE);
fc->SetMouseDownState(PR_TRUE);
fc->SetMouseDoubleDown(PR_TRUE);
return HandleMultiplePress(aPresContext, aEvent, aEventStatus, control);
}
@ -2304,33 +2171,14 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRInt32 target;
rv = GetDataForTableSelection(fs, shell, me, getter_AddRefs(parentContent),
&contentOffset, &target);
rv = GetDataForTableSelection(frameselection, shell, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(rv) && parentContent)
{
// In table selection mode, a nearest scrollable frame should capture the
// mouse events.
if (captureMouse) {
// NOTE: we must have set a content to capture already. The content is
// selection root of this frame. Therefore, when there is no scrollable
// frame, we don't need to reset the capturing content.
NS_ASSERTION(nsIPresShell::GetCapturingContent() != nsnull,
"Someone must have captured mouse event already");
nsIScrollableFrame* scrollableFrame =
FindNearestScrollableFrameForSelection(this);
if (scrollableFrame) {
nsIFrame* frame = do_QueryFrame(scrollableFrame);
nsIContent* contentToCaptureForTableSelection =
GetContentToCaptureForSelection(frame->GetContent());
nsIPresShell::SetCapturingContent(contentToCaptureForTableSelection,
CAPTURE_IGNOREALLOWED);
}
}
fs->SetMouseDownState(PR_TRUE);
return fs->HandleTableSelection(parentContent, contentOffset, target, me);
fc->SetMouseDownState(PR_TRUE);
return fc->HandleTableSelection(parentContent, contentOffset, target, me);
}
fs->SetDelayedCaretData(0);
fc->SetDelayedCaretData(0);
// Check if any part of this frame is selected, and if the
// user clicked inside the selected region. If so, we delay
@ -2343,8 +2191,8 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
if (isSelected)
{
PRBool inSelection = PR_FALSE;
details =
fs->LookUpSelection(offsets.content, 0, offsets.EndOffset(), PR_FALSE);
details = frameselection->LookUpSelection(offsets.content, 0,
offsets.EndOffset(), PR_FALSE);
//
// If there are any details, check to see if the user clicked
@ -2376,17 +2224,17 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
}
if (inSelection) {
fs->SetMouseDownState(PR_FALSE);
fs->SetDelayedCaretData(me);
fc->SetMouseDownState(PR_FALSE);
fc->SetDelayedCaretData(me);
return NS_OK;
}
}
fs->SetMouseDownState(PR_TRUE);
fc->SetMouseDownState(PR_TRUE);
// Do not touch any nsFrame members after this point without adding
// weakFrame checks.
rv = fs->HandleClick(offsets.content, offsets.StartOffset(),
rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
offsets.EndOffset(), me->isShift, control,
offsets.associateWithNext);
@ -2394,7 +2242,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
return rv;
if (offsets.offset != offsets.secondaryOffset)
fs->MaintainSelection();
fc->MaintainSelection();
if (isEditor && !me->isShift &&
(offsets.EndOffset() - offsets.StartOffset()) == 1)
@ -2404,7 +2252,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
// -moz-user-select: all or a non-text node without children).
// Therefore, disable selection extension during mouse moves.
// XXX This is a bit hacky; shouldn't editor be able to deal with this?
fs->SetMouseDownState(PR_FALSE);
fc->SetMouseDownState(PR_FALSE);
}
return rv;
@ -2556,67 +2404,46 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
return frameSelection->MaintainSelection(aAmountBack);
}
NS_IMETHODIMP
nsFrame::HandleDrag(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
nsFrame* target;
nsRefPtr<nsFrameSelection> fs =
FindDraggingFrameSelection(aPresContext->PresShell(), &target);
if (!fs || !target || IsSelectionOff()) {
return NS_OK; // not selecting now
PRBool selectable;
PRUint8 selectStyle;
IsSelectable(&selectable, &selectStyle);
// XXX Do we really need to exclude non-selectable content here?
// GetContentOffsetsFromPoint can handle it just fine, although some
// other stuff might not like it.
if (!selectable)
return NS_OK;
if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
return NS_OK;
}
nsIPresShell *presShell = aPresContext->PresShell();
NS_ASSERTION(target->PresContext()->PresShell() == fs->GetShell(),
"A different presShell received mouse move event during drag");
nsRefPtr<nsFrameSelection> frameselection = GetFrameSelection();
PRBool mouseDown = frameselection->GetMouseDownState();
if (!mouseDown)
return NS_OK;
// Stop auto scrolling, first.
fs->StopAutoScrollTimer();
return target->ExpandSelectionByMouseMove(fs, fs->GetShell(),
static_cast<nsMouseEvent*>(aEvent),
aEventStatus);
}
static const char kPrefName_EdgeWidth[] =
"layout.selection.drag.autoscroll.edge_width";
static const char kPrefName_EdgeScrollAmount[] =
"layout.selection.drag.autoscroll.edge_scroll_amount";
nsresult
nsFrame::ExpandSelectionByMouseMove(nsFrameSelection* aFrameSelection,
nsIPresShell* aPresShell,
nsMouseEvent* aEvent,
nsEventStatus* aEventStatus)
{
#ifdef DEBUG
nsFrameSelection* draggingFrameSelection =
nsFrameSelection::GetMouseDownFrameSelection();
nsFrameSelection* selectionFrameForSelectingByMouse =
GetFrameSelectionForSelectingByMouse();
NS_ASSERTION(draggingFrameSelection,
"dragging FrameSelection must not be NULL");
NS_ASSERTION(draggingFrameSelection == selectionFrameForSelectingByMouse,
"aFrameSelection must be handling current drag for selection");
#endif
frameselection->StopAutoScrollTimer();
// Check if we are dragging in a table cell
nsCOMPtr<nsIContent> parentContent;
PRInt32 contentOffset;
PRInt32 target;
nsresult rv = GetDataForTableSelection(aFrameSelection, aPresShell,
aEvent, getter_AddRefs(parentContent),
&contentOffset, &target);
PRBool handleTableSelection = NS_SUCCEEDED(rv) && parentContent;
nsMouseEvent *me = (nsMouseEvent *)aEvent;
nsresult result;
result = GetDataForTableSelection(frameselection, presShell, me,
getter_AddRefs(parentContent),
&contentOffset, &target);
nsWeakFrame weakThis = this;
if (handleTableSelection) {
aFrameSelection->HandleTableSelection(parentContent, contentOffset,
target, aEvent);
if (NS_SUCCEEDED(result) && parentContent) {
frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
} else {
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
aFrameSelection->HandleDrag(this, pt);
frameselection->HandleDrag(this, pt);
}
// The frameselection object notifies selection listeners synchronously above
@ -2625,332 +2452,175 @@ nsFrame::ExpandSelectionByMouseMove(nsFrameSelection* aFrameSelection,
return NS_OK;
}
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
if (!capturingContent) {
return NS_OK; // The capture was canceled.
}
nsIContent* selectionRoot =
GetSelectionRootContentForCapturingContent(aPresShell, capturingContent);
nsIScrollableFrame* scrollableFrame =
FindNearestScrollableFrameForSelection(this, selectionRoot);
// If a non-scrollable content captures by script and there is no scrollable
// frame between the selection root and this, we don't need to do anymore.
if (!scrollableFrame) {
return NS_OK;
}
const PRUint32 kAutoScrollTimerDelay = 30;
if (!handleTableSelection) {
nsIScrollableFrame* selectionRootScrollableFrame =
FindNearestScrollableFrameForSelection(selectionRoot->GetPrimaryFrame(),
selectionRoot);
while (scrollableFrame) {
nsPoint scrollTo;
if (IsOnScrollableFrameEdge(scrollableFrame, aEvent, scrollTo)) {
aFrameSelection->StartAutoScrollTimer(
scrollableFrame->GetScrolledFrame(), scrollTo, kAutoScrollTimerDelay);
return NS_OK;
}
nsIFrame* frame = do_QueryFrame(scrollableFrame);
scrollableFrame =
FindNearestScrollableFrameForSelection(frame->GetParent(),
selectionRoot);
// get the nearest scrollframe
nsIFrame* checkFrame = this;
nsIScrollableFrame *scrollFrame = nsnull;
while (checkFrame) {
scrollFrame = do_QueryFrame(checkFrame);
if (scrollFrame) {
break;
}
scrollableFrame = selectionRootScrollableFrame;
checkFrame = checkFrame->GetParent();
}
if (!scrollableFrame) {
return NS_OK;
if (scrollFrame) {
nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
if (capturingFrame) {
nsPoint pt =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, capturingFrame);
frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
}
}
nsIFrame* scrolledFrame = scrollableFrame->GetScrolledFrame();
NS_ASSERTION(scrolledFrame,
"The found scrollable frame doesn't have scrolled frame");
nsPoint scrollTo =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, scrolledFrame);
// We should set minimum scroll speed same as the on-edge scrolling speed.
// E.g., while mouse cursor is on the edge, scrolling speed is always same.
nsPoint currentScrollPos = scrollableFrame->GetScrollPosition();
nsRect visibleRectOfScrolledFrame = scrollableFrame->GetScrollPortRect();
visibleRectOfScrolledFrame.MoveTo(currentScrollPos);
if (visibleRectOfScrolledFrame.Contains(scrollTo)) {
return NS_OK; // scroll wouldn't happen actually
}
PRInt32 minAmountPixel =
NS_MAX(Preferences::GetInt(kPrefName_EdgeScrollAmount), 1);
nscoord minAmountApp = PresContext()->DevPixelsToAppUnits(minAmountPixel);
if (visibleRectOfScrolledFrame.x > scrollTo.x) {
scrollTo.x =
NS_MIN(visibleRectOfScrolledFrame.x - minAmountApp, scrollTo.x);
} else if (visibleRectOfScrolledFrame.XMost() < scrollTo.x) {
scrollTo.x =
NS_MAX(visibleRectOfScrolledFrame.XMost() + minAmountApp, scrollTo.x);
}
if (visibleRectOfScrolledFrame.y > scrollTo.y) {
scrollTo.y =
NS_MIN(visibleRectOfScrolledFrame.y - minAmountApp, scrollTo.y);
} else if (visibleRectOfScrolledFrame.YMost() < scrollTo.y) {
scrollTo.y =
NS_MAX(visibleRectOfScrolledFrame.YMost() + minAmountApp, scrollTo.y);
}
aFrameSelection->StartAutoScrollTimer(scrolledFrame, scrollTo,
kAutoScrollTimerDelay);
return NS_OK;
}
nsFrame*
nsFrame::FindSelectableAncestor(nsIFrame* aFrame,
nsFrameSelection* aFrameSelection)
/**
* This static method handles part of the nsFrame::HandleRelease in a way
* which doesn't rely on the nsFrame object to stay alive.
*/
static nsresult
HandleFrameSelection(nsFrameSelection* aFrameSelection,
nsIFrame::ContentOffsets& aOffsets,
PRBool aHandleTableSel,
PRInt32 aContentOffsetForTableSel,
PRInt32 aTargetForTableSel,
nsIContent* aParentContentForTableSel,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
// If we're not selecting by mouse dragging, our ancestor must be selecting,
// so, we should handle it on the first selectable ancestor frame of the
// selecting document.
for (nsIFrame* frame = aFrame; frame;
frame = nsLayoutUtils::GetCrossDocParentFrame(frame)) {
PRBool selectable = PR_FALSE;
if (frame->GetConstFrameSelection() == aFrameSelection &&
NS_SUCCEEDED(frame->IsSelectable(&selectable, nsnull)) &&
selectable) {
nsFrame* result = do_QueryFrame(frame);
if (result) {
return result;
if (!aFrameSelection) {
return NS_OK;
}
nsresult rv = NS_OK;
if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
if (!aHandleTableSel) {
nsMouseEvent *me = aFrameSelection->GetDelayedCaretData();
if (!aOffsets.content || !me) {
return NS_ERROR_FAILURE;
}
// We are doing this to simulate what we would have done on HandlePress.
// We didn't do it there to give the user an opportunity to drag
// the text, but since they didn't drag, we want to place the
// caret.
// However, we'll use the mouse position from the release, since:
// * it's easier
// * that's the normal click position to use (although really, in
// the normal case, small movements that don't count as a drag
// can do selection)
aFrameSelection->SetMouseDownState(PR_TRUE);
rv = aFrameSelection->HandleClick(aOffsets.content,
aOffsets.StartOffset(),
aOffsets.EndOffset(),
me->isShift, PR_FALSE,
aOffsets.associateWithNext);
if (NS_FAILED(rv)) {
return rv;
}
} else if (aParentContentForTableSel) {
aFrameSelection->SetMouseDownState(PR_FALSE);
rv = aFrameSelection->HandleTableSelection(aParentContentForTableSel,
aContentOffsetForTableSel,
aTargetForTableSel,
(nsMouseEvent *)aEvent);
if (NS_FAILED(rv)) {
return rv;
}
}
}
return nsnull;
}
nsFrameSelection*
nsFrame::FindDraggingFrameSelection(nsIPresShell* aPresShell,
nsFrame** aEventTarget)
{
*aEventTarget = nsnull;
nsFrameSelection* fs = nsFrameSelection::GetMouseDownFrameSelection();
if (!fs) {
return nsnull; // not dragging now
}
NS_ASSERTION(fs->GetMouseDownState(),
"Wrong nsFrameSelection was returned by GetMouseDownFrameSelection()");
nsIFrame* selectingFrame = this;
// If this frame is for capturing content and it has independent selection,
// the actual selection root element might be its child or descendant which
// is a native anonymous element.
if (mContent == nsIPresShell::GetCapturingContent()) {
nsIContent* selectionRoot =
GetSelectionRootContentForCapturingContent(aPresShell, mContent);
if (selectionRoot) {
nsIFrame* frame = selectionRoot->GetPrimaryFrame();
if (frame) {
selectingFrame = frame;
}
}
}
*aEventTarget = FindSelectableAncestor(selectingFrame, fs);
if (!*aEventTarget) {
*aEventTarget = this;
}
return fs;
}
PRBool
nsFrame::IsOnScrollableFrameEdge(nsIScrollableFrame* aScrollableFrame,
nsGUIEvent* aEvent,
nsPoint &aScrollIntoView)
{
nsIFrame* scrollableFrame = do_QueryFrame(aScrollableFrame);
nsPoint ptInScrollableFrame =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, scrollableFrame);
nsRect scrollableFrameRect(scrollableFrame->GetRect());
scrollableFrameRect.MoveTo(0, 0);
if (!scrollableFrameRect.Contains(ptInScrollableFrame)) {
return PR_FALSE; // cursor is outside of the frame.
}
nsPoint scrollPosition = aScrollableFrame->GetScrollPosition();
nsRect scrollRange = aScrollableFrame->GetScrollRange();
nsRect scrollPort = aScrollableFrame->GetScrollPortRect();
nsIFrame* scrolledFrame = aScrollableFrame->GetScrolledFrame();
NS_ENSURE_TRUE(scrolledFrame, PR_FALSE);
aScrollIntoView =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, scrolledFrame);
// The edge width (or height) is defined by pref, however, if the value
// is too thick for the frame, we should use 1/4 width (or height) of
// the frame.
nsPresContext* pc = PresContext();
PRInt32 edgePixel = Preferences::GetInt(kPrefName_EdgeWidth);
nscoord edgeApp = pc->DevPixelsToAppUnits(edgePixel);
nscoord onePixel = pc->DevPixelsToAppUnits(1);
nscoord edgeH = NS_MAX(onePixel, NS_MIN(edgeApp, scrollPort.width / 4));
nscoord edgeV = NS_MAX(onePixel, NS_MIN(edgeApp, scrollPort.height / 4));
// The scrolling mouse is defined by pref, however, if the amount is
// too big for the frame, we should use 1/2 width (or height) of the
// frame.
PRInt32 scrollAmountPixel =
NS_MAX(Preferences::GetInt(kPrefName_EdgeScrollAmount), 1);
nscoord scrollAmountApp = pc->DevPixelsToAppUnits(scrollAmountPixel);
nscoord scrollAmountH =
NS_MAX(onePixel, NS_MIN(scrollAmountApp, scrollPort.width / 2));
nscoord scrollAmountV =
NS_MAX(onePixel, NS_MIN(scrollAmountApp, scrollPort.height / 2));
PRBool isOnEdge = PR_FALSE;
if (ptInScrollableFrame.x < scrollPort.x + edgeH) {
if (scrollRange.x < scrollPosition.x) {
// Scroll to left.
aScrollIntoView.x = scrollPosition.x - scrollAmountH;
isOnEdge = PR_TRUE;
}
} else if (ptInScrollableFrame.x > scrollPort.x + scrollPort.width - edgeH) {
if (scrollRange.width > scrollPosition.x) {
// Scroll to right.
aScrollIntoView.x = scrollPosition.x + scrollPort.width + scrollAmountH;
isOnEdge = PR_TRUE;
}
aFrameSelection->SetDelayedCaretData(0);
}
if (ptInScrollableFrame.y < scrollPort.y + edgeV) {
if (scrollRange.y < scrollPosition.y) {
// Scroll to top.
aScrollIntoView.y = scrollPosition.y - scrollAmountV;
isOnEdge = PR_TRUE;
}
} else if (ptInScrollableFrame.y > scrollPort.y + scrollPort.height - edgeV) {
if (scrollRange.height > scrollPosition.y) {
// Scroll to bottom.
aScrollIntoView.y = scrollPosition.y + scrollPort.height + scrollAmountV;
isOnEdge = PR_TRUE;
}
}
return isOnEdge;
}
NS_IMETHODIMP
nsFrame::HandleRelease(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
// NOTE: You don't need to release mouse capture here. It'll be done
// in PresShell automatically. If you need to do it here, you must
// do it after nsFrame::EndSelectionChangeByMouse() because we need
// to call nsFrameSelection::SetMouseDownState(PR_FALSE) first.
// If we release mouse event capture first, it doesn't cause
// MOUSEUP_REASON selection change event.
nsFrame* targetFrame;
nsRefPtr<nsFrameSelection> fs =
FindDraggingFrameSelection(aPresContext->PresShell(), &targetFrame);
if (!fs) {
// If mouse button was pressed on selected text and released without
// mousemove event, there is no dragging frame selection. At that time,
// we need to clean up the pressed state with the frame selection for this
// frame.
fs = GetFrameSelectionForSelectingByMouse();
if (!fs) {
return NS_OK; // maybe, select: none
}
targetFrame = FindSelectableAncestor(this, fs);
if (!targetFrame) {
// XXX At this time, can we just return?
targetFrame = this;
}
}
NS_ASSERTION(targetFrame, "targetFrame must be non-null");
nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
return targetFrame->EndSelectionChangeByMouse(fs, mouseEvent, aEventStatus);
}
nsresult
nsFrame::EndSelectionChangeByMouse(nsFrameSelection* aFrameSelection,
nsMouseEvent* aMouseEvent,
nsEventStatus* aEventStatus)
{
PRBool wasMouseDown = aFrameSelection->GetMouseDownState();
// First, stop expanding selection if necessary
aFrameSelection->SetMouseDownState(PR_FALSE);
aFrameSelection->StopAutoScrollTimer();
if (IsSelectionOff() || nsEventStatus_eConsumeNoDefault == *aEventStatus) {
return NS_OK;
}
// Check if the frameselection recorded the mouse going down.
// If not, the user must have clicked in a part of the selection.
// Place the caret before continuing!
nsresult rv = NS_OK;
nsMouseEvent* delayedEvent = aFrameSelection->GetDelayedCaretData();
if (!wasMouseDown && delayedEvent && delayedEvent->clickCount < 2) {
nsPoint pt =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aMouseEvent, this);
ContentOffsets offsets = GetContentOffsetsFromPoint(pt);
NS_ENSURE_TRUE(offsets.content, NS_ERROR_FAILURE);
// We are doing this to simulate what we would have done on HandlePress.
// We didn't do it there to give the user an opportunity to drag
// the text, but since they didn't drag, we want to place the
// caret.
// However, we'll use the mouse position from the release, since:
// * it's easier
// * that's the normal click position to use (although really, in
// the normal case, small movements that don't count as a drag
// can do selection)
aFrameSelection->SetMouseDownState(PR_TRUE);
// XXX Do not call any methods of the current object after this point!!!
// The object is perhaps dead!
rv = aFrameSelection->HandleClick(offsets.content,
offsets.StartOffset(),
offsets.EndOffset(),
delayedEvent->isShift,
PR_FALSE,
offsets.associateWithNext);
aFrameSelection->SetMouseDownState(PR_FALSE);
aFrameSelection->SetDelayedCaretData(0);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsCOMPtr<nsIContent> parentContent;
PRInt32 contentOffsetForTableSel = 0;
PRInt32 targetForTableSel = 0;
GetDataForTableSelection(aFrameSelection, PresContext()->PresShell(),
aMouseEvent, getter_AddRefs(parentContent),
&contentOffsetForTableSel, &targetForTableSel);
if (parentContent) {
// XXX Do not call any methods of the current object after this point!!!
// The object is perhaps dead!
rv = aFrameSelection->HandleTableSelection(parentContent,
contentOffsetForTableSel,
targetForTableSel,
aMouseEvent);
}
aFrameSelection->SetDelayedCaretData(nsnull);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
PRBool
nsFrame::IsSelectionOff()
NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
NS_ENSURE_TRUE(fs, PR_TRUE);
return (fs->GetDisplaySelection() == nsISelectionController::SELECTION_OFF);
nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
// We can unconditionally stop capturing because
// we should never be capturing when the mouse button is up
nsIPresShell::SetCapturingContent(nsnull, 0);
PRBool selectionOff =
(DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
nsRefPtr<nsFrameSelection> frameselection;
ContentOffsets offsets;
nsCOMPtr<nsIContent> parentContent;
PRInt32 contentOffsetForTableSel = 0;
PRInt32 targetForTableSel = 0;
PRBool handleTableSelection = PR_TRUE;
if (!selectionOff) {
frameselection = GetFrameSelection();
if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
// Check if the frameselection recorded the mouse going down.
// If not, the user must have clicked in a part of the selection.
// Place the caret before continuing!
PRBool mouseDown = frameselection->GetMouseDownState();
nsMouseEvent *me = frameselection->GetDelayedCaretData();
if (!mouseDown && me && me->clickCount < 2) {
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
offsets = GetContentOffsetsFromPoint(pt);
handleTableSelection = PR_FALSE;
} else {
GetDataForTableSelection(frameselection, PresContext()->PresShell(),
(nsMouseEvent *)aEvent,
getter_AddRefs(parentContent),
&contentOffsetForTableSel,
&targetForTableSel);
}
}
}
// We might be capturing in some other document and the event just happened to
// trickle down here. Make sure that document's frame selection is notified.
// Note, this may cause the current nsFrame object to be deleted, bug 336592.
nsRefPtr<nsFrameSelection> frameSelection;
if (activeFrame != this &&
static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
!= nsISelectionController::SELECTION_OFF) {
frameSelection = activeFrame->GetFrameSelection();
}
// Also check the selection of the capturing content which might be in a
// different document.
if (!frameSelection && captureContent) {
nsIDocument* doc = captureContent->GetCurrentDoc();
if (doc) {
nsIPresShell* capturingShell = doc->GetShell();
if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
frameSelection = capturingShell->FrameSelection();
}
}
}
if (frameSelection) {
frameSelection->SetMouseDownState(PR_FALSE);
frameSelection->StopAutoScrollTimer();
}
// Do not call any methods of the current object after this point!!!
// The object is perhaps dead!
return selectionOff
? NS_OK
: HandleFrameSelection(frameselection, offsets, handleTableSelection,
contentOffsetForTableSel, targetForTableSel,
parentContent, aEvent, aEventStatus);
}
struct NS_STACK_CLASS FrameContentRange {

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

@ -599,53 +599,6 @@ protected:
nsIContent **aParentContent, PRInt32 *aContentOffset,
PRInt32 *aTarget);
// Returns nsFrameSelection which is handling drag for selection.
// If it's not dragging for selection, this returns NULL. Otherwise,
// this returns the handling nsFrameSelection and a frame which is ancestor
// and should handle mouse events for selection.
nsFrameSelection* FindDraggingFrameSelection(nsIPresShell* aPresShell,
nsFrame** aEventTarget);
// ExpandSelectionByMouseMove() will expand selection by aEvent.
// This should be called ONLY when the frame is mouse event target which is
// found by FindDraggingFrameSelection(). And aFrameSelection must be the
// drag handling nsFrameSelection.
nsresult ExpandSelectionByMouseMove(nsFrameSelection* aFrameSelection,
nsIPresShell* aPresShell,
nsMouseEvent* aEvent,
nsEventStatus* aEventStatus);
// EndSelectionChangeByMouse() will stop the drag for selection if during
// that. And also cancel the selection if it's clicked on the selection
// range.
// This can be called on every frame. However, if an nsFrameSelection is
// handling drag for selection, this is called on the mouse event target
// frame which is computed by FindDraggingFrameSelection().
// Otherwise, nearest ancestor selectable frame's should be called.
nsresult EndSelectionChangeByMouse(nsFrameSelection* aFrameSelection,
nsMouseEvent* aMouseEvent,
nsEventStatus* aEventStatus);
// IsOnScrollableFrameEdge() checks whether the aEvent is fired on the
// edge of aScrollableFrame and it can be scrolled to the direction of the
// edge. If aEvent is fired on the edge and scrollable, this returns TRUE.
// Otherwise, FALSE. When this returns TRUE, this computes aScrollIntoView.
PRBool IsOnScrollableFrameEdge(nsIScrollableFrame* aScrollableFrame,
nsGUIEvent* aEvent,
nsPoint &aScrollIntoView);
// FindSelectableAncestor() returns a frame which is the nearest selectable
// ancestor of aFrame.
static nsFrame* FindSelectableAncestor(nsIFrame* aFrame,
nsFrameSelection* aFrameSelection);
// Returns nsFrameSelection for selecting by mouse in the frame.
nsFrameSelection* GetFrameSelectionForSelectingByMouse();
// If selection is off, returns TRUE. Otherwise, FALSE.
// This method always uses the frame's nsFrameSelection.
PRBool IsSelectionOff();
// Fills aCursor with the appropriate information from ui
static void FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
nsIFrame::Cursor& aCursor);

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

@ -369,20 +369,6 @@ public:
*/
PRBool GetMouseDownState() const { return mMouseDownState; }
/**
* GetMouseDownedFrameSelection returns an instance which is handling
* mouse dragging.
*/
static nsFrameSelection* GetMouseDownFrameSelection()
{
return sDraggingFrameSelection;
}
/**
* Call AbortDragForSelection() when we abort handling the drag as selecting.
*/
void AbortDragForSelection();
/**
if we are in table cell selection mode. aka ctrl click in table cell
*/
@ -612,7 +598,6 @@ public:
nsFrameSelection();
virtual ~nsFrameSelection();
void StartBatchChanges();
void EndBatchChanges();
@ -621,11 +606,7 @@ public:
nsIPresShell *GetShell()const { return mShell; }
void DisconnectFromPresShell()
{
AbortDragForSelection();
mShell = nsnull;
}
void DisconnectFromPresShell() { StopAutoScrollTimer(); mShell = nsnull; }
private:
nsresult TakeFocus(nsIContent *aNewFocus,
PRUint32 aContentOffset,
@ -715,8 +696,6 @@ private:
nsresult CreateAndAddRange(nsINode *aParentNode, PRInt32 aOffset);
nsresult ClearNormalSelection();
static nsFrameSelection* sDraggingFrameSelection;
nsCOMPtr<nsINode> mCellParent; //used to snap to table selection
nsCOMPtr<nsIContent> mStartSelectedCell;
nsCOMPtr<nsIContent> mEndSelectedCell;

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

@ -141,7 +141,7 @@ static void printRange(nsIRange *aDomRange);
#define DEBUG_OUT_RANGE(x)
#endif //MOZ_DEBUG
nsFrameSelection* nsFrameSelection::sDraggingFrameSelection = nsnull;
//#define DEBUG_SELECTION // uncomment for printf describing every collapse and extend.
//#define DEBUG_NAVIGATION
@ -426,8 +426,7 @@ public:
}
// aPoint is relative to aPresContext's root frame
nsresult Start(nsPresContext *aPresContext, nsIContent *aContent,
nsPoint &aPoint)
nsresult Start(nsPresContext *aPresContext, nsPoint &aPoint)
{
mPoint = aPoint;
@ -435,7 +434,7 @@ public:
// stopped by the selection if the prescontext is destroyed.
mPresContext = aPresContext;
mContent = aContent;
mContent = nsIPresShell::GetCapturingContent();
if (!mTimer)
{
@ -749,13 +748,6 @@ nsFrameSelection::nsFrameSelection()
mSelectionChangeReason = nsISelectionListener::NO_REASON;
}
nsFrameSelection::~nsFrameSelection()
{
if (this == sDraggingFrameSelection) {
sDraggingFrameSelection = nsnull;
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameSelection)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameSelection)
@ -925,10 +917,41 @@ nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(nsIFrame *aFrame,
if (anchorRoot == contentRoot)
{
// The anchor and aFrame's root are the same. There
// is no need to constrain, simply return aFrame.
*aRetFrame = aFrame;
return NS_OK;
// If the aFrame's content isn't the capturing content, it should be
// a descendant. At this time, we can return simply.
nsIContent* capturedContent = nsIPresShell::GetCapturingContent();
if (capturedContent != content)
{
return NS_OK;
}
// Find the frame under the mouse cursor with the root frame.
// At this time, don't use the anchor's frame because it may not have
// fixed positioned frames.
nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
nsPoint ptInRoot = aPoint + aFrame->GetOffsetTo(rootFrame);
nsIFrame* cursorFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
// If the mouse cursor in on a frame which is descendant of same
// selection root, we can expand the selection to the frame.
if (cursorFrame && cursorFrame->PresContext()->PresShell() == mShell)
{
nsIContent* cursorContent = cursorFrame->GetContent();
NS_ENSURE_TRUE(cursorContent, NS_ERROR_FAILURE);
nsIContent* cursorContentRoot =
cursorContent->GetSelectionRootContent(mShell);
NS_ENSURE_TRUE(cursorContentRoot, NS_ERROR_UNEXPECTED);
if (cursorContentRoot == anchorRoot)
{
*aRetFrame = cursorFrame;
aRetPoint = aPoint + aFrame->GetOffsetTo(cursorFrame);
return NS_OK;
}
}
// Otherwise, e.g., the cursor isn't on any frames (e.g., the mouse
// cursor is out of the window), we should use the frame of the anchor
// root.
}
}
@ -1921,40 +1944,16 @@ nsFrameSelection::SetMouseDownState(PRBool aState)
if (mMouseDownState == aState)
return;
NS_ASSERTION((aState && !sDraggingFrameSelection) ||
(!aState && sDraggingFrameSelection),
"Unexpected state happened");
mMouseDownState = aState;
if (mMouseDownState) {
if (sDraggingFrameSelection) {
sDraggingFrameSelection->AbortDragForSelection();
}
sDraggingFrameSelection = this;
} else {
if (sDraggingFrameSelection == this) {
sDraggingFrameSelection = nsnull;
}
if (!mMouseDownState)
{
mDragSelectingCells = PR_FALSE;
PostReason(nsISelectionListener::MOUSEUP_REASON);
NotifySelectionListeners(nsISelectionController::SELECTION_NORMAL); //notify that reason is mouse up please.
}
}
void
nsFrameSelection::AbortDragForSelection()
{
if (sDraggingFrameSelection == this) {
sDraggingFrameSelection = nsnull;
mMouseDownState = PR_FALSE;
mDragSelectingCells = PR_FALSE;
PostReason(nsISelectionListener::NO_REASON);
NotifySelectionListeners(nsISelectionController::SELECTION_NORMAL);
}
StopAutoScrollTimer();
}
nsISelection*
nsFrameSelection::GetSelection(SelectionType aType) const
{
@ -4718,8 +4717,7 @@ nsTypedSelection::DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint)
{
nsPoint presContextPoint = globalPoint -
presContext->PresShell()->FrameManager()->GetRootFrame()->GetOffsetToCrossDoc(rootmostFrame);
mAutoScrollTimer->Start(presContext, aFrame->GetContent(),
presContextPoint);
mAutoScrollTimer->Start(presContext, presContextPoint);
}
return NS_OK;

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

@ -135,12 +135,6 @@ _CHROME_FILES = \
test_backspace_delete.xul \
test_bug514732-2.xul \
file_bug514732_window.xul \
test_selection_scrolling.html \
window_selection_scrolling.html \
test_bug670058.html \
test_bug670508.html \
test_bug671319.html \
test_bug673315-1.html \
$(NULL)
libs:: $(_TEST_FILES)

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

@ -1,52 +0,0 @@
<!DOCTYPE>
<html>
<head>
<title>test for bug 670058</title>
<script type="text/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<textarea id="textarea" style="width: 200px; height: 100px;"></textarea>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var textarea = document.getElementById('textarea');
var x = 50;
var y = 50;
var timer = 0;
function doTest() {
synthesizeMouse(textarea, x, y, { type: "mousedown" });
timer = setInterval(function()
{
if (textarea.style.display == 'block') {
synthesizeMouse(textarea, x++, y++, { type: "mousemove" });
textarea.style.display = '';
} else {
textarea.style.display = 'block';
synthesizeMouse(textarea, x++, y++, { type: "mousemove" });
}
if (x == 70) {
ok(true, "not crashed");
clearInterval(timer);
SimpleTest.finish();
}
}, 200);
}
SimpleTest.waitForFocus(doTest, window);
</script>
</pre>
</body>
</html>

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

@ -1,37 +0,0 @@
<!DOCTYPE>
<html>
<head>
<title>test for bug 670508</title>
<script type="text/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<table>
<tr>
<td id="td" contenteditable="true">
here is an editable table cell
</td>
</tr>
</table>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
function doTest() {
synthesizeMouse(document.getElementById('td'), 5, 5, { ctrlKey: true });
ok(true, "not crashed");
SimpleTest.finish();
}
SimpleTest.waitForFocus(doTest, window);
</script>
</pre>
</body>
</html>

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

@ -1,55 +0,0 @@
<!DOCTYPE>
<html>
<head>
<title>test for bug 671319</title>
<script type="text/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<iframe id="iframe1"
src="data:text/html,&lt;input id='childInput' style='width: 100px; height: 20px;'&gt;"
style="margin: 10px; width: 150px; height: 40px;"></iframe><br>
<iframe id="iframe2"
src="data:text/html,&lt;input id='childInput' style='width: 100px; height: 20px;'&gt;"
style="margin: 10px; width: 150px; height: 40px;"></iframe>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
function doTest() {
var iframe1 = document.getElementById("iframe1");
var childInput1 = iframe1.contentDocument.getElementById("childInput");
var childWindow1 = iframe1.contentWindow;
var iframe2 = document.getElementById("iframe2");
var childInput2 = iframe2.contentDocument.getElementById("childInput");
childInput2.onmousedown = function (aEvent) {
aEvent.preventDefault();
};
childInput2.onmousemove = function (aEvent) {
childInput2.setCapture();
};
var childWindow2 = iframe2.contentWindow;
synthesizeMouse(childInput1, 10, 10, { type: "mousedown", button: 0 }, childWindow1);
iframe1.contentDocument.releaseCapture();
synthesizeMouse(childInput2, 10, 10, { type: "mousedown", button: 0 }, childWindow2);
synthesizeMouse(childInput2, 20, 10, { type: "mousemove" }, childWindow2);
ok(true, "not crashed");
SimpleTest.finish();
}
SimpleTest.waitForFocus(doTest, window);
</script>
</pre>
</body>
</html>

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

@ -1,64 +0,0 @@
<!DOCTYPE>
<html>
<head>
<title>test for bug 673315 part.1</title>
<script type="text/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<p id="p">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</p>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var gSelectionListener = {
reason: 0,
reset: function () { this.reason = 0; },
notifySelectionChanged: function (doc, sel, reason)
{
this.reason |= reason;
}
}
function doTest() {
var p = document.getElementById("p");
const nsISelectionPrivate = Components.interfaces.nsISelectionPrivate;
const nsISelectionListener = Components.interfaces.nsISelectionListener;
var selPrivate =
window.getSelection().QueryInterface(nsISelectionPrivate);
selPrivate.addSelectionListener(gSelectionListener);
gSelectionListener.reset();
synthesizeMouse(p, 10, 10, { type: "mousedown", button: 0 });
is(gSelectionListener.reason,
nsISelectionListener.DRAG_REASON | nsISelectionListener.MOUSEDOWN_REASON,
"the reason isn't drag and mosuedown after mousedown event");
gSelectionListener.reset();
synthesizeMouse(p, 10, 50, { type: "mousemove" });
is(gSelectionListener.reason,
nsISelectionListener.DRAG_REASON | nsISelectionListener.MOUSEDOWN_REASON,
"the reason isn't drag and mosuedown after mousemove event");
gSelectionListener.reset();
synthesizeMouse(p, 10, 50, { type: "mouseup", button: 0 });
is(gSelectionListener.reason,
nsISelectionListener.MOUSEUP_REASON,
"the reason isn't mosueup after mouseup event");
selPrivate.addSelectionListener(gSelectionListener);
SimpleTest.finish();
}
SimpleTest.waitForFocus(doTest, window);
</script>
</pre>
</body>
</html>

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

@ -184,21 +184,28 @@ function test()
// selection starting at div1
synthesizeMouse(div1, 30, 5, { type: "mousedown" });
// XXX if we move the mouse cursor to another document, the
// nsFrameSelection::HandleDrag method is called on the another document's.
// to iframe
synthesizeMouse(iframe, 30, 5, { type: "mousemove" });
check(kTrue, kFalse, kFalse,
check(kTrue | kToDo, kFalse, kFalse,
kFalse, kFalse, kFalse, kFalse, kFalse, kFalse,
"div1-iframe, all boxes are overflow: " + kOverflows[i] + ";");
// XXX if the overflow is visible, synthesizeMouse with the input element
// or textarea element doesn't work fine.
var isVisibleTesting = kOverflows[i] == "visible";
var todoFlag = isVisibleTesting ? kToDo : 0;
// to input
synthesizeMouse(input, 30, 5, { type: "mousemove" });
check(kTrue, kTrue, kFalse,
check(kTrue | todoFlag, kTrue | todoFlag, kFalse,
kFalse, kFalse, kFalse, kFalse, kFalse, kFalse,
"div1-input, all boxes are overflow: " + kOverflows[i] + ";");
// to textarea
synthesizeMouse(textarea, 30, 5, { type: "mousemove" });
check(kTrue, kTrue, kTrue,
check(kTrue | todoFlag, kTrue | todoFlag, kTrue | todoFlag,
kFalse, kFalse, kFalse, kFalse, kFalse, kFalse,
"div1-textarea, all boxes are overflow: " + kOverflows[i] + ";");

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

@ -1,22 +0,0 @@
<!DOCTYPE>
<html>
<head>
<title>selection scrolling test</title>
<script type="text/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
window.open("window_selection_scrolling.html", "_blank",
"top=100,left=100,width=500,height=500,scrollbars=yes");
</script>
</pre>
</body>
</html>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -169,7 +169,7 @@ nsAutoRepeatBoxFrame::HandleRelease(nsPresContext* aPresContext,
if (!IsActivatedOnHover()) {
StopRepeat();
}
return nsButtonBoxFrame::HandleRelease(aPresContext, aEvent, aEventStatus);
return NS_OK;
}
NS_IMETHODIMP

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

@ -82,10 +82,11 @@ nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext,
return NS_OK;
}
if (aEvent->message == NS_MOUSE_EXIT_SYNTH) {
Deactivate();
}
// XXX hack until handle release is actually called in nsframe.
if (aEvent->message == NS_MOUSE_EXIT_SYNTH ||
aEvent->message == NS_MOUSE_BUTTON_UP)
HandleRelease(aPresContext, aEvent, aEventStatus);
// if we didn't handle the press ourselves, pass it on to the superclass
if (!HandleButtonPress(aPresContext, aEvent, aEventStatus))
return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
@ -190,15 +191,10 @@ nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
Deactivate();
return nsButtonBoxFrame::HandleRelease(aPresContext, aEvent, aEventStatus);
}
void
nsScrollbarButtonFrame::Deactivate()
{
// we're not active anymore
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, PR_TRUE);
StopRepeat();
return NS_OK;
}
void nsScrollbarButtonFrame::Notify()

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

@ -81,6 +81,10 @@ public:
nsEventStatus* aEventStatus,
PRBool aControlHeld) { return NS_OK; }
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus) { return NS_OK; }
NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
@ -101,8 +105,6 @@ protected:
}
PRInt32 mIncrement;
void Deactivate();
};
#endif

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

@ -154,6 +154,22 @@ nsScrollbarFrame::HandleMultiplePress(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsScrollbarFrame::HandleDrag(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsScrollbarFrame::HandleRelease(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
return NS_OK;
}
void
nsScrollbarFrame::SetScrollbarMediatorContent(nsIContent* aMediator)
{

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

@ -79,6 +79,14 @@ public:
nsEventStatus* aEventStatus,
PRBool aControlHeld);
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow);

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

@ -587,19 +587,8 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext,
// if (aEvent->message == NS_MOUSE_EXIT_SYNTH || aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP || aEvent->message == NS_MOUSE_LEFT_BUTTON_UP)
// HandleRelease(aPresContext, aEvent, aEventStatus);
if (aEvent->message == NS_MOUSE_EXIT_SYNTH && mChange) {
// XXX This is wrong behavior. We shouldn't stop handling dragging by
// mouseexit event.
// On Windows, can continue to change the value when mouse cursor is
// moved back to the slider button.
// On Linux (GTK), even if the mouse cursor existed from slider button,
// kept to change the value. (confirmed on Ubuntu 10.10)
// On Mac, like Windows, when mouse cursor is moved back to the button,
// restart to change the value. However, Mac's slider can use the other
// direction button too.
HandleRelease(aPresContext, aEvent, aEventStatus);
nsIPresShell::SetCapturingContent(nsnull, 0);
}
if (aEvent->message == NS_MOUSE_EXIT_SYNTH && mChange)
HandleRelease(aPresContext, aEvent, aEventStatus);
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
}
@ -1055,7 +1044,7 @@ nsSliderFrame::HandleRelease(nsPresContext* aPresContext,
{
StopRepeat();
return nsBoxFrame::HandleRelease(aPresContext, aEvent, aEventStatus);
return NS_OK;
}
void

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

@ -148,6 +148,10 @@ public:
nsEventStatus* aEventStatus,
PRBool aControlHeld) { return NS_OK; }
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus) { return NS_OK; }
NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);

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

@ -380,6 +380,22 @@ nsSplitterFrame::HandleMultiplePress(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsSplitterFrame::HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsSplitterFrame::HandleRelease(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsSplitterFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,

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

@ -86,6 +86,14 @@ public:
nsEventStatus* aEventStatus,
PRBool aControlHeld);
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus);

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

@ -1353,20 +1353,6 @@ pref("layout.word_select.stop_at_punctuation", true);
// deletes the selection (Unix default)
pref("layout.selection.caret_style", 0);
// Prefs for auto scrolling by mouse drag. When the mouse cursor is on edge of
// scrollable frame which is a selection root or its descendant, the frame will
// be scrolled.
// |.edge_width| defines the edge width by device pixels.
// |.edge_scroll_amount| defines the scrolling speed by device pixels.
// The auto scroll implementation uses this value for scrolling-to computation.
// When the mouse cursor is on the edge, it tries to scroll the frame to
// this pixels away from the edge.
// I.e., larger value makes faster scroll.
// And also this value is used for the minimum scrolling speed when mouse cursor
// is outside of the selection root element.
pref("layout.selection.drag.autoscroll.edge_width", 32);
pref("layout.selection.drag.autoscroll.edge_scroll_amount", 8);
// pref to control whether or not to replace backslashes with Yen signs
// in documents encoded in one of Japanese legacy encodings (EUC-JP,
// Shift_JIS, ISO-2022-JP)

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

@ -220,13 +220,6 @@ function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
var left = rect.left + aOffsetX;
var top = rect.top + aOffsetY;
// body's bounding client rect depends its scroll position.
var body = aTarget.ownerDocument.body;
if (body == aTarget) {
left += aTarget.scrollLeft;
top += aTarget.scrollTop;
}
if (aEvent.type) {
utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers);
}
@ -289,14 +282,8 @@ function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
var rect = aTarget.getBoundingClientRect();
var left = rect.left + aOffsetX;
var top = rect.top + aOffsetY;
// body's bounding client rect depends its scroll position.
if (aTarget.ownerDocument.body == aTarget) {
left += aTarget.scrollLeft;
top += aTarget.scrollTop;
}
var left = rect.left;
var top = rect.top;
var type = aEvent.type || "DOMMouseScroll";
var axis = aEvent.axis || "vertical";
@ -307,7 +294,7 @@ function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
if (aEvent.isMomentum) {
scrollFlags |= kIsMomentum;
}
utils.sendMouseScrollEvent(type, left, top, button,
utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button,
scrollFlags, aEvent.delta, modifiers);
}
}