예제 #1
0
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);
}
예제 #2
0
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);
}
예제 #3
0
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);
}
예제 #4
0
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);
}
예제 #5
0
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;
}
예제 #6
0
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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}
예제 #9
0
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);
}
예제 #10
0
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;
}
예제 #11
0
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;
}