--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head>
+</head>
+<body>
+<p><b>BUG ID:</b> <a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=9984">Bugzilla bug 9984</a> ASSERTION FAILURE: _private->mouseDownEvent != nil (WebKit/WebView/WebHTMLView.m:4863 -[WebHTMLView(WebInternal) _delegateDragSourceActionMask])</p>
+
+<p id="test" style="background-color:skyblue; padding:3px;"><b>STEPS TO TEST:</b>
+Open this test in a new Safari window. In the new window, click once on the text “Click me”. Do not click
+anywhere else in the window before clicking the text.
+</p>
+
+<p id="success" style="background-color:palegreen; padding:3px;"><b>TEST PASS:</b>
+The text will be deselected.
+</p>
+
+<p id="failure" style="background-color:#FF3300; padding:3px;"><b>TEST FAIL:</b>
+An assertion failure will occur.
+</p>
+
+<iframe id="frame"></iframe>
+<script>
+ var win = window['frame'];
+ var doc = win.document;
+ doc.write("<p id='target'>Click me</p>");
+ var target = doc.getElementById('target');
+ win.getSelection().setBaseAndExtent(target, 0, target, 1);
+</script>
+
+</body>
+</html>
- (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString;
- (DOMRange *)_documentRange;
- (WebFrameBridge *)_bridge;
+- (void)_setMouseDownEvent:(NSEvent *)event;
@end
@interface WebHTMLView (WebForwardDeclaration) // FIXME: Put this in a normal category and stop doing the forward declaration trick.
}
}
+- (void)_setMouseDownEvent:(NSEvent *)event
+{
+ ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
+
+ if (event == _private->mouseDownEvent)
+ return;
+
+ [event retain];
+ [_private->mouseDownEvent release];
+ _private->mouseDownEvent = event;
+
+ [_private->firstResponderTextViewAtMouseDownTime release];
+
+ // The only code that checks this ivar only cares about NSTextViews. The code used to be more general,
+ // but it caused reference cycles leading to world leaks (see 4557386). We should be able to eliminate
+ // firstResponderTextViewAtMouseDownTime entirely when all the form controls are native widgets, because
+ // the only caller (in WebCore) will be unnecessary.
+ if (event) {
+ NSResponder *firstResponder = [[self window] firstResponder];
+ if ([firstResponder isKindOfClass:[NSTextView class]])
+ _private->firstResponderTextViewAtMouseDownTime = [firstResponder retain];
+ else
+ _private->firstResponderTextViewAtMouseDownTime = nil;
+ } else
+ _private->firstResponderTextViewAtMouseDownTime = nil;
+}
+
@end
@implementation WebHTMLView (WebPrivate)
- (BOOL)_startDraggingImage:(NSImage *)wcDragImage at:(NSPoint)wcDragLoc operation:(NSDragOperation)op event:(NSEvent *)mouseDraggedEvent sourceIsDHTML:(BOOL)srcIsDHTML DHTMLWroteData:(BOOL)dhtmlWroteData
{
WebHTMLView *topHTMLView = [self _topHTMLView];
- if (self != topHTMLView)
- return [topHTMLView _startDraggingImage:wcDragImage at:wcDragLoc operation:op event:mouseDraggedEvent sourceIsDHTML:srcIsDHTML DHTMLWroteData:dhtmlWroteData];
+ if (self != topHTMLView) {
+ [topHTMLView _setMouseDownEvent:_private->mouseDownEvent];
+ BOOL result = [topHTMLView _startDraggingImage:wcDragImage at:wcDragLoc operation:op event:mouseDraggedEvent sourceIsDHTML:srcIsDHTML DHTMLWroteData:dhtmlWroteData];
+ [topHTMLView _setMouseDownEvent:nil];
+ return result;
+ }
NSPoint mouseDownPoint = [self convertPoint:[_private->mouseDownEvent locationInWindow] fromView:nil];
NSDictionary *element = [self elementAtPoint:mouseDownPoint allowShadowContent:YES];
return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsSelectedKey] boolValue];
}
-- (void)_setMouseDownEvent:(NSEvent *)event
-{
- ASSERT([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
-
- if (event == _private->mouseDownEvent) {
- return;
- }
-
- [event retain];
- [_private->mouseDownEvent release];
- _private->mouseDownEvent = event;
-
- [_private->firstResponderTextViewAtMouseDownTime release];
-
- // The only code that checks this ivar only cares about NSTextViews. The code used to be more general,
- // but it caused reference cycles leading to world leaks (see 4557386). We should be able to eliminate
- // firstResponderTextViewAtMouseDownTime entirely when all the form controls are native widgets, because
- // the only caller (in WebCore) will be unnecessary.
- NSResponder *firstResponder = [[self window] firstResponder];
- if ([firstResponder isKindOfClass:[NSTextView class]])
- _private->firstResponderTextViewAtMouseDownTime = [firstResponder retain];
- else
- _private->firstResponderTextViewAtMouseDownTime = nil;
-}
-
- (BOOL)acceptsFirstMouse:(NSEvent *)event
{
NSView *hitView = [self _hitViewForEvent:event];
WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
- [hitHTMLView _setMouseDownEvent:event];
if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysAcceptsFirstMouse])
return YES;
if (hitHTMLView != nil) {
+ [hitHTMLView _setMouseDownEvent:event];
[[hitHTMLView _bridge] setActivationEventNumber:[event eventNumber]];
- return [hitHTMLView _isSelectionEvent:event] ? [[hitHTMLView _bridge] eventMayStartDrag:event] : NO;
- } else {
+ BOOL result = [hitHTMLView _isSelectionEvent:event] ? [[hitHTMLView _bridge] eventMayStartDrag:event] : NO;
+ [hitHTMLView _setMouseDownEvent:nil];
+ return result;
+ } else
return [hitView acceptsFirstMouse:event];
- }
}
- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
if (hitHTMLView != nil) {
[hitHTMLView _setMouseDownEvent:event];
- return [hitHTMLView _isSelectionEvent:event] ? [[hitHTMLView _bridge] eventMayStartDrag:event] : NO;
- } else {
+ BOOL result = [hitHTMLView _isSelectionEvent:event] ? [[hitHTMLView _bridge] eventMayStartDrag:event] : NO;
+ [hitHTMLView _setMouseDownEvent:nil];
+ return result;
+ } else
return [hitView shouldDelayWindowOrderingForEvent:event];
- }
}
- (void)mouseDown:(NSEvent *)event
- (void)mouseUp:(NSEvent *)event
{
+ [self _setMouseDownEvent:nil];
+
NSInputManager *currentInputManager = [NSInputManager currentInputManager];
if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
return;
- (unsigned)_delegateDragSourceActionMask
{
+ ASSERT(_private->mouseDownEvent != nil);
WebHTMLView *topHTMLView = [self _topHTMLView];
- if (self != topHTMLView)
- return [topHTMLView _delegateDragSourceActionMask];
+ if (self != topHTMLView) {
+ [topHTMLView _setMouseDownEvent:_private->mouseDownEvent];
+ unsigned result = [topHTMLView _delegateDragSourceActionMask];
+ [topHTMLView _setMouseDownEvent:nil];
+ return result;
+ }
- ASSERT(_private->mouseDownEvent != nil);
WebView *webView = [self _webView];
NSPoint point = [webView convertPoint:[_private->mouseDownEvent locationInWindow] fromView:nil];
_private->dragSourceActionMask = [[webView _UIDelegateForwarder] webView:webView dragSourceActionMaskForPoint:point];