nsresult HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = false; if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) { return NS_OK; } // Track whether we're in the outermost Dispatch invocation that will // cause activation of the input. That is, if we're a click event, or a // DOMActivate that was dispatched directly, this will be set, but if we're // a DOMActivate dispatched from click handling, it will not be set. WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); bool outerActivateEvent = ((mouseEvent && mouseEvent->IsLeftClickEvent()) || (aVisitor.mEvent->mMessage == eLegacyDOMActivate && !mInInternalActivate)); if (outerActivateEvent) { aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT; if (mType == NS_FORM_BUTTON_SUBMIT && mForm) { aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK; // tell the form that we are about to enter a click handler. // that means that if there are scripted submissions, the // latest one will be deferred until after the exit point of the handler. mForm->OnSubmitClickBegin(this); } } return nsGenericHTMLElement::GetEventTargetParent(aVisitor); }
void HTMLImageElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) { // We handle image element with attribute ismap in its corresponding frame // element. Set mMultipleActionsPrevented here to prevent the click event // trigger the behaviors in Element::PostHandleEventForLinks WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) { mouseEvent->mFlags.mMultipleActionsPrevented = true; } nsGenericHTMLElement::GetEventTargetParent(aVisitor); }
nsresult HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { // If we are a map and get a mouse click, don't let it be handled by // the Generic Element as this could cause a click event to fire // twice, once by the image frame for the map and once by the Anchor // element. (bug 39723) WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) { aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } return nsGenericHTMLElement::PreHandleEvent(aVisitor); }
nsresult nsAutoRepeatBoxFrame::HandleEvent(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } switch(aEvent->mMessage) { // repeat mode may be "hover" for repeating while the mouse is hovering // over the element, otherwise repetition is done while the element is // active (pressed). case eMouseEnterIntoWidget: case eMouseOver: if (IsActivatedOnHover()) { StartRepeat(); mTrustedEvent = aEvent->IsTrusted(); } break; case eMouseExitFromWidget: case eMouseOut: // always stop on mouse exit StopRepeat(); // Not really necessary but do this to be safe mTrustedEvent = false; break; case eMouseClick: { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (mouseEvent->IsLeftClickEvent()) { // skip button frame handling to prevent click handling return nsBoxFrame::HandleEvent(aPresContext, mouseEvent, aEventStatus); } break; } default: break; } return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); }
nsresult nsResizerFrame::HandleEvent(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } nsWeakFrame weakFrame(this); bool doDefault = true; switch (aEvent->mMessage) { case eTouchStart: case eMouseDown: { if (aEvent->mClass == eTouchEventClass || (aEvent->mClass == eMouseEventClass && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsIContent* contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); if (contentToResize) { nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); if (!frameToResize) break; // cache the content rectangle for the frame to resize // GetScreenRectInAppUnits returns the border box rectangle, so // adjust to get the desired content rectangle. nsRect rect = frameToResize->GetScreenRectInAppUnits(); switch (frameToResize->StylePosition()->mBoxSizing) { case StyleBoxSizing::Content: rect.Deflate(frameToResize->GetUsedPadding()); MOZ_FALLTHROUGH; case StyleBoxSizing::Padding: rect.Deflate(frameToResize->GetUsedBorder()); MOZ_FALLTHROUGH; case StyleBoxSizing::Border: // nothing break; } mMouseDownRect = LayoutDeviceIntRect::FromAppUnitsToNearest(rect, aPresContext->AppUnitsPerDevPixel()); doDefault = false; } else { // If there is no window, then resizing isn't allowed. if (!window) break; doDefault = false; // ask the widget implementation to begin a resize drag if it can Direction direction = GetDirection(); nsresult rv = aEvent->mWidget->BeginResizeDrag(aEvent, direction.mHorizontal, direction.mVertical); // for native drags, don't set the fields below if (rv != NS_ERROR_NOT_IMPLEMENTED) break; // if there's no native resize support, we need to do window // resizing ourselves window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y, &mMouseDownRect.width, &mMouseDownRect.height); } // remember current mouse coordinates LayoutDeviceIntPoint refPoint; if (!GetEventPoint(aEvent, refPoint)) return NS_OK; mMouseDownPoint = refPoint + aEvent->mWidget->WidgetToScreenOffset(); // we're tracking mTrackingMouseMove = true; nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); } } break; case eTouchEnd: case eMouseUp: { if (aEvent->mClass == eTouchEventClass || (aEvent->mClass == eMouseEventClass && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) { // we're done tracking. mTrackingMouseMove = false; nsIPresShell::SetCapturingContent(nullptr, 0); doDefault = false; } } break; case eTouchMove: case eMouseMove: { if (mTrackingMouseMove) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsCOMPtr<nsIContent> contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); // check if the returned content really is a menupopup nsMenuPopupFrame* menuPopupFrame = nullptr; if (contentToResize) { menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame()); } // both MouseMove and direction are negative when pointing to the // top and left, and positive when pointing to the bottom and right // retrieve the offset of the mousemove event relative to the mousedown. // The difference is how much the resize needs to be LayoutDeviceIntPoint refPoint; if (!GetEventPoint(aEvent, refPoint)) return NS_OK; LayoutDeviceIntPoint screenPoint = refPoint + aEvent->mWidget->WidgetToScreenOffset(); LayoutDeviceIntPoint mouseMove(screenPoint - mMouseDownPoint); // Determine which direction to resize by checking the dir attribute. // For windows and menus, ensure that it can be resized in that direction. Direction direction = GetDirection(); if (window || menuPopupFrame) { if (menuPopupFrame) { menuPopupFrame->CanAdjustEdges( (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT, (direction.mVertical == -1) ? NS_SIDE_TOP : NS_SIDE_BOTTOM, mouseMove); } } else if (!contentToResize) { break; // don't do anything if there's nothing to resize } LayoutDeviceIntRect rect = mMouseDownRect; // Check if there are any size constraints on this window. widget::SizeConstraints sizeConstraints; if (window) { nsCOMPtr<nsIWidget> widget; window->GetMainWidget(getter_AddRefs(widget)); sizeConstraints = widget->GetSizeConstraints(); } AdjustDimensions(&rect.x, &rect.width, sizeConstraints.mMinSize.width, sizeConstraints.mMaxSize.width, mouseMove.x, direction.mHorizontal); AdjustDimensions(&rect.y, &rect.height, sizeConstraints.mMinSize.height, sizeConstraints.mMaxSize.height, mouseMove.y, direction.mVertical); // Don't allow resizing a window or a popup past the edge of the screen, // so adjust the rectangle to fit within the available screen area. if (window) { nsCOMPtr<nsIScreen> screen; nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1")); if (sm) { nsIntRect frameRect = GetScreenRect(); // ScreenForRect requires display pixels, so scale from device pix double scale; window->GetUnscaledDevicePixelsPerCSSPixel(&scale); sm->ScreenForRect(NSToIntRound(frameRect.x / scale), NSToIntRound(frameRect.y / scale), 1, 1, getter_AddRefs(screen)); if (screen) { LayoutDeviceIntRect screenRect; screen->GetRect(&screenRect.x, &screenRect.y, &screenRect.width, &screenRect.height); rect.IntersectRect(rect, screenRect); } } } else if (menuPopupFrame) { nsRect frameRect = menuPopupFrame->GetScreenRectInAppUnits(); nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame(); nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits(); nsPopupLevel popupLevel = menuPopupFrame->PopupLevel(); int32_t appPerDev = aPresContext->AppUnitsPerDevPixel(); LayoutDeviceIntRect screenRect = menuPopupFrame->GetConstraintRect (LayoutDeviceIntRect::FromAppUnitsToNearest(frameRect, appPerDev), // round using ...ToInside as it's better to be a pixel too small // than be too large. If the popup is too large it could get flipped // to the opposite side of the anchor point while resizing. LayoutDeviceIntRect::FromAppUnitsToInside(rootScreenRect, appPerDev), popupLevel); rect.IntersectRect(rect, screenRect); } if (contentToResize) { // convert the rectangle into css pixels. When changing the size in a // direction, don't allow the new size to be less that the resizer's // size. This ensures that content isn't resized too small as to make // the resizer invisible. nsRect appUnitsRect = ToAppUnits(rect.ToUnknownRect(), aPresContext->AppUnitsPerDevPixel()); if (appUnitsRect.width < mRect.width && mouseMove.x) appUnitsRect.width = mRect.width; if (appUnitsRect.height < mRect.height && mouseMove.y) appUnitsRect.height = mRect.height; nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel()); LayoutDeviceIntRect oldRect; nsWeakFrame weakFrame(menuPopupFrame); if (menuPopupFrame) { nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); if (widget) widget->GetScreenBounds(oldRect); // convert the new rectangle into outer window coordinates LayoutDeviceIntPoint clientOffset = widget->GetClientOffset(); rect.x -= clientOffset.x; rect.y -= clientOffset.y; } SizeInfo sizeInfo, originalSizeInfo; sizeInfo.width.AppendInt(cssRect.width); sizeInfo.height.AppendInt(cssRect.height); ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo); MaybePersistOriginalSize(contentToResize, originalSizeInfo); // Move the popup to the new location unless it is anchored, since // the position shouldn't change. nsMenuPopupFrame::SetPopupPosition // will instead ensure that the popup's position is anchored at the // right place. if (weakFrame.IsAlive() && (oldRect.x != rect.x || oldRect.y != rect.y) && (!menuPopupFrame->IsAnchored() || menuPopupFrame->PopupLevel() != ePopupLevelParent)) { CSSPoint cssPos = rect.TopLeft() / aPresContext->CSSToDevPixelScale(); menuPopupFrame->MoveTo(RoundedToInt(cssPos), true); } } else { window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, true); // do the repaint. } doDefault = false; } } break; case eMouseClick: { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (mouseEvent->IsLeftClickEvent()) { MouseClicked(mouseEvent); } break; } case eMouseDoubleClick: if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { nsCOMPtr<nsIBaseWindow> window; nsIPresShell* presShell = aPresContext->GetPresShell(); nsIContent* contentToResize = GetContentToResize(presShell, getter_AddRefs(window)); if (contentToResize) { nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame()); if (menuPopupFrame) break; // Don't restore original sizing for menupopup frames until // we handle screen constraints here. (Bug 357725) RestoreOriginalSize(contentToResize); } } break; default: break; } if (!doDefault) *aEventStatus = nsEventStatus_eConsumeNoDefault; if (doDefault && weakFrame.IsAlive()) return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus); return NS_OK; }
nsresult HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { nsresult rv = NS_OK; if (!aVisitor.mPresContext) { return rv; } if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent()) { // DOMActive event should be trusted since the activation is actually // occurred even if the cause is an untrusted click event. InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent); actEvent.mDetail = 1; nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell(); if (shell) { nsEventStatus status = nsEventStatus_eIgnore; mInInternalActivate = true; shell->HandleDOMEventWithTarget(this, &actEvent, &status); mInInternalActivate = false; // If activate is cancelled, we must do the same as when click is // cancelled (revert the checkbox to its original value). if (status == nsEventStatus_eConsumeNoDefault) { aVisitor.mEventStatus = status; } } } } // mForm is null if the event handler removed us from the document (bug 194582). if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // tell the form that we are about to exit a click handler // so the form knows not to defer subsequent submissions // the pending ones that were created during the handler // will be flushed or forgoten. mForm->OnSubmitClickEnd(); } if (nsEventStatus_eIgnore == aVisitor.mEventStatus) { switch (aVisitor.mEvent->mMessage) { case eKeyPress: case eKeyUp: { // For backwards compat, trigger buttons with space or enter // (bug 25300) WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); if ((keyEvent->mKeyCode == NS_VK_RETURN && eKeyPress == aVisitor.mEvent->mMessage) || (keyEvent->mKeyCode == NS_VK_SPACE && eKeyUp == aVisitor.mEvent->mMessage)) { DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(), aVisitor.mPresContext); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break; default: break; } if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) { if (mForm && (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET)) { InternalFormEvent event(true, (mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit); event.mOriginator = this; nsEventStatus status = nsEventStatus_eIgnore; nsCOMPtr<nsIPresShell> presShell = aVisitor.mPresContext->GetPresShell(); // If |nsIPresShell::Destroy| has been called due to // handling the event, the pres context will return // a null pres shell. See bug 125624. // // Using presShell to dispatch the event. It makes sure that // event is not handled if the window is being destroyed. if (presShell && (event.mMessage != eFormSubmit || mForm->SubmissionCanProceed(this))) { // TODO: removing this code and have the submit event sent by the form // see bug 592124. // Hold a strong ref while dispatching RefPtr<HTMLFormElement> form(mForm); presShell->HandleDOMEventWithTarget(form, &event, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } } } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // Tell the form to flush a possible pending submission. // the reason is that the script returned false (the event was // not ignored) so if there is a stored submission, it needs to // be submitted immediatelly. // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event. mForm->FlushPendingSubmission(); } //if return rv; }
nsresult HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mHandlingEvent || (!(mouseEvent && mouseEvent->IsLeftClickEvent()) && aVisitor.mEvent->mMessage != eMouseDown) || aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || !aVisitor.mPresContext || // Don't handle the event if it's already been handled by another label aVisitor.mEvent->mFlags.mMultipleActionsPrevented) { return NS_OK; } nsCOMPtr<nsIContent> target = do_QueryInterface(aVisitor.mEvent->target); if (InInteractiveHTMLContent(target, this)) { return NS_OK; } // Strong ref because event dispatch is going to happen. RefPtr<Element> content = GetLabeledElement(); if (content) { mHandlingEvent = true; switch (aVisitor.mEvent->mMessage) { case eMouseDown: if (mouseEvent->button == WidgetMouseEvent::eLeftButton) { // We reset the mouse-down point on every event because there is // no guarantee we will reach the eMouseClick code below. LayoutDeviceIntPoint* curPoint = new LayoutDeviceIntPoint(mouseEvent->refPoint); SetProperty(nsGkAtoms::labelMouseDownPtProperty, static_cast<void*>(curPoint), nsINode::DeleteProperty<LayoutDeviceIntPoint>); } break; case eMouseClick: if (mouseEvent->IsLeftClickEvent()) { LayoutDeviceIntPoint* mouseDownPoint = static_cast<LayoutDeviceIntPoint*>( GetProperty(nsGkAtoms::labelMouseDownPtProperty)); bool dragSelect = false; if (mouseDownPoint) { LayoutDeviceIntPoint dragDistance = *mouseDownPoint; DeleteProperty(nsGkAtoms::labelMouseDownPtProperty); dragDistance -= mouseEvent->refPoint; const int CLICK_DISTANCE = 2; dragSelect = dragDistance.x > CLICK_DISTANCE || dragDistance.x < -CLICK_DISTANCE || dragDistance.y > CLICK_DISTANCE || dragDistance.y < -CLICK_DISTANCE; } // Don't click the for-content if we did drag-select text or if we // have a kbd modifier (which adjusts a selection). if (dragSelect || mouseEvent->IsShift() || mouseEvent->IsControl() || mouseEvent->IsAlt() || mouseEvent->IsMeta()) { break; } // Only set focus on the first click of multiple clicks to prevent // to prevent immediate de-focus. if (mouseEvent->clickCount <= 1) { nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { // Use FLAG_BYMOVEFOCUS here so that the label is scrolled to. // Also, within HTMLInputElement::PostHandleEvent, inputs will // be selected only when focused via a key or when the navigation // flag is used and we want to select the text on label clicks as // well. // If the label has been clicked by the user, we also want to // pass FLAG_BYMOUSE so that we get correct focus ring behavior, // but we don't want to pass FLAG_BYMOUSE if this click event was // caused by the user pressing an accesskey. nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content); bool byMouse = (mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD); bool byTouch = (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH); fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS | (byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) | (byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0)); } } // Dispatch a new click event to |content| // (For compatibility with IE, we do only left click. If // we wanted to interpret the HTML spec very narrowly, we // would do nothing. If we wanted to do something // sensible, we might send more events through like // this.) See bug 7554, bug 49897, and bug 96813. nsEventStatus status = aVisitor.mEventStatus; // Ok to use aVisitor.mEvent as parameter because DispatchClickEvent // will actually create a new event. EventFlags eventFlags; eventFlags.mMultipleActionsPrevented = true; DispatchClickEvent(aVisitor.mPresContext, mouseEvent, content, false, &eventFlags, &status); // Do we care about the status this returned? I don't think we do... // Don't run another <label> off of this click mouseEvent->mFlags.mMultipleActionsPrevented = true; } break; default: break; } mHandlingEvent = false; } return NS_OK; }
nsresult nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } bool doDefault = true; switch (aEvent->message) { case NS_MOUSE_BUTTON_DOWN: { if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { // titlebar has no effect in non-chrome shells nsCOMPtr<nsIDocShellTreeItem> dsti = aPresContext->GetDocShell(); if (dsti) { if (dsti->ItemType() == nsIDocShellTreeItem::typeChrome) { // we're tracking. mTrackingMouseMove = true; // start capture. nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); // remember current mouse coordinates. mLastPoint = aEvent->refPoint; } } *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = false; } } break; case NS_MOUSE_BUTTON_UP: { if (mTrackingMouseMove && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { // we're done tracking. mTrackingMouseMove = false; // end capture nsIPresShell::SetCapturingContent(nullptr, 0); *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = false; } } break; case NS_MOUSE_MOVE: { if(mTrackingMouseMove) { LayoutDeviceIntPoint nsMoveBy = aEvent->refPoint - mLastPoint; nsIFrame* parent = GetParent(); while (parent) { nsMenuPopupFrame* popupFrame = do_QueryFrame(parent); if (popupFrame) break; parent = parent->GetParent(); } // if the titlebar is in a popup, move the popup frame, otherwise // move the widget associated with the window if (parent) { nsMenuPopupFrame* menuPopupFrame = static_cast<nsMenuPopupFrame*>(parent); nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); nsIntRect bounds; widget->GetScreenBounds(bounds); int32_t newx = aPresContext->DevPixelsToIntCSSPixels(bounds.x + nsMoveBy.x); int32_t newy = aPresContext->DevPixelsToIntCSSPixels(bounds.y + nsMoveBy.y); menuPopupFrame->MoveTo(newx, newy, false); } else { nsIPresShell* presShell = aPresContext->PresShell(); nsPIDOMWindow *window = presShell->GetDocument()->GetWindow(); if (window) { window->MoveBy(nsMoveBy.x, nsMoveBy.y); } } *aEventStatus = nsEventStatus_eConsumeNoDefault; doDefault = false; } } break; case NS_MOUSE_CLICK: { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (mouseEvent->IsLeftClickEvent()) { MouseClicked(aPresContext, mouseEvent); } break; } } if ( doDefault ) return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); else return NS_OK; }
nsresult nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } switch (aEvent->message) { case NS_KEY_DOWN: { WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); if (!keyEvent) { break; } if (NS_VK_SPACE == keyEvent->keyCode) { EventStateManager* esm = aPresContext->EventStateManager(); // :hover:active state esm->SetContentState(mContent, NS_EVENT_STATE_HOVER); esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE); mIsHandlingKeyEvent = true; } break; } // On mac, Return fires the default button, not the focused one. #ifndef XP_MACOSX case NS_KEY_PRESS: { WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); if (!keyEvent) { break; } if (NS_VK_RETURN == keyEvent->keyCode) { nsCOMPtr<nsIDOMXULButtonElement> buttonEl(do_QueryInterface(mContent)); if (buttonEl) { MouseClicked(aPresContext, aEvent); *aEventStatus = nsEventStatus_eConsumeNoDefault; } } break; } #endif case NS_KEY_UP: { WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); if (!keyEvent) { break; } if (NS_VK_SPACE == keyEvent->keyCode) { mIsHandlingKeyEvent = false; // only activate on keyup if we're already in the :hover:active state NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?"); EventStates buttonState = mContent->AsElement()->State(); if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) { // return to normal state EventStateManager* esm = aPresContext->EventStateManager(); esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER); MouseClicked(aPresContext, aEvent); } } break; } case NS_MOUSE_CLICK: { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (mouseEvent->IsLeftClickEvent()) { MouseClicked(aPresContext, mouseEvent); } break; } } return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); }
nsresult HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { nsresult rv = NS_OK; if (!aVisitor.mPresContext) { return rv; } if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent()) { // XXX Activating actually occurs even if it's caused by untrusted event. // Therefore, shouldn't this be always trusted event? InternalUIEvent actEvent(aVisitor.mEvent->mFlags.mIsTrusted, NS_UI_ACTIVATE); actEvent.detail = 1; nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell(); if (shell) { nsEventStatus status = nsEventStatus_eIgnore; mInInternalActivate = true; shell->HandleDOMEventWithTarget(this, &actEvent, &status); mInInternalActivate = false; // If activate is cancelled, we must do the same as when click is // cancelled (revert the checkbox to its original value). if (status == nsEventStatus_eConsumeNoDefault) { aVisitor.mEventStatus = status; } } } } // mForm is null if the event handler removed us from the document (bug 194582). if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // tell the form that we are about to exit a click handler // so the form knows not to defer subsequent submissions // the pending ones that were created during the handler // will be flushed or forgoten. mForm->OnSubmitClickEnd(); } if (nsEventStatus_eIgnore == aVisitor.mEventStatus) { switch (aVisitor.mEvent->message) { case NS_KEY_PRESS: case NS_KEY_UP: { // For backwards compat, trigger buttons with space or enter // (bug 25300) WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); if ((keyEvent->keyCode == NS_VK_RETURN && NS_KEY_PRESS == aVisitor.mEvent->message) || (keyEvent->keyCode == NS_VK_SPACE && NS_KEY_UP == aVisitor.mEvent->message)) { nsEventStatus status = nsEventStatus_eIgnore; WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK, nullptr, WidgetMouseEvent::eReal); event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; EventDispatcher::Dispatch(static_cast<nsIContent*>(this), aVisitor.mPresContext, &event, nullptr, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break;// NS_KEY_PRESS case NS_MOUSE_BUTTON_DOWN: { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent->button == WidgetMouseEvent::eLeftButton) { if (mouseEvent->mFlags.mIsTrusted) { EventStateManager* esm = aVisitor.mPresContext->EventStateManager(); EventStateManager::SetActiveManager( static_cast<EventStateManager*>(esm), this); } nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) fm->SetFocus(this, nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL); mouseEvent->mFlags.mMultipleActionsPrevented = true; } else if (mouseEvent->button == WidgetMouseEvent::eMiddleButton || mouseEvent->button == WidgetMouseEvent::eRightButton) { // cancel all of these events for buttons //XXXsmaug What to do with these events? Why these should be cancelled? if (aVisitor.mDOMEvent) { aVisitor.mDOMEvent->StopPropagation(); } } } break; // cancel all of these events for buttons //XXXsmaug What to do with these events? Why these should be cancelled? case NS_MOUSE_BUTTON_UP: case NS_MOUSE_DOUBLECLICK: { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (aVisitor.mDOMEvent && (mouseEvent->button == WidgetMouseEvent::eMiddleButton || mouseEvent->button == WidgetMouseEvent::eRightButton)) { aVisitor.mDOMEvent->StopPropagation(); } } break; case NS_MOUSE_ENTER_SYNTH: { aVisitor.mPresContext->EventStateManager()-> SetContentState(this, NS_EVENT_STATE_HOVER); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } break; // XXX this doesn't seem to do anything yet case NS_MOUSE_EXIT_SYNTH: { aVisitor.mPresContext->EventStateManager()-> SetContentState(nullptr, NS_EVENT_STATE_HOVER); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } break; default: break; } if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) { if (mForm && (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET)) { InternalFormEvent event(true, (mType == NS_FORM_BUTTON_RESET) ? NS_FORM_RESET : NS_FORM_SUBMIT); event.originator = this; nsEventStatus status = nsEventStatus_eIgnore; nsCOMPtr<nsIPresShell> presShell = aVisitor.mPresContext->GetPresShell(); // If |nsIPresShell::Destroy| has been called due to // handling the event, the pres context will return // a null pres shell. See bug 125624. // // Using presShell to dispatch the event. It makes sure that // event is not handled if the window is being destroyed. if (presShell && (event.message != NS_FORM_SUBMIT || mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || // We know the element is a submit control, if this check is moved, // make sure formnovalidate is used only if it's a submit control. HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) || mForm->CheckValidFormSubmission())) { // TODO: removing this code and have the submit event sent by the form // see bug 592124. // Hold a strong ref while dispatching nsRefPtr<HTMLFormElement> form(mForm); presShell->HandleDOMEventWithTarget(mForm, &event, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } } } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // Tell the form to flush a possible pending submission. // the reason is that the script returned false (the event was // not ignored) so if there is a stored submission, it needs to // be submitted immediatelly. // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event. mForm->FlushPendingSubmission(); } //if return rv; }
nsresult HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { nsresult rv = NS_OK; if (!aVisitor.mPresContext) { return rv; } if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent()) { // DOMActive event should be trusted since the activation is actually // occurred even if the cause is an untrusted click event. InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent); actEvent.mDetail = 1; nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell(); if (shell) { nsEventStatus status = nsEventStatus_eIgnore; mInInternalActivate = true; shell->HandleDOMEventWithTarget(this, &actEvent, &status); mInInternalActivate = false; // If activate is cancelled, we must do the same as when click is // cancelled (revert the checkbox to its original value). if (status == nsEventStatus_eConsumeNoDefault) { aVisitor.mEventStatus = status; } } } } // mForm is null if the event handler removed us from the document (bug 194582). if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // tell the form that we are about to exit a click handler // so the form knows not to defer subsequent submissions // the pending ones that were created during the handler // will be flushed or forgoten. mForm->OnSubmitClickEnd(); } if (nsEventStatus_eIgnore == aVisitor.mEventStatus) { switch (aVisitor.mEvent->mMessage) { case eKeyPress: case eKeyUp: { // For backwards compat, trigger buttons with space or enter // (bug 25300) WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); if ((keyEvent->mKeyCode == NS_VK_RETURN && eKeyPress == aVisitor.mEvent->mMessage) || (keyEvent->mKeyCode == NS_VK_SPACE && eKeyUp == aVisitor.mEvent->mMessage)) { DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(), aVisitor.mPresContext); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break; case eMouseDown: { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent->button == WidgetMouseEvent::eLeftButton) { if (mouseEvent->IsTrusted()) { EventStateManager* esm = aVisitor.mPresContext->EventStateManager(); EventStateManager::SetActiveManager( static_cast<EventStateManager*>(esm), this); } nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { uint32_t flags = nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL; // If this was a touch-generated event, pass that information: if (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { flags |= nsIFocusManager::FLAG_BYTOUCH; } fm->SetFocus(this, flags); } mouseEvent->mFlags.mMultipleActionsPrevented = true; } else if (mouseEvent->button == WidgetMouseEvent::eMiddleButton || mouseEvent->button == WidgetMouseEvent::eRightButton) { // cancel all of these events for buttons //XXXsmaug What to do with these events? Why these should be cancelled? if (aVisitor.mDOMEvent) { aVisitor.mDOMEvent->StopPropagation(); } } } break; // cancel all of these events for buttons //XXXsmaug What to do with these events? Why these should be cancelled? case eMouseUp: case eMouseDoubleClick: { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (aVisitor.mDOMEvent && (mouseEvent->button == WidgetMouseEvent::eMiddleButton || mouseEvent->button == WidgetMouseEvent::eRightButton)) { aVisitor.mDOMEvent->StopPropagation(); } } break; case eMouseOver: { aVisitor.mPresContext->EventStateManager()-> SetContentState(this, NS_EVENT_STATE_HOVER); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } break; // XXX this doesn't seem to do anything yet case eMouseOut: { aVisitor.mPresContext->EventStateManager()-> SetContentState(nullptr, NS_EVENT_STATE_HOVER); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } break; default: break; } if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) { if (mForm && (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET)) { InternalFormEvent event(true, (mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit); event.mOriginator = this; nsEventStatus status = nsEventStatus_eIgnore; nsCOMPtr<nsIPresShell> presShell = aVisitor.mPresContext->GetPresShell(); // If |nsIPresShell::Destroy| has been called due to // handling the event, the pres context will return // a null pres shell. See bug 125624. // // Using presShell to dispatch the event. It makes sure that // event is not handled if the window is being destroyed. if (presShell && (event.mMessage != eFormSubmit || mForm->SubmissionCanProceed(this))) { // TODO: removing this code and have the submit event sent by the form // see bug 592124. // Hold a strong ref while dispatching RefPtr<HTMLFormElement> form(mForm); presShell->HandleDOMEventWithTarget(form, &event, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } } } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // Tell the form to flush a possible pending submission. // the reason is that the script returned false (the event was // not ignored) so if there is a stored submission, it needs to // be submitted immediatelly. // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event. mForm->FlushPendingSubmission(); } //if return rv; }