Bug 995603 - Ensure mouse-enter/exit events are sent to plugins as appropriate. r=mstange,masayuki

This commit is contained in:
Steven Michaud 2014-04-30 11:55:40 -05:00
parent 115813e446
commit b9f66f47e7
5 changed files with 45 additions and 96 deletions

View File

@ -50,12 +50,8 @@ ContentEventHandler::ContentEventHandler(nsPresContext* aPresContext)
}
nsresult
ContentEventHandler::InitCommon()
ContentEventHandler::InitBasic()
{
if (mSelection) {
return NS_OK;
}
NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE);
// If text frame which has overflowing selection underline is dirty,
@ -65,11 +61,24 @@ ContentEventHandler::InitCommon()
// Flushing notifications can cause mPresShell to be destroyed (bug 577963).
NS_ENSURE_TRUE(!mPresShell->IsDestroying(), NS_ERROR_FAILURE);
return NS_OK;
}
nsresult
ContentEventHandler::InitCommon()
{
if (mSelection) {
return NS_OK;
}
nsresult rv = InitBasic();
NS_ENSURE_SUCCESS(rv, rv);
nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(),
getter_AddRefs(mSelection));
nsCOMPtr<nsIDOMRange> firstRange;
nsresult rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
// This shell doesn't support selection.
if (NS_FAILED(rv)) {
return NS_ERROR_NOT_AVAILABLE;
@ -996,11 +1005,14 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent)
nsresult
ContentEventHandler::OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent)
{
nsresult rv = Init(aEvent);
NS_ASSERTION(aEvent, "aEvent must not be null");
nsresult rv = InitBasic();
if (NS_FAILED(rv)) {
return rv;
}
aEvent->mSucceeded = false;
aEvent->mReply.mWidgetIsHit = false;
NS_ENSURE_TRUE(aEvent->widget, NS_ERROR_FAILURE);

View File

@ -68,7 +68,7 @@ protected:
nsresult Init(WidgetQueryContentEvent* aEvent);
nsresult Init(WidgetSelectionEvent* aEvent);
// InitCommon() is called from each Init().
nsresult InitBasic();
nsresult InitCommon();
public:

View File

@ -3272,6 +3272,31 @@ NSEvent* gLastDragMouseDownEvent = nil;
return mIsPluginView;
}
- (NSView *)hitTest:(NSPoint)aPoint
{
NSView* target = [super hitTest:aPoint];
if ((target == self) && [self isPluginView] && mGeckoChild) {
nsAutoRetainCocoaObject kungFuDeathGrip(self);
NSPoint cocoaLoc = [[self superview] convertPoint:aPoint toView:self];
LayoutDeviceIntPoint widgetLoc = LayoutDeviceIntPoint::FromUntyped(
mGeckoChild->CocoaPointsToDevPixels(cocoaLoc));
WidgetQueryContentEvent hitTest(true, NS_QUERY_DOM_WIDGET_HITTEST,
mGeckoChild);
hitTest.InitForQueryDOMWidgetHittest(widgetLoc);
// This might destroy our widget.
mGeckoChild->DispatchWindowEvent(hitTest);
if (!mGeckoChild) {
return nil;
}
if (hitTest.mSucceeded && !hitTest.mReply.mWidgetIsHit) {
return nil;
}
}
return target;
}
// Are we processing an NSLeftMouseDown event that will fail to click through?
// If so, we shouldn't focus or unfocus a plugin.
- (BOOL)isInFailingLeftClickThrough
@ -5528,67 +5553,12 @@ static int32_t RoundUp(double aDouble)
return !mGeckoChild->DispatchWindowEvent(geckoEvent);
}
// Don't focus a plugin if the user has clicked on a DOM element above it.
// In this case the user has actually clicked on the plugin's ChildView
// (underneath the non-plugin DOM element). But we shouldn't allow the
// ChildView to be focused. See bug 627649.
- (BOOL)currentEventShouldFocusPlugin
{
if (!mGeckoChild)
return NO;
NSEvent* currentEvent = [NSApp currentEvent];
if ([currentEvent type] != NSLeftMouseDown)
return YES;
nsAutoRetainCocoaObject kungFuDeathGrip(self);
// hitTest needs coordinates in device pixels
NSPoint eventLoc = nsCocoaUtils::ScreenLocationForEvent(currentEvent);
eventLoc.y = nsCocoaUtils::FlippedScreenY(eventLoc.y);
LayoutDeviceIntPoint widgetLoc = LayoutDeviceIntPoint::FromUntyped(
mGeckoChild->CocoaPointsToDevPixels(eventLoc) -
mGeckoChild->WidgetToScreenOffset());
WidgetQueryContentEvent hitTest(true, NS_QUERY_DOM_WIDGET_HITTEST,
mGeckoChild);
hitTest.InitForQueryDOMWidgetHittest(widgetLoc);
// This might destroy our widget (and null out mGeckoChild).
mGeckoChild->DispatchWindowEvent(hitTest);
if (!mGeckoChild)
return NO;
if (hitTest.mSucceeded && !hitTest.mReply.mWidgetIsHit)
return NO;
return YES;
}
// Don't focus a plugin if we're in a left click-through that will fail (see
// [ChildView isInFailingLeftClickThrough] above).
- (BOOL)shouldFocusPlugin:(BOOL)getFocus
{
if (!mGeckoChild)
return NO;
nsCocoaWindow* windowWidget = mGeckoChild->GetXULWindowWidget();
if (windowWidget && !windowWidget->ShouldFocusPlugin())
return NO;
if (getFocus && ![self currentEventShouldFocusPlugin])
return NO;
return YES;
}
// Returns NO if the plugin shouldn't be focused/unfocused.
- (BOOL)updatePluginFocusStatus:(BOOL)getFocus
{
if (!mGeckoChild)
return NO;
if (![self shouldFocusPlugin:getFocus])
return NO;
if (mPluginEventModel == NPEventModelCocoa) {
WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, mGeckoChild);
NPCocoaEvent cocoaEvent;

View File

@ -352,9 +352,6 @@ public:
void SetPopupWindowLevel();
bool IsChildInFailingLeftClickThrough(NSView *aChild);
bool ShouldFocusPlugin();
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:

View File

@ -2090,36 +2090,6 @@ void nsCocoaWindow::SetPopupWindowLevel()
}
}
bool nsCocoaWindow::IsChildInFailingLeftClickThrough(NSView *aChild)
{
if ([aChild isKindOfClass:[ChildView class]]) {
ChildView* childView = (ChildView*) aChild;
if ([childView isInFailingLeftClickThrough])
return true;
}
NSArray* subviews = [aChild subviews];
if (subviews) {
NSUInteger count = [subviews count];
for (NSUInteger i = 0; i < count; ++i) {
NSView* aView = (NSView*) [subviews objectAtIndex:i];
if (IsChildInFailingLeftClickThrough(aView))
return true;
}
}
return false;
}
// Don't focus a plugin if we're in a left click-through that will
// fail (see [ChildView isInFailingLeftClickThrough]). Called from
// [ChildView shouldFocusPlugin].
bool nsCocoaWindow::ShouldFocusPlugin()
{
if (!mWindow || IsChildInFailingLeftClickThrough([mWindow contentView]))
return false;
return true;
}
NS_IMETHODIMP
nsCocoaWindow::NotifyIME(const IMENotification& aIMENotification)
{