Use TextIndicator instead of the built in Lookup highlight
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / mac / WKView.mm
1 /*
2  * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WKView.h"
28
29 #if PLATFORM(MAC)
30
31 #if USE(DICTATION_ALTERNATIVES)
32 #import <AppKit/NSTextAlternatives.h>
33 #import <AppKit/NSAttributedString.h>
34 #endif
35
36 #import "APIHistoryClient.h"
37 #import "ActionMenuHitTestResult.h"
38 #import "AttributedString.h"
39 #import "ColorSpaceData.h"
40 #import "DataReference.h"
41 #import "EditingRange.h"
42 #import "EditorState.h"
43 #import "LayerTreeContext.h"
44 #import "Logging.h"
45 #import "NativeWebKeyboardEvent.h"
46 #import "NativeWebMouseEvent.h"
47 #import "NativeWebWheelEvent.h"
48 #import "PageClientImpl.h"
49 #import "PasteboardTypes.h"
50 #import "RemoteLayerTreeDrawingAreaProxy.h"
51 #import "StringUtilities.h"
52 #import "TextChecker.h"
53 #import "TextCheckerState.h"
54 #import "TextIndicator.h"
55 #import "TextIndicatorWindow.h"
56 #import "TiledCoreAnimationDrawingAreaProxy.h"
57 #import "ViewGestureController.h"
58 #import "ViewSnapshotStore.h"
59 #import "WKAPICast.h"
60 #import "WKActionMenuController.h"
61 #import "WKActionMenuItemTypes.h"
62 #import "WKFullScreenWindowController.h"
63 #import "WKPrintingView.h"
64 #import "WKProcessPoolInternal.h"
65 #import "WKStringCF.h"
66 #import "WKTextInputWindowController.h"
67 #import "WKViewInternal.h"
68 #import "WKViewPrivate.h"
69 #import "WebBackForwardList.h"
70 #import "WebContext.h"
71 #import "WebEventFactory.h"
72 #import "WebKit2Initialize.h"
73 #import "WebPage.h"
74 #import "WebPageGroup.h"
75 #import "WebPageProxy.h"
76 #import "WebPreferences.h"
77 #import "WebProcessProxy.h"
78 #import "WebSystemInterface.h"
79 #import "_WKThumbnailViewInternal.h"
80 #import <QuartzCore/QuartzCore.h>
81 #import <WebCore/AXObjectCache.h>
82 #import <WebCore/ColorMac.h>
83 #import <WebCore/DragController.h>
84 #import <WebCore/DragData.h>
85 #import <WebCore/FloatRect.h>
86 #import <WebCore/Image.h>
87 #import <WebCore/IntRect.h>
88 #import <WebCore/FileSystem.h>
89 #import <WebCore/KeyboardEvent.h>
90 #import <WebCore/LocalizedStrings.h>
91 #import <WebCore/LookupSPI.h>
92 #import <WebCore/NSViewSPI.h>
93 #import <WebCore/PlatformEventFactoryMac.h>
94 #import <WebCore/PlatformScreen.h>
95 #import <WebCore/Region.h>
96 #import <WebCore/SharedBuffer.h>
97 #import <WebCore/SoftLinking.h>
98 #import <WebCore/TextAlternativeWithRange.h>
99 #import <WebCore/TextUndoInsertionMarkupMac.h>
100 #import <WebCore/WebActionDisablingCALayerDelegate.h>
101 #import <WebCore/WebCoreCALayerExtras.h>
102 #import <WebCore/WebCoreFullScreenPlaceholderView.h>
103 #import <WebCore/WebCoreFullScreenWindow.h>
104 #import <WebCore/WebCoreNSStringExtras.h>
105 #import <WebKitSystemInterface.h>
106 #import <sys/stat.h>
107 #import <wtf/RefPtr.h>
108 #import <wtf/RetainPtr.h>
109 #import <wtf/RunLoop.h>
110
111 /* API internals. */
112 #import "WKBrowsingContextControllerInternal.h"
113 #import "WKBrowsingContextGroupPrivate.h"
114 #import "WKProcessGroupPrivate.h"
115
116 @interface NSApplication (WKNSApplicationDetails)
117 - (void)speakString:(NSString *)string;
118 - (void)_setCurrentEvent:(NSEvent *)event;
119 @end
120
121 @interface NSWindow (WKNSWindowDetails)
122 - (NSRect)_intersectBottomCornersWithRect:(NSRect)viewRect;
123 - (void)_maskRoundedBottomCorners:(NSRect)clipRect;
124 @end
125
126 #if USE(ASYNC_NSTEXTINPUTCLIENT)
127 @interface NSTextInputContext (WKNSTextInputContextDetails)
128 - (void)handleEvent:(NSEvent *)theEvent completionHandler:(void(^)(BOOL handled))completionHandler;
129 - (void)handleEventByInputMethod:(NSEvent *)theEvent completionHandler:(void(^)(BOOL handled))completionHandler;
130 - (BOOL)handleEventByKeyboardLayout:(NSEvent *)theEvent;
131 @end
132 #endif
133
134 #if defined(__has_include) && __has_include(<CoreGraphics/CoreGraphicsPrivate.h>)
135 #import <CoreGraphics/CoreGraphicsPrivate.h>
136 #endif
137
138 extern "C" {
139 typedef uint32_t CGSConnectionID;
140 typedef uint32_t CGSWindowID;
141 CGSConnectionID CGSMainConnectionID(void);
142 CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *rect);
143 };
144
145 using namespace WebKit;
146 using namespace WebCore;
147
148 namespace WebKit {
149
150 typedef id <NSValidatedUserInterfaceItem> ValidationItem;
151 typedef Vector<RetainPtr<ValidationItem>> ValidationVector;
152 typedef HashMap<String, ValidationVector> ValidationMap;
153
154 }
155
156 #if !USE(ASYNC_NSTEXTINPUTCLIENT)
157 struct WKViewInterpretKeyEventsParameters {
158     bool eventInterpretationHadSideEffects;
159     bool consumedByIM;
160     bool executingSavedKeypressCommands;
161     Vector<KeypressCommand>* commands;
162 };
163 #endif
164
165 @interface WKViewData : NSObject {
166 @public
167     std::unique_ptr<PageClientImpl> _pageClient;
168     RefPtr<WebPageProxy> _page;
169
170 #if WK_API_ENABLED
171     RetainPtr<WKBrowsingContextController> _browsingContextController;
172 #endif
173
174     RetainPtr<NSTrackingArea> _primaryTrackingArea;
175
176     // For ToolTips.
177     NSToolTipTag _lastToolTipTag;
178     id _trackingRectOwner;
179     void* _trackingRectUserData;
180
181     RetainPtr<NSView> _layerHostingView;
182
183     RetainPtr<id> _remoteAccessibilityChild;
184     
185     // For asynchronous validation.
186     ValidationMap _validationMap;
187
188     std::unique_ptr<TextIndicatorWindow> _textIndicatorWindow;
189
190     // We keep here the event when resending it to
191     // the application to distinguish the case of a new event from one 
192     // that has been already sent to WebCore.
193     RetainPtr<NSEvent> _keyDownEventBeingResent;
194 #if USE(ASYNC_NSTEXTINPUTCLIENT)
195     Vector<KeypressCommand>* _collectedKeypressCommands;
196 #else
197     WKViewInterpretKeyEventsParameters* _interpretKeyEventsParameters;
198 #endif
199
200     NSSize _resizeScrollOffset;
201
202     // The identifier of the plug-in we want to send complex text input to, or 0 if there is none.
203     uint64_t _pluginComplexTextInputIdentifier;
204
205     // The state of complex text input for the plug-in.
206     PluginComplexTextInputState _pluginComplexTextInputState;
207
208     bool _inBecomeFirstResponder;
209     bool _inResignFirstResponder;
210     NSEvent *_mouseDownEvent;
211     BOOL _ignoringMouseDraggedEvents;
212
213     id _flagsChangedEventMonitor;
214
215 #if ENABLE(FULLSCREEN_API)
216     RetainPtr<WKFullScreenWindowController> _fullScreenWindowController;
217 #endif
218
219     BOOL _hasSpellCheckerDocumentTag;
220     NSInteger _spellCheckerDocumentTag;
221
222     BOOL _inSecureInputState;
223
224     NSRect _windowBottomCornerIntersectionRect;
225     
226     unsigned _frameSizeUpdatesDisabledCount;
227     BOOL _shouldDeferViewInWindowChanges;
228
229     BOOL _viewInWindowChangeWasDeferred;
230
231     BOOL _needsViewFrameInWindowCoordinates;
232     BOOL _didScheduleWindowAndViewFrameUpdate;
233
234     RetainPtr<NSColorSpace> _colorSpace;
235
236     RefPtr<WebCore::Image> _promisedImage;
237     String _promisedFilename;
238     String _promisedURL;
239     
240     NSSize _intrinsicContentSize;
241     BOOL _clipsToVisibleRect;
242     NSRect _contentPreparationRect;
243     BOOL _useContentPreparationRectForVisibleRect;
244     BOOL _windowOcclusionDetectionEnabled;
245
246     std::unique_ptr<ViewGestureController> _gestureController;
247     BOOL _allowsMagnification;
248     BOOL _ignoresNonWheelMouseEvents;
249     BOOL _allowsBackForwardNavigationGestures;
250
251     RetainPtr<CALayer> _rootLayer;
252
253     BOOL _didScheduleSetTopContentInset;
254     CGFloat _topContentInset;
255
256 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
257     BOOL _automaticallyAdjustsContentInsets;
258     RetainPtr<WKActionMenuController> _actionMenuController;
259 #endif
260
261 #if WK_API_ENABLED
262     _WKThumbnailView *_thumbnailView;
263 #endif
264 }
265
266 @end
267
268 @implementation WKViewData
269 @end
270
271 @interface WKResponderChainSink : NSResponder {
272     NSResponder *_lastResponderInChain;
273     bool _didReceiveUnhandledCommand;
274 }
275 - (id)initWithResponderChain:(NSResponder *)chain;
276 - (void)detach;
277 - (bool)didReceiveUnhandledCommand;
278 @end
279
280 @interface WKFlippedView : NSView
281 @end
282
283 @implementation WKFlippedView
284
285 - (BOOL)isFlipped
286 {
287     return YES;
288 }
289
290 @end
291
292 @implementation WKView
293
294 #if WK_API_ENABLED
295
296 - (id)initWithFrame:(NSRect)frame processGroup:(WKProcessGroup *)processGroup browsingContextGroup:(WKBrowsingContextGroup *)browsingContextGroup
297 {
298     return [self initWithFrame:frame contextRef:processGroup._contextRef pageGroupRef:browsingContextGroup._pageGroupRef relatedToPage:nil];
299 }
300
301 - (id)initWithFrame:(NSRect)frame processGroup:(WKProcessGroup *)processGroup browsingContextGroup:(WKBrowsingContextGroup *)browsingContextGroup relatedToView:(WKView *)relatedView
302 {
303     return [self initWithFrame:frame contextRef:processGroup._contextRef pageGroupRef:browsingContextGroup._pageGroupRef relatedToPage:relatedView ? toAPI(relatedView->_data->_page.get()) : nil];
304 }
305
306 #endif // WK_API_ENABLED
307
308 - (void)dealloc
309 {
310 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
311     [_data->_actionMenuController willDestroyView:self];
312 #endif
313
314     _data->_page->close();
315
316 #if WK_API_ENABLED
317     ASSERT(!_data->_thumbnailView);
318 #endif
319     ASSERT(!_data->_inSecureInputState);
320
321     [_data release];
322     _data = nil;
323
324     NSNotificationCenter* workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
325     [workspaceNotificationCenter removeObserver:self name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
326
327     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:NSApp];
328
329     if (canDisableLookupIndicator())
330         [[NSNotificationCenter defaultCenter] removeObserver:self name:getLUNotificationPopoverWillClose() object:nil];
331
332     WebContext::statistics().wkViewCount--;
333
334     [super dealloc];
335 }
336
337 #if WK_API_ENABLED
338
339 - (WKBrowsingContextController *)browsingContextController
340 {
341     if (!_data->_browsingContextController)
342         _data->_browsingContextController = adoptNS([[WKBrowsingContextController alloc] _initWithPageRef:toAPI(_data->_page.get())]);
343
344     return _data->_browsingContextController.get();
345 }
346
347 #endif // WK_API_ENABLED
348
349 - (void)setDrawsBackground:(BOOL)drawsBackground
350 {
351     _data->_page->setDrawsBackground(drawsBackground);
352 }
353
354 - (BOOL)drawsBackground
355 {
356     return _data->_page->drawsBackground();
357 }
358
359 - (void)setDrawsTransparentBackground:(BOOL)drawsTransparentBackground
360 {
361     _data->_page->setDrawsTransparentBackground(drawsTransparentBackground);
362 }
363
364 - (BOOL)drawsTransparentBackground
365 {
366     return _data->_page->drawsTransparentBackground();
367 }
368
369 - (BOOL)acceptsFirstResponder
370 {
371     return YES;
372 }
373
374 - (BOOL)becomeFirstResponder
375 {
376     NSSelectionDirection direction = [[self window] keyViewSelectionDirection];
377
378     _data->_inBecomeFirstResponder = true;
379     
380     [self _updateSecureInputState];
381     _data->_page->viewStateDidChange(ViewState::IsFocused);
382
383     _data->_inBecomeFirstResponder = false;
384     
385     if (direction != NSDirectSelection) {
386         NSEvent *event = [NSApp currentEvent];
387         NSEvent *keyboardEvent = nil;
388         if ([event type] == NSKeyDown || [event type] == NSKeyUp)
389             keyboardEvent = event;
390         _data->_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, Vector<KeypressCommand>()));
391     }
392     return YES;
393 }
394
395 - (BOOL)resignFirstResponder
396 {
397     _data->_inResignFirstResponder = true;
398
399 #if USE(ASYNC_NSTEXTINPUTCLIENT)
400     _data->_page->confirmCompositionAsync();
401 #else
402     if (_data->_page->editorState().hasComposition && !_data->_page->editorState().shouldIgnoreCompositionSelectionChange)
403         _data->_page->cancelComposition();
404 #endif
405
406     [self _notifyInputContextAboutDiscardedComposition];
407
408     [self _resetSecureInputState];
409
410     if (!_data->_page->maintainsInactiveSelection())
411         _data->_page->clearSelection();
412     
413     _data->_page->viewStateDidChange(ViewState::IsFocused);
414
415     _data->_inResignFirstResponder = false;
416
417     return YES;
418 }
419
420 - (void)viewWillStartLiveResize
421 {
422     _data->_page->viewWillStartLiveResize();
423 }
424
425 - (void)viewDidEndLiveResize
426 {
427     _data->_page->viewWillEndLiveResize();
428 }
429
430 - (BOOL)isFlipped
431 {
432     return YES;
433 }
434
435 - (NSSize)intrinsicContentSize
436 {
437     return _data->_intrinsicContentSize;
438 }
439
440 - (void)prepareContentInRect:(NSRect)rect
441 {
442     _data->_contentPreparationRect = rect;
443     _data->_useContentPreparationRectForVisibleRect = YES;
444
445     [self _updateViewExposedRect];
446 }
447
448 - (void)_updateViewExposedRect
449 {
450     NSRect exposedRect = [self visibleRect];
451
452     if (_data->_useContentPreparationRectForVisibleRect)
453         exposedRect = NSUnionRect(_data->_contentPreparationRect, exposedRect);
454
455     if (auto drawingArea = _data->_page->drawingArea())
456         drawingArea->setExposedRect(_data->_clipsToVisibleRect ? FloatRect(exposedRect) : FloatRect::infiniteRect());
457 }
458
459 - (void)setFrameSize:(NSSize)size
460 {
461     [super setFrameSize:size];
462
463     if (![self frameSizeUpdatesDisabled]) {
464         if (_data->_clipsToVisibleRect)
465             [self _updateViewExposedRect];
466         [self _setDrawingAreaSize:size];
467     }
468 }
469
470 - (void)_updateWindowAndViewFrames
471 {
472     if (_data->_clipsToVisibleRect)
473         [self _updateViewExposedRect];
474
475     if (_data->_didScheduleWindowAndViewFrameUpdate)
476         return;
477
478     _data->_didScheduleWindowAndViewFrameUpdate = YES;
479
480     dispatch_async(dispatch_get_main_queue(), ^{
481         _data->_didScheduleWindowAndViewFrameUpdate = NO;
482
483         NSRect viewFrameInWindowCoordinates = NSZeroRect;
484         NSPoint accessibilityPosition = NSZeroPoint;
485
486         if (_data->_needsViewFrameInWindowCoordinates)
487             viewFrameInWindowCoordinates = [self convertRect:self.frame toView:nil];
488
489 #pragma clang diagnostic push
490 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
491         if (WebCore::AXObjectCache::accessibilityEnabled())
492             accessibilityPosition = [[self accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue];
493 #pragma clang diagnostic pop
494
495         _data->_page->windowAndViewFramesChanged(viewFrameInWindowCoordinates, accessibilityPosition);
496     });
497 }
498
499 - (void)renewGState
500 {
501     // Hide the find indicator.
502     _data->_textIndicatorWindow = nullptr;
503
504     // Update the view frame.
505     if ([self window])
506         [self _updateWindowAndViewFrames];
507
508 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
509     [self _updateContentInsetsIfAutomatic];
510 #endif
511
512     [super renewGState];
513 }
514
515 - (void)_setPluginComplexTextInputState:(PluginComplexTextInputState)pluginComplexTextInputState
516 {
517     _data->_pluginComplexTextInputState = pluginComplexTextInputState;
518     
519     if (_data->_pluginComplexTextInputState != PluginComplexTextInputDisabled)
520         return;
521
522     // Send back an empty string to the plug-in. This will disable text input.
523     _data->_page->sendComplexTextInputToPlugin(_data->_pluginComplexTextInputIdentifier, String());
524 }
525
526 typedef HashMap<SEL, String> SelectorNameMap;
527
528 // Map selectors into Editor command names.
529 // This is not needed for any selectors that have the same name as the Editor command.
530 static const SelectorNameMap* createSelectorExceptionMap()
531 {
532     SelectorNameMap* map = new HashMap<SEL, String>;
533     
534     map->add(@selector(insertNewlineIgnoringFieldEditor:), "InsertNewline");
535     map->add(@selector(insertParagraphSeparator:), "InsertNewline");
536     map->add(@selector(insertTabIgnoringFieldEditor:), "InsertTab");
537     map->add(@selector(pageDown:), "MovePageDown");
538     map->add(@selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection");
539     map->add(@selector(pageUp:), "MovePageUp");
540     map->add(@selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection");
541     map->add(@selector(scrollPageDown:), "ScrollPageForward");
542     map->add(@selector(scrollPageUp:), "ScrollPageBackward");
543     
544     return map;
545 }
546
547 static String commandNameForSelector(SEL selector)
548 {
549     // Check the exception map first.
550     static const SelectorNameMap* exceptionMap = createSelectorExceptionMap();
551     SelectorNameMap::const_iterator it = exceptionMap->find(selector);
552     if (it != exceptionMap->end())
553         return it->value;
554     
555     // Remove the trailing colon.
556     // No need to capitalize the command name since Editor command names are
557     // not case sensitive.
558     const char* selectorName = sel_getName(selector);
559     size_t selectorNameLength = strlen(selectorName);
560     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
561         return String();
562     return String(selectorName, selectorNameLength - 1);
563 }
564
565 // Editing commands
566
567 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { _data->_page->executeEditCommand(commandNameForSelector(_cmd)); }
568
569 WEBCORE_COMMAND(alignCenter)
570 WEBCORE_COMMAND(alignJustified)
571 WEBCORE_COMMAND(alignLeft)
572 WEBCORE_COMMAND(alignRight)
573 WEBCORE_COMMAND(copy)
574 WEBCORE_COMMAND(cut)
575 WEBCORE_COMMAND(delete)
576 WEBCORE_COMMAND(deleteBackward)
577 WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter)
578 WEBCORE_COMMAND(deleteForward)
579 WEBCORE_COMMAND(deleteToBeginningOfLine)
580 WEBCORE_COMMAND(deleteToBeginningOfParagraph)
581 WEBCORE_COMMAND(deleteToEndOfLine)
582 WEBCORE_COMMAND(deleteToEndOfParagraph)
583 WEBCORE_COMMAND(deleteToMark)
584 WEBCORE_COMMAND(deleteWordBackward)
585 WEBCORE_COMMAND(deleteWordForward)
586 WEBCORE_COMMAND(ignoreSpelling)
587 WEBCORE_COMMAND(indent)
588 WEBCORE_COMMAND(insertBacktab)
589 WEBCORE_COMMAND(insertLineBreak)
590 WEBCORE_COMMAND(insertNewline)
591 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
592 WEBCORE_COMMAND(insertParagraphSeparator)
593 WEBCORE_COMMAND(insertTab)
594 WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
595 WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight)
596 WEBCORE_COMMAND(makeTextWritingDirectionNatural)
597 WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft)
598 WEBCORE_COMMAND(moveBackward)
599 WEBCORE_COMMAND(moveBackwardAndModifySelection)
600 WEBCORE_COMMAND(moveDown)
601 WEBCORE_COMMAND(moveDownAndModifySelection)
602 WEBCORE_COMMAND(moveForward)
603 WEBCORE_COMMAND(moveForwardAndModifySelection)
604 WEBCORE_COMMAND(moveLeft)
605 WEBCORE_COMMAND(moveLeftAndModifySelection)
606 WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection)
607 WEBCORE_COMMAND(moveParagraphForwardAndModifySelection)
608 WEBCORE_COMMAND(moveRight)
609 WEBCORE_COMMAND(moveRightAndModifySelection)
610 WEBCORE_COMMAND(moveToBeginningOfDocument)
611 WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection)
612 WEBCORE_COMMAND(moveToBeginningOfLine)
613 WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection)
614 WEBCORE_COMMAND(moveToBeginningOfParagraph)
615 WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection)
616 WEBCORE_COMMAND(moveToBeginningOfSentence)
617 WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection)
618 WEBCORE_COMMAND(moveToEndOfDocument)
619 WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection)
620 WEBCORE_COMMAND(moveToEndOfLine)
621 WEBCORE_COMMAND(moveToEndOfLineAndModifySelection)
622 WEBCORE_COMMAND(moveToEndOfParagraph)
623 WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection)
624 WEBCORE_COMMAND(moveToEndOfSentence)
625 WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection)
626 WEBCORE_COMMAND(moveToLeftEndOfLine)
627 WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection)
628 WEBCORE_COMMAND(moveToRightEndOfLine)
629 WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection)
630 WEBCORE_COMMAND(moveUp)
631 WEBCORE_COMMAND(moveUpAndModifySelection)
632 WEBCORE_COMMAND(moveWordBackward)
633 WEBCORE_COMMAND(moveWordBackwardAndModifySelection)
634 WEBCORE_COMMAND(moveWordForward)
635 WEBCORE_COMMAND(moveWordForwardAndModifySelection)
636 WEBCORE_COMMAND(moveWordLeft)
637 WEBCORE_COMMAND(moveWordLeftAndModifySelection)
638 WEBCORE_COMMAND(moveWordRight)
639 WEBCORE_COMMAND(moveWordRightAndModifySelection)
640 WEBCORE_COMMAND(outdent)
641 WEBCORE_COMMAND(pageDown)
642 WEBCORE_COMMAND(pageDownAndModifySelection)
643 WEBCORE_COMMAND(pageUp)
644 WEBCORE_COMMAND(pageUpAndModifySelection)
645 WEBCORE_COMMAND(paste)
646 WEBCORE_COMMAND(pasteAsPlainText)
647 WEBCORE_COMMAND(scrollPageDown)
648 WEBCORE_COMMAND(scrollPageUp)
649 WEBCORE_COMMAND(scrollLineDown)
650 WEBCORE_COMMAND(scrollLineUp)
651 WEBCORE_COMMAND(scrollToBeginningOfDocument)
652 WEBCORE_COMMAND(scrollToEndOfDocument)
653 WEBCORE_COMMAND(selectAll)
654 WEBCORE_COMMAND(selectLine)
655 WEBCORE_COMMAND(selectParagraph)
656 WEBCORE_COMMAND(selectSentence)
657 WEBCORE_COMMAND(selectToMark)
658 WEBCORE_COMMAND(selectWord)
659 WEBCORE_COMMAND(setMark)
660 WEBCORE_COMMAND(subscript)
661 WEBCORE_COMMAND(superscript)
662 WEBCORE_COMMAND(swapWithMark)
663 WEBCORE_COMMAND(takeFindStringFromSelection)
664 WEBCORE_COMMAND(transpose)
665 WEBCORE_COMMAND(underline)
666 WEBCORE_COMMAND(unscript)
667 WEBCORE_COMMAND(yank)
668 WEBCORE_COMMAND(yankAndSelect)
669
670 #undef WEBCORE_COMMAND
671
672 // This method is needed to support Mac OS X services.
673
674 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
675 {
676     size_t numTypes = [types count];
677     [pasteboard declareTypes:types owner:nil];
678     for (size_t i = 0; i < numTypes; ++i) {
679         if ([[types objectAtIndex:i] isEqualTo:NSStringPboardType])
680             [pasteboard setString:_data->_page->stringSelectionForPasteboard() forType:NSStringPboardType];
681         else {
682             RefPtr<SharedBuffer> buffer = _data->_page->dataSelectionForPasteboard([types objectAtIndex:i]);
683             [pasteboard setData:buffer ? buffer->createNSData().get() : nil forType:[types objectAtIndex:i]];
684        }
685     }
686     return YES;
687 }
688
689 - (void)centerSelectionInVisibleArea:(id)sender 
690
691     _data->_page->centerSelectionInVisibleArea();
692 }
693
694 // This method is needed to support Mac OS X services.
695
696 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
697 {
698     EditorState editorState = _data->_page->editorState();
699     BOOL isValidSendType = NO;
700
701     if (sendType && !editorState.selectionIsNone) {
702         if (editorState.isInPlugin)
703             isValidSendType = [sendType isEqualToString:NSStringPboardType];
704         else
705             isValidSendType = [PasteboardTypes::forSelection() containsObject:sendType];
706     }
707
708     BOOL isValidReturnType = NO;
709     if (!returnType)
710         isValidReturnType = YES;
711     else if ([PasteboardTypes::forEditing() containsObject:returnType] && editorState.isContentEditable) {
712         // We can insert strings in any editable context.  We can insert other types, like images, only in rich edit contexts.
713         isValidReturnType = editorState.isContentRichlyEditable || [returnType isEqualToString:NSStringPboardType];
714     }
715     if (isValidSendType && isValidReturnType)
716         return self;
717     return [[self nextResponder] validRequestorForSendType:sendType returnType:returnType];
718 }
719
720 // This method is needed to support Mac OS X services.
721
722 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard 
723 {
724     return _data->_page->readSelectionFromPasteboard([pasteboard name]);
725 }
726
727 /*
728
729 When possible, editing-related methods should be implemented in WebCore with the
730 EditorCommand mechanism and invoked via WEBCORE_COMMAND, rather than implementing
731 individual methods here with Mac-specific code.
732
733 Editing-related methods still unimplemented that are implemented in WebKit1:
734
735 - (void)capitalizeWord:(id)sender;
736 - (void)changeFont:(id)sender;
737 - (void)complete:(id)sender;
738 - (void)copyFont:(id)sender;
739 - (void)lowercaseWord:(id)sender;
740 - (void)makeBaseWritingDirectionLeftToRight:(id)sender;
741 - (void)makeBaseWritingDirectionNatural:(id)sender;
742 - (void)makeBaseWritingDirectionRightToLeft:(id)sender;
743 - (void)pasteFont:(id)sender;
744 - (void)scrollLineDown:(id)sender;
745 - (void)scrollLineUp:(id)sender;
746 - (void)showGuessPanel:(id)sender;
747 - (void)uppercaseWord:(id)sender;
748
749 Some other editing-related methods still unimplemented:
750
751 - (void)changeCaseOfLetter:(id)sender;
752 - (void)copyRuler:(id)sender;
753 - (void)insertContainerBreak:(id)sender;
754 - (void)insertDoubleQuoteIgnoringSubstitution:(id)sender;
755 - (void)insertSingleQuoteIgnoringSubstitution:(id)sender;
756 - (void)pasteRuler:(id)sender;
757 - (void)toggleRuler:(id)sender;
758 - (void)transposeWords:(id)sender;
759
760 */
761
762 // Menu items validation
763
764 static NSMenuItem *menuItem(id <NSValidatedUserInterfaceItem> item)
765 {
766     if (![(NSObject *)item isKindOfClass:[NSMenuItem class]])
767         return nil;
768     return (NSMenuItem *)item;
769 }
770
771 static NSToolbarItem *toolbarItem(id <NSValidatedUserInterfaceItem> item)
772 {
773     if (![(NSObject *)item isKindOfClass:[NSToolbarItem class]])
774         return nil;
775     return (NSToolbarItem *)item;
776 }
777
778 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
779 {
780     SEL action = [item action];
781
782     if (action == @selector(showGuessPanel:)) {
783         if (NSMenuItem *menuItem = ::menuItem(item))
784             [menuItem setTitle:contextMenuItemTagShowSpellingPanel(![[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible])];
785         return _data->_page->editorState().isContentEditable;
786     }
787
788     if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:))
789         return _data->_page->editorState().isContentEditable;
790
791     if (action == @selector(toggleContinuousSpellChecking:)) {
792         bool enabled = TextChecker::isContinuousSpellCheckingAllowed();
793         bool checked = enabled && TextChecker::state().isContinuousSpellCheckingEnabled;
794         [menuItem(item) setState:checked ? NSOnState : NSOffState];
795         return enabled;
796     }
797
798     if (action == @selector(toggleGrammarChecking:)) {
799         bool checked = TextChecker::state().isGrammarCheckingEnabled;
800         [menuItem(item) setState:checked ? NSOnState : NSOffState];
801         return YES;
802     }
803
804     if (action == @selector(toggleAutomaticSpellingCorrection:)) {
805         bool checked = TextChecker::state().isAutomaticSpellingCorrectionEnabled;
806         [menuItem(item) setState:checked ? NSOnState : NSOffState];
807         return _data->_page->editorState().isContentEditable;
808     }
809
810     if (action == @selector(orderFrontSubstitutionsPanel:)) {
811         if (NSMenuItem *menuItem = ::menuItem(item))
812             [menuItem setTitle:contextMenuItemTagShowSubstitutions(![[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible])];
813         return _data->_page->editorState().isContentEditable;
814     }
815
816     if (action == @selector(toggleSmartInsertDelete:)) {
817         bool checked = _data->_page->isSmartInsertDeleteEnabled();
818         [menuItem(item) setState:checked ? NSOnState : NSOffState];
819         return _data->_page->editorState().isContentEditable;
820     }
821
822     if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
823         bool checked = TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
824         [menuItem(item) setState:checked ? NSOnState : NSOffState];
825         return _data->_page->editorState().isContentEditable;
826     }
827
828     if (action == @selector(toggleAutomaticDashSubstitution:)) {
829         bool checked = TextChecker::state().isAutomaticDashSubstitutionEnabled;
830         [menuItem(item) setState:checked ? NSOnState : NSOffState];
831         return _data->_page->editorState().isContentEditable;
832     }
833
834     if (action == @selector(toggleAutomaticLinkDetection:)) {
835         bool checked = TextChecker::state().isAutomaticLinkDetectionEnabled;
836         [menuItem(item) setState:checked ? NSOnState : NSOffState];
837         return _data->_page->editorState().isContentEditable;
838     }
839
840     if (action == @selector(toggleAutomaticTextReplacement:)) {
841         bool checked = TextChecker::state().isAutomaticTextReplacementEnabled;
842         [menuItem(item) setState:checked ? NSOnState : NSOffState];
843         return _data->_page->editorState().isContentEditable;
844     }
845
846     if (action == @selector(uppercaseWord:) || action == @selector(lowercaseWord:) || action == @selector(capitalizeWord:))
847         return _data->_page->editorState().selectionIsRange && _data->_page->editorState().isContentEditable;
848     
849     if (action == @selector(stopSpeaking:))
850         return [NSApp isSpeaking];
851     
852     // The centerSelectionInVisibleArea: selector is enabled if there's a selection range or if there's an insertion point in an editable area.
853     if (action == @selector(centerSelectionInVisibleArea:))
854         return _data->_page->editorState().selectionIsRange || (_data->_page->editorState().isContentEditable && !_data->_page->editorState().selectionIsNone);
855
856     // Next, handle editor commands. Start by returning YES for anything that is not an editor command.
857     // Returning YES is the default thing to do in an AppKit validate method for any selector that is not recognized.
858     String commandName = commandNameForSelector([item action]);
859     if (!Editor::commandIsSupportedFromMenuOrKeyBinding(commandName))
860         return YES;
861
862     // Add this item to the vector of items for a given command that are awaiting validation.
863     ValidationMap::AddResult addResult = _data->_validationMap.add(commandName, ValidationVector());
864     addResult.iterator->value.append(item);
865     if (addResult.isNewEntry) {
866         // If we are not already awaiting validation for this command, start the asynchronous validation process.
867         // FIXME: Theoretically, there is a race here; when we get the answer it might be old, from a previous time
868         // we asked for the same command; there is no guarantee the answer is still valid.
869         _data->_page->validateCommand(commandName, [self](const String& commandName, bool isEnabled, int32_t state, CallbackBase::Error error) {
870             // If the process exits before the command can be validated, we'll be called back with an error.
871             if (error != CallbackBase::Error::None)
872                 return;
873             
874             [self _setUserInterfaceItemState:commandName enabled:isEnabled state:state];
875         });
876     }
877
878     // Treat as enabled until we get the result back from the web process and _setUserInterfaceItemState is called.
879     // FIXME <rdar://problem/8803459>: This means disabled items will flash enabled at first for a moment.
880     // But returning NO here would be worse; that would make keyboard commands such as command-C fail.
881     return YES;
882 }
883
884 - (IBAction)startSpeaking:(id)sender
885 {
886     _data->_page->getSelectionOrContentsAsString([self](const String& string, CallbackBase::Error error) {
887         if (error != CallbackBase::Error::None)
888             return;
889         if (!string)
890             return;
891
892         [NSApp speakString:string];
893     });
894 }
895
896 - (IBAction)stopSpeaking:(id)sender
897 {
898     [NSApp stopSpeaking:sender];
899 }
900
901 - (IBAction)showGuessPanel:(id)sender
902 {
903     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
904     if (!checker) {
905         LOG_ERROR("No NSSpellChecker");
906         return;
907     }
908     
909     NSPanel *spellingPanel = [checker spellingPanel];
910     if ([spellingPanel isVisible]) {
911         [spellingPanel orderOut:sender];
912         return;
913     }
914     
915     _data->_page->advanceToNextMisspelling(true);
916     [spellingPanel orderFront:sender];
917 }
918
919 - (IBAction)checkSpelling:(id)sender
920 {
921     _data->_page->advanceToNextMisspelling(false);
922 }
923
924 - (void)changeSpelling:(id)sender
925 {
926     NSString *word = [[sender selectedCell] stringValue];
927
928     _data->_page->changeSpellingToWord(word);
929 }
930
931 - (IBAction)toggleContinuousSpellChecking:(id)sender
932 {
933     bool spellCheckingEnabled = !TextChecker::state().isContinuousSpellCheckingEnabled;
934     TextChecker::setContinuousSpellCheckingEnabled(spellCheckingEnabled);
935
936     _data->_page->process().updateTextCheckerState();
937 }
938
939 - (BOOL)isGrammarCheckingEnabled
940 {
941     return TextChecker::state().isGrammarCheckingEnabled;
942 }
943
944 - (void)setGrammarCheckingEnabled:(BOOL)flag
945 {
946     if (static_cast<bool>(flag) == TextChecker::state().isGrammarCheckingEnabled)
947         return;
948     
949     TextChecker::setGrammarCheckingEnabled(flag);
950     _data->_page->process().updateTextCheckerState();
951 }
952
953 - (IBAction)toggleGrammarChecking:(id)sender
954 {
955     bool grammarCheckingEnabled = !TextChecker::state().isGrammarCheckingEnabled;
956     TextChecker::setGrammarCheckingEnabled(grammarCheckingEnabled);
957
958     _data->_page->process().updateTextCheckerState();
959 }
960
961 - (IBAction)toggleAutomaticSpellingCorrection:(id)sender
962 {
963     TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled);
964
965     _data->_page->process().updateTextCheckerState();
966 }
967
968 - (void)orderFrontSubstitutionsPanel:(id)sender
969 {
970     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
971     if (!checker) {
972         LOG_ERROR("No NSSpellChecker");
973         return;
974     }
975     
976     NSPanel *substitutionsPanel = [checker substitutionsPanel];
977     if ([substitutionsPanel isVisible]) {
978         [substitutionsPanel orderOut:sender];
979         return;
980     }
981     [substitutionsPanel orderFront:sender];
982 }
983
984 - (IBAction)toggleSmartInsertDelete:(id)sender
985 {
986     _data->_page->setSmartInsertDeleteEnabled(!_data->_page->isSmartInsertDeleteEnabled());
987 }
988
989 - (BOOL)isAutomaticQuoteSubstitutionEnabled
990 {
991     return TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
992 }
993
994 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag
995 {
996     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticQuoteSubstitutionEnabled)
997         return;
998
999     TextChecker::setAutomaticQuoteSubstitutionEnabled(flag);
1000     _data->_page->process().updateTextCheckerState();
1001 }
1002
1003 - (void)toggleAutomaticQuoteSubstitution:(id)sender
1004 {
1005     TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
1006     _data->_page->process().updateTextCheckerState();
1007 }
1008
1009 - (BOOL)isAutomaticDashSubstitutionEnabled
1010 {
1011     return TextChecker::state().isAutomaticDashSubstitutionEnabled;
1012 }
1013
1014 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag
1015 {
1016     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticDashSubstitutionEnabled)
1017         return;
1018
1019     TextChecker::setAutomaticDashSubstitutionEnabled(flag);
1020     _data->_page->process().updateTextCheckerState();
1021 }
1022
1023 - (void)toggleAutomaticDashSubstitution:(id)sender
1024 {
1025     TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
1026     _data->_page->process().updateTextCheckerState();
1027 }
1028
1029 - (BOOL)isAutomaticLinkDetectionEnabled
1030 {
1031     return TextChecker::state().isAutomaticLinkDetectionEnabled;
1032 }
1033
1034 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag
1035 {
1036     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticLinkDetectionEnabled)
1037         return;
1038
1039     TextChecker::setAutomaticLinkDetectionEnabled(flag);
1040     _data->_page->process().updateTextCheckerState();
1041 }
1042
1043 - (void)toggleAutomaticLinkDetection:(id)sender
1044 {
1045     TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
1046     _data->_page->process().updateTextCheckerState();
1047 }
1048
1049 - (BOOL)isAutomaticTextReplacementEnabled
1050 {
1051     return TextChecker::state().isAutomaticTextReplacementEnabled;
1052 }
1053
1054 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag
1055 {
1056     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticTextReplacementEnabled)
1057         return;
1058
1059     TextChecker::setAutomaticTextReplacementEnabled(flag);
1060     _data->_page->process().updateTextCheckerState();
1061 }
1062
1063 - (void)toggleAutomaticTextReplacement:(id)sender
1064 {
1065     TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
1066     _data->_page->process().updateTextCheckerState();
1067 }
1068
1069 - (void)uppercaseWord:(id)sender
1070 {
1071     _data->_page->uppercaseWord();
1072 }
1073
1074 - (void)lowercaseWord:(id)sender
1075 {
1076     _data->_page->lowercaseWord();
1077 }
1078
1079 - (void)capitalizeWord:(id)sender
1080 {
1081     _data->_page->capitalizeWord();
1082 }
1083
1084 - (void)displayIfNeeded
1085 {
1086     // FIXME: We should remove this code when <rdar://problem/9362085> is resolved. In the meantime,
1087     // it is necessary to disable scren updates so we get a chance to redraw the corners before this 
1088     // display is visible.
1089     NSWindow *window = [self window];
1090     BOOL shouldMaskWindow = window && !NSIsEmptyRect(_data->_windowBottomCornerIntersectionRect);
1091     if (shouldMaskWindow)
1092         NSDisableScreenUpdates();
1093
1094     [super displayIfNeeded];
1095
1096     if (shouldMaskWindow) {
1097         [window _maskRoundedBottomCorners:_data->_windowBottomCornerIntersectionRect];
1098         NSEnableScreenUpdates();
1099         _data->_windowBottomCornerIntersectionRect = NSZeroRect;
1100     }
1101 }
1102
1103 // Events
1104
1105 - (BOOL)_shouldIgnoreMouseEvents
1106 {
1107     // FIXME: This check is surprisingly specific. Are there any other cases where we need to block mouse events?
1108     // Do we actually need to in thumbnail view? And if we do, what about non-mouse events?
1109 #if WK_API_ENABLED
1110     if (_data->_thumbnailView)
1111         return YES;
1112 #endif
1113
1114     // -scrollWheel: uses -_shouldIgnoreWheelEvents, so for all other event types it is correct to use this.
1115     return _data->_ignoresNonWheelMouseEvents;
1116 }
1117
1118 - (BOOL)_shouldIgnoreWheelEvents
1119 {
1120 #if WK_API_ENABLED
1121     if (_data->_thumbnailView)
1122         return YES;
1123 #endif
1124
1125     return NO;
1126 }
1127
1128 // Override this so that AppKit will send us arrow keys as key down events so we can
1129 // support them via the key bindings mechanism.
1130 - (BOOL)_wantsKeyDownForEvent:(NSEvent *)event
1131 {
1132     return YES;
1133 }
1134
1135 - (void)_setMouseDownEvent:(NSEvent *)event
1136 {
1137     ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
1138     
1139     if (event == _data->_mouseDownEvent)
1140         return;
1141     
1142     [_data->_mouseDownEvent release];
1143     _data->_mouseDownEvent = [event retain];
1144 }
1145
1146 #if USE(ASYNC_NSTEXTINPUTCLIENT)
1147 #define NATIVE_MOUSE_EVENT_HANDLER(Selector) \
1148     - (void)Selector:(NSEvent *)theEvent \
1149     { \
1150         if (self._shouldIgnoreMouseEvents) \
1151             return; \
1152         if (NSTextInputContext *context = [self inputContext]) { \
1153             [context handleEvent:theEvent completionHandler:^(BOOL handled) { \
1154                 if (handled) \
1155                     LOG(TextInput, "%s was handled by text input context", String(#Selector).substring(0, String(#Selector).find("Internal")).ascii().data()); \
1156                 else { \
1157                     NativeWebMouseEvent webEvent(theEvent, self); \
1158                     _data->_page->handleMouseEvent(webEvent); \
1159                 } \
1160             }]; \
1161             return; \
1162         } \
1163         NativeWebMouseEvent webEvent(theEvent, self); \
1164         _data->_page->handleMouseEvent(webEvent); \
1165     }
1166 #else
1167 #define NATIVE_MOUSE_EVENT_HANDLER(Selector) \
1168     - (void)Selector:(NSEvent *)theEvent \
1169     { \
1170         if (self._shouldIgnoreMouseEvents) \
1171             return; \
1172         if ([[self inputContext] handleEvent:theEvent]) { \
1173             LOG(TextInput, "%s was handled by text input context", String(#Selector).substring(0, String(#Selector).find("Internal")).ascii().data()); \
1174             return; \
1175         } \
1176         NativeWebMouseEvent webEvent(theEvent, self); \
1177         _data->_page->handleMouseEvent(webEvent); \
1178     }
1179 #endif
1180
1181 NATIVE_MOUSE_EVENT_HANDLER(mouseEntered)
1182 NATIVE_MOUSE_EVENT_HANDLER(mouseExited)
1183 NATIVE_MOUSE_EVENT_HANDLER(mouseMovedInternal)
1184 NATIVE_MOUSE_EVENT_HANDLER(mouseDownInternal)
1185 NATIVE_MOUSE_EVENT_HANDLER(mouseUpInternal)
1186 NATIVE_MOUSE_EVENT_HANDLER(mouseDraggedInternal)
1187 NATIVE_MOUSE_EVENT_HANDLER(otherMouseDown)
1188 NATIVE_MOUSE_EVENT_HANDLER(otherMouseDragged)
1189 NATIVE_MOUSE_EVENT_HANDLER(otherMouseMoved)
1190 NATIVE_MOUSE_EVENT_HANDLER(otherMouseUp)
1191 NATIVE_MOUSE_EVENT_HANDLER(rightMouseDown)
1192 NATIVE_MOUSE_EVENT_HANDLER(rightMouseDragged)
1193 NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
1194
1195 #undef NATIVE_MOUSE_EVENT_HANDLER
1196
1197 - (void)_ensureGestureController
1198 {
1199     if (_data->_gestureController)
1200         return;
1201
1202     _data->_gestureController = std::make_unique<ViewGestureController>(*_data->_page);
1203 }
1204
1205 - (void)scrollWheel:(NSEvent *)event
1206 {
1207     if ([self _shouldIgnoreWheelEvents])
1208         return;
1209
1210     if (_data->_allowsBackForwardNavigationGestures) {
1211         [self _ensureGestureController];
1212         if (_data->_gestureController->handleScrollWheelEvent(event))
1213             return;
1214     }
1215
1216     NativeWebWheelEvent webEvent = NativeWebWheelEvent(event, self);
1217     _data->_page->handleWheelEvent(webEvent);
1218 }
1219
1220 - (void)swipeWithEvent:(NSEvent *)event
1221 {
1222     if (self._shouldIgnoreMouseEvents)
1223         return;
1224
1225     if (!_data->_allowsBackForwardNavigationGestures) {
1226         [super swipeWithEvent:event];
1227         return;
1228     }
1229
1230     if (event.deltaX > 0.0)
1231         _data->_page->goBack();
1232     else if (event.deltaX < 0.0)
1233         _data->_page->goForward();
1234     else
1235         [super swipeWithEvent:event];
1236 }
1237
1238 - (void)mouseMoved:(NSEvent *)event
1239 {
1240     if (self._shouldIgnoreMouseEvents)
1241         return;
1242
1243     // When a view is first responder, it gets mouse moved events even when the mouse is outside its visible rect.
1244     if (self == [[self window] firstResponder] && !NSPointInRect([self convertPoint:[event locationInWindow] fromView:nil], [self visibleRect]))
1245         return;
1246
1247     [self mouseMovedInternal:event];
1248 }
1249
1250 - (void)mouseDown:(NSEvent *)event
1251 {
1252     if (self._shouldIgnoreMouseEvents)
1253         return;
1254
1255     [self _setMouseDownEvent:event];
1256     _data->_ignoringMouseDraggedEvents = NO;
1257     [self mouseDownInternal:event];
1258 }
1259
1260 - (void)mouseUp:(NSEvent *)event
1261 {
1262     if (self._shouldIgnoreMouseEvents)
1263         return;
1264
1265     [self _setMouseDownEvent:nil];
1266     [self mouseUpInternal:event];
1267 }
1268
1269 - (void)mouseDragged:(NSEvent *)event
1270 {
1271     if (self._shouldIgnoreMouseEvents)
1272         return;
1273
1274     if (_data->_ignoringMouseDraggedEvents)
1275         return;
1276     [self mouseDraggedInternal:event];
1277 }
1278
1279 - (BOOL)acceptsFirstMouse:(NSEvent *)event
1280 {
1281     // There's a chance that responding to this event will run a nested event loop, and
1282     // fetching a new event might release the old one. Retaining and then autoreleasing
1283     // the current event prevents that from causing a problem inside WebKit or AppKit code.
1284     [[event retain] autorelease];
1285     
1286     if (![self hitTest:[event locationInWindow]])
1287         return NO;
1288     
1289     [self _setMouseDownEvent:event];
1290     bool result = _data->_page->acceptsFirstMouse([event eventNumber], WebEventFactory::createWebMouseEvent(event, self));
1291     [self _setMouseDownEvent:nil];
1292     return result;
1293 }
1294
1295 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
1296 {
1297     // If this is the active window or we don't have a range selection, there is no need to perform additional checks
1298     // and we can avoid making a synchronous call to the WebProcess.
1299     if ([[self window] isKeyWindow] || _data->_page->editorState().selectionIsNone || !_data->_page->editorState().selectionIsRange)
1300         return NO;
1301
1302     // There's a chance that responding to this event will run a nested event loop, and
1303     // fetching a new event might release the old one. Retaining and then autoreleasing
1304     // the current event prevents that from causing a problem inside WebKit or AppKit code.
1305     [[event retain] autorelease];
1306     
1307     if (![self hitTest:[event locationInWindow]])
1308         return NO;
1309     
1310     [self _setMouseDownEvent:event];
1311     bool result = _data->_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, self));
1312     [self _setMouseDownEvent:nil];
1313     return result;
1314 }
1315
1316 - (void)_disableComplexTextInputIfNecessary
1317 {
1318     if (!_data->_pluginComplexTextInputIdentifier)
1319         return;
1320
1321     if (_data->_pluginComplexTextInputState != PluginComplexTextInputEnabled)
1322         return;
1323
1324     // Check if the text input window has been dismissed.
1325     if (![[WKTextInputWindowController sharedTextInputWindowController] hasMarkedText])
1326         [self _setPluginComplexTextInputState:PluginComplexTextInputDisabled];
1327 }
1328
1329 - (BOOL)_handlePluginComplexTextInputKeyDown:(NSEvent *)event
1330 {
1331     ASSERT(_data->_pluginComplexTextInputIdentifier);
1332     ASSERT(_data->_pluginComplexTextInputState != PluginComplexTextInputDisabled);
1333
1334     BOOL usingLegacyCocoaTextInput = _data->_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy;
1335
1336     NSString *string = nil;
1337     BOOL didHandleEvent = [[WKTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:event usingLegacyCocoaTextInput:usingLegacyCocoaTextInput string:&string];
1338
1339     if (string) {
1340         _data->_page->sendComplexTextInputToPlugin(_data->_pluginComplexTextInputIdentifier, string);
1341
1342         if (!usingLegacyCocoaTextInput)
1343             _data->_pluginComplexTextInputState = PluginComplexTextInputDisabled;
1344     }
1345
1346     return didHandleEvent;
1347 }
1348
1349 - (BOOL)_tryHandlePluginComplexTextInputKeyDown:(NSEvent *)event
1350 {
1351     if (!_data->_pluginComplexTextInputIdentifier || _data->_pluginComplexTextInputState == PluginComplexTextInputDisabled)
1352         return NO;
1353
1354     // Check if the text input window has been dismissed and let the plug-in process know.
1355     // This is only valid with the updated Cocoa text input spec.
1356     [self _disableComplexTextInputIfNecessary];
1357
1358     // Try feeding the keyboard event directly to the plug-in.
1359     if (_data->_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy)
1360         return [self _handlePluginComplexTextInputKeyDown:event];
1361
1362     return NO;
1363 }
1364
1365 static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnderline>& result)
1366 {
1367     int length = [[string string] length];
1368     
1369     int i = 0;
1370     while (i < length) {
1371         NSRange range;
1372         NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&range inRange:NSMakeRange(i, length - i)];
1373         
1374         if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
1375             Color color = Color::black;
1376             if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName])
1377                 color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
1378             result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] > 1));
1379         }
1380         
1381         i = range.location + range.length;
1382     }
1383 }
1384
1385 #if USE(ASYNC_NSTEXTINPUTCLIENT)
1386
1387 - (void)_collectKeyboardLayoutCommandsForEvent:(NSEvent *)event to:(Vector<KeypressCommand>&)commands
1388 {
1389     if ([event type] != NSKeyDown)
1390         return;
1391
1392     ASSERT(!_data->_collectedKeypressCommands);
1393     _data->_collectedKeypressCommands = &commands;
1394
1395     if (NSTextInputContext *context = [self inputContext])
1396         [context handleEventByKeyboardLayout:event];
1397     else
1398         [self interpretKeyEvents:[NSArray arrayWithObject:event]];
1399
1400     _data->_collectedKeypressCommands = nullptr;
1401 }
1402
1403 - (void)_interpretKeyEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled, const Vector<KeypressCommand>& commands))completionHandler
1404 {
1405     // For regular Web content, input methods run before passing a keydown to DOM, but plug-ins get an opportunity to handle the event first.
1406     // There is no need to collect commands, as the plug-in cannot execute them.
1407     if (_data->_pluginComplexTextInputIdentifier) {
1408         completionHandler(NO, Vector<KeypressCommand>());
1409         return;
1410     }
1411
1412     if (![self inputContext]) {
1413         Vector<KeypressCommand> commands;
1414         [self _collectKeyboardLayoutCommandsForEvent:event to:commands];
1415         completionHandler(NO, commands);
1416         return;
1417     }
1418
1419     LOG(TextInput, "-> handleEventByInputMethod:%p %@", event, event);
1420     [[self inputContext] handleEventByInputMethod:event completionHandler:^(BOOL handled) {
1421         
1422         LOG(TextInput, "... handleEventByInputMethod%s handled", handled ? "" : " not");
1423         if (handled) {
1424             completionHandler(YES, Vector<KeypressCommand>());
1425             return;
1426         }
1427
1428         Vector<KeypressCommand> commands;
1429         [self _collectKeyboardLayoutCommandsForEvent:event to:commands];
1430         completionHandler(NO, commands);
1431     }];
1432 }
1433
1434 - (void)doCommandBySelector:(SEL)selector
1435 {
1436     LOG(TextInput, "doCommandBySelector:\"%s\"", sel_getName(selector));
1437
1438     Vector<KeypressCommand>* keypressCommands = _data->_collectedKeypressCommands;
1439
1440     if (keypressCommands) {
1441         KeypressCommand command(NSStringFromSelector(selector));
1442         keypressCommands->append(command);
1443         LOG(TextInput, "...stored");
1444         _data->_page->registerKeypressCommandName(command.commandName);
1445     } else {
1446         // FIXME: Send the command to Editor synchronously and only send it along the
1447         // responder chain if it's a selector that does not correspond to an editing command.
1448         [super doCommandBySelector:selector];
1449     }
1450 }
1451
1452 - (void)insertText:(id)string
1453 {
1454     // Unlike an NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
1455     // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
1456     // command ensures that a keypress event is dispatched as appropriate.
1457     [self insertText:string replacementRange:NSMakeRange(NSNotFound, 0)];
1458 }
1459
1460 - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
1461 {
1462     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
1463     ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
1464
1465     if (replacementRange.location != NSNotFound)
1466         LOG(TextInput, "insertText:\"%@\" replacementRange:(%u, %u)", isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
1467     else
1468         LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
1469
1470     NSString *text;
1471     Vector<TextAlternativeWithRange> dictationAlternatives;
1472
1473     bool registerUndoGroup = false;
1474     if (isAttributedString) {
1475 #if USE(DICTATION_ALTERNATIVES)
1476         collectDictationTextAlternatives(string, dictationAlternatives);
1477 #endif
1478 #if USE(INSERTION_UNDO_GROUPING)
1479         registerUndoGroup = shouldRegisterInsertionUndoGroup(string);
1480 #endif
1481         // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
1482         text = [string string];
1483     } else
1484         text = string;
1485
1486     // insertText can be called for several reasons:
1487     // - If it's from normal key event processing (including key bindings), we save the action to perform it later.
1488     // - If it's from an input method, then we should go ahead and insert the text now.
1489     // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
1490     // then we also execute it immediately, as there will be no other chance.
1491     Vector<KeypressCommand>* keypressCommands = _data->_collectedKeypressCommands;
1492     if (keypressCommands) {
1493         ASSERT(replacementRange.location == NSNotFound);
1494         KeypressCommand command("insertText:", text);
1495         keypressCommands->append(command);
1496         LOG(TextInput, "...stored");
1497         _data->_page->registerKeypressCommandName(command.commandName);
1498         return;
1499     }
1500
1501     String eventText = text;
1502     eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
1503     if (!dictationAlternatives.isEmpty())
1504         _data->_page->insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives, registerUndoGroup);
1505     else
1506         _data->_page->insertTextAsync(eventText, replacementRange, registerUndoGroup);
1507 }
1508
1509 - (void)selectedRangeWithCompletionHandler:(void(^)(NSRange selectedRange))completionHandlerPtr
1510 {
1511     RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
1512
1513     LOG(TextInput, "selectedRange");
1514     _data->_page->getSelectedRangeAsync([completionHandler](const EditingRange& editingRangeResult, CallbackBase::Error error) {
1515         void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
1516         if (error != CallbackBase::Error::None) {
1517             LOG(TextInput, "    ...selectedRange failed.");
1518             completionHandlerBlock(NSMakeRange(NSNotFound, 0));
1519             return;
1520         }
1521         NSRange result = editingRangeResult;
1522         if (result.location == NSNotFound)
1523             LOG(TextInput, "    -> selectedRange returned (NSNotFound, %llu)", result.length);
1524         else
1525             LOG(TextInput, "    -> selectedRange returned (%llu, %llu)", result.location, result.length);
1526         completionHandlerBlock(result);
1527     });
1528 }
1529
1530 - (void)markedRangeWithCompletionHandler:(void(^)(NSRange markedRange))completionHandlerPtr
1531 {
1532     RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
1533
1534     LOG(TextInput, "markedRange");
1535     _data->_page->getMarkedRangeAsync([completionHandler](const EditingRange& editingRangeResult, CallbackBase::Error error) {
1536         void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
1537         if (error != CallbackBase::Error::None) {
1538             LOG(TextInput, "    ...markedRange failed.");
1539             completionHandlerBlock(NSMakeRange(NSNotFound, 0));
1540             return;
1541         }
1542         NSRange result = editingRangeResult;
1543         if (result.location == NSNotFound)
1544             LOG(TextInput, "    -> markedRange returned (NSNotFound, %llu)", result.length);
1545         else
1546             LOG(TextInput, "    -> markedRange returned (%llu, %llu)", result.location, result.length);
1547         completionHandlerBlock(result);
1548     });
1549 }
1550
1551 - (void)hasMarkedTextWithCompletionHandler:(void(^)(BOOL hasMarkedText))completionHandlerPtr
1552 {
1553     RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
1554
1555     LOG(TextInput, "hasMarkedText");
1556     _data->_page->getMarkedRangeAsync([completionHandler](const EditingRange& editingRangeResult, CallbackBase::Error error) {
1557         void (^completionHandlerBlock)(BOOL) = (void (^)(BOOL))completionHandler.get();
1558         if (error != CallbackBase::Error::None) {
1559             LOG(TextInput, "    ...hasMarkedText failed.");
1560             completionHandlerBlock(NO);
1561             return;
1562         }
1563         BOOL hasMarkedText = editingRangeResult.location != notFound;
1564         LOG(TextInput, "    -> hasMarkedText returned %u", hasMarkedText);
1565         completionHandlerBlock(hasMarkedText);
1566     });
1567 }
1568
1569 - (void)attributedSubstringForProposedRange:(NSRange)nsRange completionHandler:(void(^)(NSAttributedString *attrString, NSRange actualRange))completionHandlerPtr
1570 {
1571     RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
1572
1573     LOG(TextInput, "attributedSubstringFromRange:(%u, %u)", nsRange.location, nsRange.length);
1574     _data->_page->attributedSubstringForCharacterRangeAsync(nsRange, [completionHandler](const AttributedString& string, const EditingRange& actualRange, CallbackBase::Error error) {
1575         void (^completionHandlerBlock)(NSAttributedString *, NSRange) = (void (^)(NSAttributedString *, NSRange))completionHandler.get();
1576         if (error != CallbackBase::Error::None) {
1577             LOG(TextInput, "    ...attributedSubstringFromRange failed.");
1578             completionHandlerBlock(0, NSMakeRange(NSNotFound, 0));
1579             return;
1580         }
1581         LOG(TextInput, "    -> attributedSubstringFromRange returned %@", [string.string.get() string]);
1582         completionHandlerBlock([[string.string.get() retain] autorelease], actualRange);
1583     });
1584 }
1585
1586 - (void)firstRectForCharacterRange:(NSRange)theRange completionHandler:(void(^)(NSRect firstRect, NSRange actualRange))completionHandlerPtr
1587 {
1588     RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
1589
1590     LOG(TextInput, "firstRectForCharacterRange:(%u, %u)", theRange.location, theRange.length);
1591
1592     // Just to match NSTextView's behavior. Regression tests cannot detect this;
1593     // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
1594     // (type something; try ranges (1, -1) and (2, -1).
1595     if ((theRange.location + theRange.length < theRange.location) && (theRange.location + theRange.length != 0))
1596         theRange.length = 0;
1597
1598     if (theRange.location == NSNotFound) {
1599         LOG(TextInput, "    -> NSZeroRect");
1600         completionHandlerPtr(NSZeroRect, theRange);
1601         return;
1602     }
1603
1604     _data->_page->firstRectForCharacterRangeAsync(theRange, [self, completionHandler](const IntRect& rect, const EditingRange& actualRange, CallbackBase::Error error) {
1605         void (^completionHandlerBlock)(NSRect, NSRange) = (void (^)(NSRect, NSRange))completionHandler.get();
1606         if (error != CallbackBase::Error::None) {
1607             LOG(TextInput, "    ...firstRectForCharacterRange failed.");
1608             completionHandlerBlock(NSZeroRect, NSMakeRange(NSNotFound, 0));
1609             return;
1610         }
1611
1612         NSRect resultRect = [self convertRect:rect toView:nil];
1613         resultRect = [self.window convertRectToScreen:resultRect];
1614
1615         LOG(TextInput, "    -> firstRectForCharacterRange returned (%f, %f, %f, %f)", resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
1616         completionHandlerBlock(resultRect, actualRange);
1617     });
1618 }
1619
1620 - (void)characterIndexForPoint:(NSPoint)thePoint completionHandler:(void(^)(NSUInteger))completionHandlerPtr
1621 {
1622     RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
1623
1624     LOG(TextInput, "characterIndexForPoint:(%f, %f)", thePoint.x, thePoint.y);
1625
1626     NSWindow *window = [self window];
1627
1628 #pragma clang diagnostic push
1629 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1630     if (window)
1631         thePoint = [window convertScreenToBase:thePoint];
1632 #pragma clang diagnostic pop
1633     thePoint = [self convertPoint:thePoint fromView:nil];  // the point is relative to the main frame
1634
1635     _data->_page->characterIndexForPointAsync(IntPoint(thePoint), [completionHandler](uint64_t result, CallbackBase::Error error) {
1636         void (^completionHandlerBlock)(NSUInteger) = (void (^)(NSUInteger))completionHandler.get();
1637         if (error != CallbackBase::Error::None) {
1638             LOG(TextInput, "    ...characterIndexForPoint failed.");
1639             completionHandlerBlock(0);
1640             return;
1641         }
1642         if (result == notFound)
1643             result = NSNotFound;
1644         LOG(TextInput, "    -> characterIndexForPoint returned %lu", result);
1645         completionHandlerBlock(result);
1646     });
1647 }
1648
1649 - (NSTextInputContext *)inputContext
1650 {
1651     if (_data->_pluginComplexTextInputIdentifier) {
1652         ASSERT(!_data->_collectedKeypressCommands); // Should not get here from -_interpretKeyEvent:completionHandler:, we only use WKTextInputWindowController after giving the plug-in a chance to handle keydown natively.
1653         return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
1654     }
1655
1656     // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
1657     if (!_data->_page->editorState().isContentEditable)
1658         return nil;
1659
1660     return [super inputContext];
1661 }
1662
1663 - (void)unmarkText
1664 {
1665     LOG(TextInput, "unmarkText");
1666
1667     _data->_page->confirmCompositionAsync();
1668 }
1669
1670 - (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
1671 {
1672     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
1673     ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
1674
1675     LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u) replacementRange:(%u, %u)", isAttributedString ? [string string] : string, selectedRange.location, selectedRange.length, replacementRange.location, replacementRange.length);
1676
1677     Vector<CompositionUnderline> underlines;
1678     NSString *text;
1679
1680     if (isAttributedString) {
1681         // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
1682         text = [string string];
1683         extractUnderlines(string, underlines);
1684     } else
1685         text = string;
1686
1687     if (_data->_inSecureInputState) {
1688         // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
1689         // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
1690         ASSERT(!_data->_page->editorState().hasComposition);
1691         [self _notifyInputContextAboutDiscardedComposition];
1692         // FIXME: We should store the command to handle it after DOM event processing, as it's regular keyboard input now, not a composition.
1693         if ([text length] == 1 && isASCII([text characterAtIndex:0]))
1694             _data->_page->insertTextAsync(text, replacementRange);
1695         else
1696             NSBeep();
1697         return;
1698     }
1699
1700     _data->_page->setCompositionAsync(text, underlines, selectedRange, replacementRange);
1701 }
1702
1703 // Synchronous NSTextInputClient is still implemented to catch spurious sync calls. Remove when that is no longer needed.
1704
1705 - (NSRange)selectedRange NO_RETURN_DUE_TO_ASSERT
1706 {
1707     ASSERT_NOT_REACHED();
1708     return NSMakeRange(NSNotFound, 0);
1709 }
1710
1711 - (BOOL)hasMarkedText NO_RETURN_DUE_TO_ASSERT
1712 {
1713     ASSERT_NOT_REACHED();
1714     return NO;
1715 }
1716
1717 - (NSRange)markedRange NO_RETURN_DUE_TO_ASSERT
1718 {
1719     ASSERT_NOT_REACHED();
1720     return NSMakeRange(NSNotFound, 0);
1721 }
1722
1723 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange NO_RETURN_DUE_TO_ASSERT
1724 {
1725     ASSERT_NOT_REACHED();
1726     return nil;
1727 }
1728
1729 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint NO_RETURN_DUE_TO_ASSERT
1730 {
1731     ASSERT_NOT_REACHED();
1732     return 0;
1733 }
1734
1735 - (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange NO_RETURN_DUE_TO_ASSERT
1736
1737     ASSERT_NOT_REACHED();
1738     return NSMakeRect(0, 0, 0, 0);
1739 }
1740
1741 - (BOOL)performKeyEquivalent:(NSEvent *)event
1742 {
1743     // There's a chance that responding to this event will run a nested event loop, and
1744     // fetching a new event might release the old one. Retaining and then autoreleasing
1745     // the current event prevents that from causing a problem inside WebKit or AppKit code.
1746     [[event retain] autorelease];
1747
1748     // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
1749     // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
1750     // Don't interpret this event again, avoiding re-entrancy and infinite loops.
1751     if ([[event charactersIgnoringModifiers] isEqualToString:@"\e"] && !([event modifierFlags] & NSDeviceIndependentModifierFlagsMask))
1752         return [super performKeyEquivalent:event];
1753
1754     if (_data->_keyDownEventBeingResent) {
1755         // WebCore has already seen the event, no need for custom processing.
1756         // Note that we can get multiple events for each event being re-sent. For example, for Cmd+'=' AppKit
1757         // first performs the original key equivalent, and if that isn't handled, it dispatches a synthetic Cmd+'+'.
1758         return [super performKeyEquivalent:event];
1759     }
1760
1761     ASSERT(event == [NSApp currentEvent]);
1762
1763     [self _disableComplexTextInputIfNecessary];
1764
1765     // Pass key combos through WebCore if there is a key binding available for
1766     // this event. This lets webpages have a crack at intercepting key-modified keypresses.
1767     // FIXME: Why is the firstResponder check needed?
1768     if (self == [[self window] firstResponder]) {
1769         [self _interpretKeyEvent:event completionHandler:^(BOOL handledByInputMethod, const Vector<KeypressCommand>& commands) {
1770             _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
1771         }];
1772         return YES;
1773     }
1774     
1775     return [super performKeyEquivalent:event];
1776 }
1777
1778 - (void)keyUp:(NSEvent *)theEvent
1779 {
1780     LOG(TextInput, "keyUp:%p %@", theEvent, theEvent);
1781
1782     [self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector<KeypressCommand>& commands) {
1783         ASSERT(!handledByInputMethod || commands.isEmpty());
1784         _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
1785     }];
1786 }
1787
1788 - (void)keyDown:(NSEvent *)theEvent
1789 {
1790     LOG(TextInput, "keyDown:%p %@%s", theEvent, theEvent, (theEvent == _data->_keyDownEventBeingResent) ? " (re-sent)" : "");
1791
1792     if ([self _tryHandlePluginComplexTextInputKeyDown:theEvent]) {
1793         LOG(TextInput, "...handled by plug-in");
1794         return;
1795     }
1796
1797     // We could be receiving a key down from AppKit if we have re-sent an event
1798     // that maps to an action that is currently unavailable (for example a copy when
1799     // there is no range selection).
1800     // If this is the case we should ignore the key down.
1801     if (_data->_keyDownEventBeingResent == theEvent) {
1802         [super keyDown:theEvent];
1803         return;
1804     }
1805
1806     [self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector<KeypressCommand>& commands) {
1807         ASSERT(!handledByInputMethod || commands.isEmpty());
1808         _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
1809     }];
1810 }
1811
1812 - (void)flagsChanged:(NSEvent *)theEvent
1813 {
1814     LOG(TextInput, "flagsChanged:%p %@", theEvent, theEvent);
1815
1816     unsigned short keyCode = [theEvent keyCode];
1817
1818     // Don't make an event from the num lock and function keys
1819     if (!keyCode || keyCode == 10 || keyCode == 63)
1820         return;
1821
1822     [self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector<KeypressCommand>& commands) {
1823         _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
1824     }];
1825 }
1826
1827 #else // USE(ASYNC_NSTEXTINPUTCLIENT)
1828
1829 - (BOOL)_interpretKeyEvent:(NSEvent *)event savingCommandsTo:(Vector<WebCore::KeypressCommand>&)commands
1830 {
1831     ASSERT(!_data->_interpretKeyEventsParameters);
1832     ASSERT(commands.isEmpty());
1833
1834     if ([event type] == NSFlagsChanged)
1835         return NO;
1836
1837     WKViewInterpretKeyEventsParameters parameters;
1838     parameters.eventInterpretationHadSideEffects = false;
1839     parameters.executingSavedKeypressCommands = false;
1840     // We assume that an input method has consumed the event, and only change this assumption if one of the NSTextInput methods is called.
1841     // We assume the IM will *not* consume hotkey sequences.
1842     parameters.consumedByIM = !([event modifierFlags] & NSCommandKeyMask);
1843     parameters.commands = &commands;
1844     _data->_interpretKeyEventsParameters = &parameters;
1845
1846     LOG(TextInput, "-> interpretKeyEvents:%p %@", event, event);
1847     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
1848
1849     _data->_interpretKeyEventsParameters = nullptr;
1850
1851     // An input method may consume an event and not tell us (e.g. when displaying a candidate window),
1852     // in which case we should not bubble the event up the DOM.
1853     if (parameters.consumedByIM) {
1854         ASSERT(commands.isEmpty());
1855         LOG(TextInput, "...event %p was consumed by an input method", event);
1856         return YES;
1857     }
1858
1859     LOG(TextInput, "...interpretKeyEvents for event %p done, returns %d", event, parameters.eventInterpretationHadSideEffects);
1860
1861     // If we have already executed all or some of the commands, the event is "handled". Note that there are additional checks on web process side.
1862     return parameters.eventInterpretationHadSideEffects;
1863 }
1864
1865 - (void)_executeSavedKeypressCommands
1866 {
1867     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
1868     if (!parameters || parameters->commands->isEmpty())
1869         return;
1870
1871     // We could be called again if the execution of one command triggers a call to selectedRange.
1872     // In this case, the state is up to date, and we don't need to execute any more saved commands to return a result.
1873     if (parameters->executingSavedKeypressCommands)
1874         return;
1875
1876     LOG(TextInput, "Executing %u saved keypress commands...", parameters->commands->size());
1877
1878     parameters->executingSavedKeypressCommands = true;
1879     parameters->eventInterpretationHadSideEffects |= _data->_page->executeKeypressCommands(*parameters->commands);
1880     parameters->commands->clear();
1881     parameters->executingSavedKeypressCommands = false;
1882
1883     LOG(TextInput, "...done executing saved keypress commands.");
1884 }
1885
1886 - (void)doCommandBySelector:(SEL)selector
1887 {
1888     LOG(TextInput, "doCommandBySelector:\"%s\"", sel_getName(selector));
1889
1890     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
1891     if (parameters)
1892         parameters->consumedByIM = false;
1893
1894     // As in insertText:replacementRange:, we assume that the call comes from an input method if there is marked text.
1895     bool isFromInputMethod = _data->_page->editorState().hasComposition;
1896
1897     if (parameters && !isFromInputMethod) {
1898         KeypressCommand command(NSStringFromSelector(selector));
1899         parameters->commands->append(command);
1900         LOG(TextInput, "...stored");
1901         _data->_page->registerKeypressCommandName(command.commandName);
1902     } else {
1903         // FIXME: Send the command to Editor synchronously and only send it along the
1904         // responder chain if it's a selector that does not correspond to an editing command.
1905         [super doCommandBySelector:selector];
1906     }
1907 }
1908
1909 - (void)insertText:(id)string
1910 {
1911     // Unlike an NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
1912     // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
1913     // command ensures that a keypress event is dispatched as appropriate.
1914     [self insertText:string replacementRange:NSMakeRange(NSNotFound, 0)];
1915 }
1916
1917 - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
1918 {
1919     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
1920     ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
1921
1922     if (replacementRange.location != NSNotFound)
1923         LOG(TextInput, "insertText:\"%@\" replacementRange:(%u, %u)", isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
1924     else
1925         LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
1926     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
1927     if (parameters)
1928         parameters->consumedByIM = false;
1929
1930     NSString *text;
1931     bool isFromInputMethod = _data->_page->editorState().hasComposition;
1932
1933     Vector<TextAlternativeWithRange> dictationAlternatives;
1934
1935     if (isAttributedString) {
1936 #if USE(DICTATION_ALTERNATIVES)
1937         collectDictationTextAlternatives(string, dictationAlternatives);
1938 #endif
1939         // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
1940         text = [string string];
1941     } else
1942         text = string;
1943
1944     // insertText can be called for several reasons:
1945     // - If it's from normal key event processing (including key bindings), we may need to save the action to perform it later.
1946     // - If it's from an input method, then we should go ahead and insert the text now. We assume it's from the input method if we have marked text.
1947     // FIXME: In theory, this could be wrong for some input methods, so we should try to find another way to determine if the call is from the input method.
1948     // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
1949     // then we also execute it immediately, as there will be no other chance.
1950     if (parameters && !isFromInputMethod) {
1951         // FIXME: Handle replacementRange in this case, too. It's known to occur in practice when canceling Press and Hold (see <rdar://11940670>).
1952         ASSERT(replacementRange.location == NSNotFound);
1953         KeypressCommand command("insertText:", text);
1954         parameters->commands->append(command);
1955         _data->_page->registerKeypressCommandName(command.commandName);
1956         return;
1957     }
1958
1959     String eventText = text;
1960     eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
1961     bool eventHandled;
1962     if (!dictationAlternatives.isEmpty())
1963         eventHandled = _data->_page->insertDictatedText(eventText, replacementRange, dictationAlternatives);
1964     else
1965         eventHandled = _data->_page->insertText(eventText, replacementRange);
1966
1967     if (parameters)
1968         parameters->eventInterpretationHadSideEffects |= eventHandled;
1969 }
1970
1971 - (NSTextInputContext *)inputContext
1972 {
1973     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
1974
1975     if (_data->_pluginComplexTextInputIdentifier && !parameters)
1976         return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
1977
1978     // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
1979     if (!_data->_page->editorState().isContentEditable)
1980         return nil;
1981
1982     return [super inputContext];
1983 }
1984
1985 - (NSRange)selectedRange
1986 {
1987     [self _executeSavedKeypressCommands];
1988
1989     EditingRange selectedRange;
1990     _data->_page->getSelectedRange(selectedRange);
1991
1992     NSRange result = selectedRange;
1993     if (result.location == NSNotFound)
1994         LOG(TextInput, "selectedRange -> (NSNotFound, %u)", result.length);
1995     else
1996         LOG(TextInput, "selectedRange -> (%u, %u)", result.location, result.length);
1997
1998     return result;
1999 }
2000
2001 - (BOOL)hasMarkedText
2002 {
2003     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
2004
2005     BOOL result;
2006     if (parameters) {
2007         result = _data->_page->editorState().hasComposition;
2008         if (result) {
2009             // A saved command can confirm a composition, but it cannot start a new one.
2010             [self _executeSavedKeypressCommands];
2011             result = _data->_page->editorState().hasComposition;
2012         }
2013     } else {
2014         EditingRange markedRange;
2015         _data->_page->getMarkedRange(markedRange);
2016         result = markedRange.location != notFound;
2017     }
2018
2019     LOG(TextInput, "hasMarkedText -> %u", result);
2020     return result;
2021 }
2022
2023 - (void)unmarkText
2024 {
2025     [self _executeSavedKeypressCommands];
2026
2027     LOG(TextInput, "unmarkText");
2028
2029     // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
2030     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
2031
2032     if (parameters) {
2033         parameters->eventInterpretationHadSideEffects = true;
2034         parameters->consumedByIM = false;
2035     }
2036
2037     _data->_page->confirmComposition();
2038 }
2039
2040 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelectedRange replacementRange:(NSRange)replacementRange
2041 {
2042     [self _executeSavedKeypressCommands];
2043
2044     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
2045     ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
2046
2047     LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelectedRange.location, newSelectedRange.length);
2048
2049     // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
2050     WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
2051
2052     if (parameters) {
2053         parameters->eventInterpretationHadSideEffects = true;
2054         parameters->consumedByIM = false;
2055     }
2056     
2057     Vector<CompositionUnderline> underlines;
2058     NSString *text;
2059
2060     if (isAttributedString) {
2061         // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
2062         text = [string string];
2063         extractUnderlines(string, underlines);
2064     } else
2065         text = string;
2066
2067     if (_data->_page->editorState().isInPasswordField) {
2068         // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
2069         // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
2070         ASSERT(!_data->_page->editorState().hasComposition);
2071         [self _notifyInputContextAboutDiscardedComposition];
2072         if ([text length] == 1 && [[text decomposedStringWithCanonicalMapping] characterAtIndex:0] < 0x80) {
2073             _data->_page->insertText(text, replacementRange);
2074         } else
2075             NSBeep();
2076         return;
2077     }
2078
2079     _data->_page->setComposition(text, underlines, newSelectedRange, replacementRange);
2080 }
2081
2082 - (NSRange)markedRange
2083 {
2084     [self _executeSavedKeypressCommands];
2085
2086     EditingRange markedRange;
2087     _data->_page->getMarkedRange(markedRange);
2088
2089     NSRange result = markedRange;
2090     if (result.location == NSNotFound)
2091         LOG(TextInput, "markedRange -> (NSNotFound, %u)", result.length);
2092     else
2093         LOG(TextInput, "markedRange -> (%u, %u)", result.location, result.length);
2094
2095     return result;
2096 }
2097
2098 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange
2099 {
2100     [self _executeSavedKeypressCommands];
2101
2102     if (!_data->_page->editorState().isContentEditable) {
2103         LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
2104         return nil;
2105     }
2106
2107     if (_data->_page->editorState().isInPasswordField)
2108         return nil;
2109
2110     AttributedString result;
2111     _data->_page->getAttributedSubstringFromRange(nsRange, result);
2112
2113     if (actualRange) {
2114         *actualRange = nsRange;
2115         actualRange->length = [result.string length];
2116     }
2117
2118     LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%@\"", nsRange.location, nsRange.length, [result.string string]);
2119     return [[result.string retain] autorelease];
2120 }
2121
2122 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
2123 {
2124     [self _executeSavedKeypressCommands];
2125
2126     NSWindow *window = [self window];
2127     
2128 #pragma clang diagnostic push
2129 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2130     if (window)
2131         thePoint = [window convertScreenToBase:thePoint];
2132 #pragma clang diagnostic pop
2133     thePoint = [self convertPoint:thePoint fromView:nil];  // the point is relative to the main frame
2134     
2135     uint64_t result = _data->_page->characterIndexForPoint(IntPoint(thePoint));
2136     if (result == notFound)
2137         result = NSNotFound;
2138     LOG(TextInput, "characterIndexForPoint:(%f, %f) -> %u", thePoint.x, thePoint.y, result);
2139     return result;
2140 }
2141
2142 - (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
2143
2144     [self _executeSavedKeypressCommands];
2145
2146     // Just to match NSTextView's behavior. Regression tests cannot detect this;
2147     // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
2148     // (type something; try ranges (1, -1) and (2, -1).
2149     if ((theRange.location + theRange.length < theRange.location) && (theRange.location + theRange.length != 0))
2150         theRange.length = 0;
2151
2152     if (theRange.location == NSNotFound) {
2153         if (actualRange)
2154             *actualRange = theRange;
2155         LOG(TextInput, "firstRectForCharacterRange:(NSNotFound, %u) -> NSZeroRect", theRange.length);
2156         return NSZeroRect;
2157     }
2158
2159     NSRect resultRect = _data->_page->firstRectForCharacterRange(theRange);
2160     resultRect = [self convertRect:resultRect toView:nil];
2161     resultRect = [self.window convertRectToScreen:resultRect];
2162
2163     if (actualRange) {
2164         // FIXME: Update actualRange to match the range of first rect.
2165         *actualRange = theRange;
2166     }
2167
2168     LOG(TextInput, "firstRectForCharacterRange:(%u, %u) -> (%f, %f, %f, %f)", theRange.location, theRange.length, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
2169     return resultRect;
2170 }
2171
2172 - (BOOL)performKeyEquivalent:(NSEvent *)event
2173 {
2174     // There's a chance that responding to this event will run a nested event loop, and
2175     // fetching a new event might release the old one. Retaining and then autoreleasing
2176     // the current event prevents that from causing a problem inside WebKit or AppKit code.
2177     [[event retain] autorelease];
2178
2179     // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
2180     // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
2181     // Don't interpret this event again, avoiding re-entrancy and infinite loops.
2182     if ([[event charactersIgnoringModifiers] isEqualToString:@"\e"] && !([event modifierFlags] & NSDeviceIndependentModifierFlagsMask))
2183         return [super performKeyEquivalent:event];
2184
2185     if (_data->_keyDownEventBeingResent) {
2186         // WebCore has already seen the event, no need for custom processing.
2187         // Note that we can get multiple events for each event being re-sent. For example, for Cmd+'=' AppKit
2188         // first performs the original key equivalent, and if that isn't handled, it dispatches a synthetic Cmd+'+'.
2189         return [super performKeyEquivalent:event];
2190     }
2191
2192     ASSERT(event == [NSApp currentEvent]);
2193
2194     [self _disableComplexTextInputIfNecessary];
2195
2196     // Pass key combos through WebCore if there is a key binding available for
2197     // this event. This lets webpages have a crack at intercepting key-modified keypresses.
2198     // FIXME: Why is the firstResponder check needed?
2199     if (self == [[self window] firstResponder]) {
2200         Vector<KeypressCommand> commands;
2201         BOOL handledByInputMethod = [self _interpretKeyEvent:event savingCommandsTo:commands];
2202         _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
2203         return YES;
2204     }
2205     
2206     return [super performKeyEquivalent:event];
2207 }
2208
2209 - (void)keyUp:(NSEvent *)theEvent
2210 {
2211     LOG(TextInput, "keyUp:%p %@", theEvent, theEvent);
2212     // We don't interpret the keyUp event, as this breaks key bindings (see <https://bugs.webkit.org/show_bug.cgi?id=130100>).
2213     _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, false, Vector<KeypressCommand>()));
2214 }
2215
2216 - (void)keyDown:(NSEvent *)theEvent
2217 {
2218     LOG(TextInput, "keyDown:%p %@%s", theEvent, theEvent, (theEvent == _data->_keyDownEventBeingResent) ? " (re-sent)" : "");
2219
2220     // There's a chance that responding to this event will run a nested event loop, and
2221     // fetching a new event might release the old one. Retaining and then autoreleasing
2222     // the current event prevents that from causing a problem inside WebKit or AppKit code.
2223     [[theEvent retain] autorelease];
2224
2225     if ([self _tryHandlePluginComplexTextInputKeyDown:theEvent]) {
2226         LOG(TextInput, "...handled by plug-in");
2227         return;
2228     }
2229
2230     // We could be receiving a key down from AppKit if we have re-sent an event
2231     // that maps to an action that is currently unavailable (for example a copy when
2232     // there is no range selection).
2233     // If this is the case we should ignore the key down.
2234     if (_data->_keyDownEventBeingResent == theEvent) {
2235         [super keyDown:theEvent];
2236         return;
2237     }
2238
2239     Vector<KeypressCommand> commands;
2240     BOOL handledByInputMethod = [self _interpretKeyEvent:theEvent savingCommandsTo:commands];
2241     if (!commands.isEmpty()) {
2242         // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
2243         // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
2244         // should be handled like normal text input after DOM event dispatch.
2245         handledByInputMethod = NO;
2246     }
2247
2248     _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
2249 }
2250
2251 - (void)flagsChanged:(NSEvent *)theEvent
2252 {
2253     LOG(TextInput, "flagsChanged:%p %@", theEvent, theEvent);
2254
2255     // There's a chance that responding to this event will run a nested event loop, and
2256     // fetching a new event might release the old one. Retaining and then autoreleasing
2257     // the current event prevents that from causing a problem inside WebKit or AppKit code.
2258     [[theEvent retain] autorelease];
2259
2260     unsigned short keyCode = [theEvent keyCode];
2261
2262     // Don't make an event from the num lock and function keys
2263     if (!keyCode || keyCode == 10 || keyCode == 63)
2264         return;
2265
2266     _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, false, Vector<KeypressCommand>()));
2267 }
2268
2269 #endif // USE(ASYNC_NSTEXTINPUTCLIENT)
2270
2271 - (NSArray *)validAttributesForMarkedText
2272 {
2273     static NSArray *validAttributes;
2274     if (!validAttributes) {
2275         validAttributes = [[NSArray alloc] initWithObjects:
2276                            NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName,
2277                            NSMarkedClauseSegmentAttributeName,
2278 #if USE(DICTATION_ALTERNATIVES)
2279                            NSTextAlternativesAttributeName,
2280 #endif
2281 #if USE(INSERTION_UNDO_GROUPING)
2282                            NSTextInsertionUndoableAttributeName,
2283 #endif
2284                            nil];
2285         // NSText also supports the following attributes, but it's
2286         // hard to tell which are really required for text input to
2287         // work well; I have not seen any input method make use of them yet.
2288         //     NSFontAttributeName, NSForegroundColorAttributeName,
2289         //     NSBackgroundColorAttributeName, NSLanguageAttributeName.
2290         CFRetain(validAttributes);
2291     }
2292     LOG(TextInput, "validAttributesForMarkedText -> (...)");
2293     return validAttributes;
2294 }
2295
2296 #if ENABLE(DRAG_SUPPORT)
2297 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
2298 {
2299     NSPoint windowImageLoc = [[self window] convertScreenToBase:aPoint];
2300     NSPoint windowMouseLoc = windowImageLoc;
2301    
2302     // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event.
2303     _data->_ignoringMouseDraggedEvents = YES;
2304     
2305     _data->_page->dragEnded(IntPoint(windowMouseLoc), globalPoint(windowMouseLoc, [self window]), operation);
2306 }
2307
2308 - (DragApplicationFlags)applicationFlags:(id <NSDraggingInfo>)draggingInfo
2309 {
2310     uint32_t flags = 0;
2311     if ([NSApp modalWindow])
2312         flags = DragApplicationIsModal;
2313     if ([[self window] attachedSheet])
2314         flags |= DragApplicationHasAttachedSheet;
2315     if ([draggingInfo draggingSource] == self)
2316         flags |= DragApplicationIsSource;
2317     if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
2318         flags |= DragApplicationIsCopyKeyDown;
2319     return static_cast<DragApplicationFlags>(flags);
2320 }
2321
2322 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2323 {
2324     IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
2325     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2326     DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
2327
2328     _data->_page->resetCurrentDragInformation();
2329     _data->_page->dragEntered(dragData, [[draggingInfo draggingPasteboard] name]);
2330     return NSDragOperationCopy;
2331 }
2332
2333 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2334 {
2335     IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
2336     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2337     DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
2338     _data->_page->dragUpdated(dragData, [[draggingInfo draggingPasteboard] name]);
2339     
2340     NSInteger numberOfValidItemsForDrop = _data->_page->currentDragNumberOfFilesToBeAccepted();
2341     NSDraggingFormation draggingFormation = NSDraggingFormationNone;
2342     if (_data->_page->currentDragIsOverFileInput() && numberOfValidItemsForDrop > 0)
2343         draggingFormation = NSDraggingFormationList;
2344
2345     if ([draggingInfo numberOfValidItemsForDrop] != numberOfValidItemsForDrop)
2346         [draggingInfo setNumberOfValidItemsForDrop:numberOfValidItemsForDrop];
2347     if ([draggingInfo draggingFormation] != draggingFormation)
2348         [draggingInfo setDraggingFormation:draggingFormation];
2349
2350     return _data->_page->currentDragOperation();
2351 }
2352
2353 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2354 {
2355     IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
2356     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2357     DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
2358     _data->_page->dragExited(dragData, [[draggingInfo draggingPasteboard] name]);
2359     _data->_page->resetCurrentDragInformation();
2360 }
2361
2362 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2363 {
2364     return YES;
2365 }
2366
2367 // FIXME: This code is more or less copied from Pasteboard::getBestURL.
2368 // It would be nice to be able to share the code somehow.
2369 static bool maybeCreateSandboxExtensionFromPasteboard(NSPasteboard *pasteboard, SandboxExtension::Handle& sandboxExtensionHandle)
2370 {
2371     NSArray *types = [pasteboard types];
2372     if (![types containsObject:NSFilenamesPboardType])
2373         return false;
2374
2375     NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
2376     if ([files count] != 1)
2377         return false;
2378
2379     NSString *file = [files objectAtIndex:0];
2380     BOOL isDirectory;
2381     if (![[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory])
2382         return false;
2383
2384     if (isDirectory)
2385         return false;
2386
2387     SandboxExtension::createHandle("/", SandboxExtension::ReadOnly, sandboxExtensionHandle);
2388     return true;
2389 }
2390
2391 static void createSandboxExtensionsForFileUpload(NSPasteboard *pasteboard, SandboxExtension::HandleArray& handles)
2392 {
2393     NSArray *types = [pasteboard types];
2394     if (![types containsObject:NSFilenamesPboardType])
2395         return;
2396
2397     NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
2398     handles.allocate([files count]);
2399     for (unsigned i = 0; i < [files count]; i++) {
2400         NSString *file = [files objectAtIndex:i];
2401         if (![[NSFileManager defaultManager] fileExistsAtPath:file])
2402             continue;
2403         SandboxExtension::Handle handle;
2404         SandboxExtension::createHandle(file, SandboxExtension::ReadOnly, handles[i]);
2405     }
2406 }
2407
2408 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2409 {
2410     IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
2411     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2412     DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
2413
2414     SandboxExtension::Handle sandboxExtensionHandle;
2415     bool createdExtension = maybeCreateSandboxExtensionFromPasteboard([draggingInfo draggingPasteboard], sandboxExtensionHandle);
2416     if (createdExtension)
2417         _data->_page->process().willAcquireUniversalFileReadSandboxExtension();
2418
2419     SandboxExtension::HandleArray sandboxExtensionForUpload;
2420     createSandboxExtensionsForFileUpload([draggingInfo draggingPasteboard], sandboxExtensionForUpload);
2421
2422     _data->_page->performDragOperation(dragData, [[draggingInfo draggingPasteboard] name], sandboxExtensionHandle, sandboxExtensionForUpload);
2423
2424     return YES;
2425 }
2426
2427 // This code is needed to support drag and drop when the drag types cannot be matched.
2428 // This is the case for elements that do not place content
2429 // in the drag pasteboard automatically when the drag start (i.e. dragging a DIV element).
2430 - (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types
2431 {
2432     if ([[self superview] mouse:*point inRect:[self frame]])
2433         return self;
2434     return nil;
2435 }
2436 #endif // ENABLE(DRAG_SUPPORT)
2437
2438 - (BOOL)_windowResizeMouseLocationIsInVisibleScrollerThumb:(NSPoint)loc
2439 {
2440     NSPoint localPoint = [self convertPoint:loc fromView:nil];
2441     NSRect visibleThumbRect = NSRect(_data->_page->visibleScrollerThumbRect());
2442     return NSMouseInRect(localPoint, visibleThumbRect, [self isFlipped]);
2443 }
2444
2445 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
2446 static void* keyValueObservingContext = &keyValueObservingContext;
2447 #endif
2448
2449 - (void)addWindowObserversForWindow:(NSWindow *)window
2450 {
2451     if (window) {
2452         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:)
2453                                                      name:NSWindowDidBecomeKeyNotification object:nil];
2454         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:)
2455                                                      name:NSWindowDidResignKeyNotification object:nil];
2456         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidMiniaturize:) 
2457                                                      name:NSWindowDidMiniaturizeNotification object:window];
2458         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidDeminiaturize:)
2459                                                      name:NSWindowDidDeminiaturizeNotification object:window];
2460         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidMove:)
2461                                                      name:NSWindowDidMoveNotification object:window];
2462         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResize:) 
2463                                                      name:NSWindowDidResizeNotification object:window];
2464         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOffScreen:) 
2465                                                      name:@"NSWindowDidOrderOffScreenNotification" object:window];
2466         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOnScreen:) 
2467                                                      name:@"_NSWindowDidBecomeVisible" object:window];
2468         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeBackingProperties:)
2469                                                      name:NSWindowDidChangeBackingPropertiesNotification object:window];
2470         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeScreen:)
2471                                                      name:NSWindowDidChangeScreenNotification object:window];
2472         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeLayerHosting:)
2473                                                      name:@"_NSWindowDidChangeContentsHostedInLayerSurfaceNotification" object:window];
2474 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
2475         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeOcclusionState:)
2476                                                      name:NSWindowDidChangeOcclusionStateNotification object:window];
2477 #endif
2478 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
2479         [window addObserver:self forKeyPath:@"contentLayoutRect" options:NSKeyValueObservingOptionInitial context:keyValueObservingContext];
2480         [window addObserver:self forKeyPath:@"titlebarAppearsTransparent" options:NSKeyValueObservingOptionInitial context:keyValueObservingContext];
2481 #endif
2482     }
2483 }
2484
2485 - (void)removeWindowObservers
2486 {
2487     NSWindow *window = [self window];
2488     if (!window)
2489         return;
2490
2491     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
2492     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
2493     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
2494     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
2495     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMoveNotification object:window];
2496     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:window];
2497     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowWillOrderOffScreenNotification" object:window];
2498     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
2499     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
2500     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
2501     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeScreenNotification object:window];
2502     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidChangeContentsHostedInLayerSurfaceNotification" object:window];
2503 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
2504     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeOcclusionStateNotification object:window];
2505 #endif
2506 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
2507     [window removeObserver:self forKeyPath:@"contentLayoutRect" context:keyValueObservingContext];
2508     [window removeObserver:self forKeyPath:@"titlebarAppearsTransparent" context:keyValueObservingContext];
2509 #endif
2510 }
2511
2512 - (void)viewWillMoveToWindow:(NSWindow *)window
2513 {
2514     NSWindow *currentWindow = [self window];
2515     if (window == currentWindow)
2516         return;
2517
2518     _data->_pageClient->viewWillMoveToAnotherWindow();
2519     
2520     [self removeWindowObservers];
2521     [self addWindowObserversForWindow:window];
2522 }
2523
2524 - (void)viewDidMoveToWindow
2525 {
2526     if ([self window]) {
2527         [self doWindowDidChangeScreen];
2528
2529         ViewState::Flags viewStateChanges = ViewState::WindowIsActive | ViewState::IsVisible;
2530         if ([self isDeferringViewInWindowChanges])
2531             _data->_viewInWindowChangeWasDeferred = YES;
2532         else
2533             viewStateChanges |= ViewState::IsInWindow;
2534         _data->_page->viewStateDidChange(viewStateChanges);
2535
2536         [self _updateWindowAndViewFrames];
2537
2538         // FIXME(135509) This call becomes unnecessary once 135509 is fixed; remove.
2539         _data->_page->layerHostingModeDidChange();
2540
2541         if (!_data->_flagsChangedEventMonitor) {
2542             _data->_flagsChangedEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSFlagsChangedMask handler:^(NSEvent *flagsChangedEvent) {
2543                 [self _postFakeMouseMovedEventForFlagsChangedEvent:flagsChangedEvent];
2544                 return flagsChangedEvent;
2545             }];
2546         }
2547
2548         [self _accessibilityRegisterUIProcessTokens];
2549     } else {
2550         ViewState::Flags viewStateChanges = ViewState::WindowIsActive | ViewState::IsVisible;
2551         if ([self isDeferringViewInWindowChanges])
2552             _data->_viewInWindowChangeWasDeferred = YES;
2553         else
2554             viewStateChanges |= ViewState::IsInWindow;
2555         _data->_page->viewStateDidChange(viewStateChanges);
2556
2557         [NSEvent removeMonitor:_data->_flagsChangedEventMonitor];
2558         _data->_flagsChangedEventMonitor = nil;
2559
2560         if (getLULookupDefinitionModuleClass())
2561             [getLULookupDefinitionModuleClass() hideDefinition];
2562         [self _dismissActionMenuPopovers];
2563     }
2564
2565     _data->_page->setIntrinsicDeviceScaleFactor([self _intrinsicDeviceScaleFactor]);
2566 }
2567
2568 - (void)doWindowDidChangeScreen
2569 {
2570     _data->_page->windowScreenDidChange((PlatformDisplayID)[[[[[self window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
2571 }
2572
2573 - (void)_windowDidBecomeKey:(NSNotification *)notification
2574 {
2575     NSWindow *keyWindow = [notification object];
2576     if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) {
2577         [self _updateSecureInputState];
2578         _data->_page->viewStateDidChange(ViewState::WindowIsActive);
2579     }
2580 }
2581
2582 - (void)_windowDidChangeScreen:(NSNotification *)notification
2583 {
2584     [self doWindowDidChangeScreen];
2585 }
2586
2587 - (void)_windowDidChangeLayerHosting:(NSNotification *)notification
2588 {
2589     _data->_page->layerHostingModeDidChange();
2590 }
2591
2592 - (void)_windowDidResignKey:(NSNotification *)notification
2593 {
2594     NSWindow *formerKeyWindow = [notification object];
2595     if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) {
2596         [self _updateSecureInputState];
2597         _data->_page->viewStateDidChange(ViewState::WindowIsActive);
2598     }
2599 }
2600
2601 - (void)_windowDidMiniaturize:(NSNotification *)notification
2602 {
2603     _data->_page->viewStateDidChange(ViewState::IsVisible);
2604 }
2605
2606 - (void)_windowDidDeminiaturize:(NSNotification *)notification
2607 {
2608     _data->_page->viewStateDidChange(ViewState::IsVisible);
2609 }
2610
2611 - (void)_windowDidMove:(NSNotification *)notification
2612 {
2613     [self _updateWindowAndViewFrames];    
2614 }
2615
2616 - (void)_windowDidResize:(NSNotification *)notification
2617 {
2618     [self _updateWindowAndViewFrames];
2619 }
2620
2621 - (void)_windowDidOrderOffScreen:(NSNotification *)notification
2622 {
2623     _data->_page->viewStateDidChange(ViewState::IsVisible | ViewState::WindowIsActive);
2624 }
2625
2626 - (void)_windowDidOrderOnScreen:(NSNotification *)notification
2627 {
2628     _data->_page->viewStateDidChange(ViewState::IsVisible | ViewState::WindowIsActive);
2629 }
2630
2631 - (void)_windowDidChangeBackingProperties:(NSNotification *)notification
2632 {
2633     CGFloat oldBackingScaleFactor = [[notification.userInfo objectForKey:NSBackingPropertyOldScaleFactorKey] doubleValue];
2634     CGFloat newBackingScaleFactor = [self _intrinsicDeviceScaleFactor]; 
2635     if (oldBackingScaleFactor == newBackingScaleFactor)
2636         return; 
2637
2638     _data->_page->setIntrinsicDeviceScaleFactor(newBackingScaleFactor);
2639 }
2640
2641 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
2642 - (void)_windowDidChangeOcclusionState:(NSNotification *)notification
2643 {
2644     _data->_page->viewStateDidChange(ViewState::IsVisible);
2645 }
2646 #endif
2647
2648 - (void)drawRect:(NSRect)rect
2649 {
2650     LOG(View, "drawRect: x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
2651     _data->_page->endPrinting();
2652 }
2653
2654 - (BOOL)isOpaque
2655 {
2656     return _data->_page->drawsBackground();
2657 }
2658
2659 - (BOOL)mouseDownCanMoveWindow
2660 {
2661     // -[NSView mouseDownCanMoveWindow] returns YES when the NSView is transparent,
2662     // but we don't want a drag in the NSView to move the window, even if it's transparent.
2663     return NO;
2664 }
2665
2666 - (void)viewDidHide
2667 {
2668     _data->_page->viewStateDidChange(ViewState::IsVisible);
2669 }
2670
2671 - (void)viewDidUnhide
2672 {
2673     _data->_page->viewStateDidChange(ViewState::IsVisible);
2674 }
2675
2676 - (void)viewDidChangeBackingProperties
2677 {
2678     NSColorSpace *colorSpace = [[self window] colorSpace];
2679     if ([colorSpace isEqualTo:_data->_colorSpace.get()])
2680         return;
2681
2682     _data->_colorSpace = nullptr;
2683     if (DrawingAreaProxy *drawingArea = _data->_page->drawingArea())
2684         drawingArea->colorSpaceDidChange();
2685 }
2686
2687 - (void)_activeSpaceDidChange:(NSNotification *)notification
2688 {
2689     _data->_page->viewStateDidChange(ViewState::IsVisible);
2690 }
2691
2692 - (void)_applicationWillTerminate:(NSNotification *)notification
2693 {
2694     _data->_page->process().context().applicationWillTerminate();
2695 }
2696
2697 - (void)_dictionaryLookupPopoverWillClose:(NSNotification *)notification
2698 {
2699     [self _setTextIndicator:nil fadeOut:NO animate:NO];
2700 }
2701
2702 - (void)_accessibilityRegisterUIProcessTokens
2703 {
2704     // Initialize remote accessibility when the window connection has been established.
2705     NSData *remoteElementToken = WKAXRemoteTokenForElement(self);
2706     NSData *remoteWindowToken = WKAXRemoteTokenForElement([self window]);
2707     IPC::DataReference elementToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteElementToken bytes]), [remoteElementToken length]);
2708     IPC::DataReference windowToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteWindowToken bytes]), [remoteWindowToken length]);
2709     _data->_page->registerUIProcessAccessibilityTokens(elementToken, windowToken);
2710 }
2711
2712 - (void)_updateRemoteAccessibilityRegistration:(BOOL)registerProcess
2713 {
2714     // When the tree is connected/disconnected, the remote accessibility registration
2715     // needs to be updated with the pid of the remote process. If the process is going
2716     // away, that information is not present in WebProcess
2717     pid_t pid = 0;
2718     if (registerProcess)
2719         pid = _data->_page->process().processIdentifier();
2720     else if (!registerProcess) {
2721         pid = WKAXRemoteProcessIdentifier(_data->_remoteAccessibilityChild.get());
2722         _data->_remoteAccessibilityChild = nil;
2723     }
2724     if (pid)
2725         WKAXRegisterRemoteProcess(registerProcess, pid); 
2726 }
2727
2728 - (void)enableAccessibilityIfNecessary
2729 {
2730     if (WebCore::AXObjectCache::accessibilityEnabled())
2731         return;
2732
2733     // After enabling accessibility update the window frame on the web process so that the
2734     // correct accessibility position is transmitted (when AX is off, that position is not calculated).
2735     WebCore::AXObjectCache::enableAccessibility();
2736     [self _updateWindowAndViewFrames];
2737 }
2738
2739 - (id)accessibilityFocusedUIElement
2740 {
2741     [self enableAccessibilityIfNecessary];
2742     return _data->_remoteAccessibilityChild.get();
2743 }
2744
2745 - (BOOL)accessibilityIsIgnored
2746 {
2747     return NO;
2748 }
2749
2750 - (id)accessibilityHitTest:(NSPoint)point
2751 {
2752     [self enableAccessibilityIfNecessary];
2753     return _data->_remoteAccessibilityChild.get();
2754 }
2755
2756 - (id)accessibilityAttributeValue:(NSString*)attribute
2757 {
2758     [self enableAccessibilityIfNecessary];
2759
2760     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2761
2762         id child = nil;
2763         if (_data->_remoteAccessibilityChild)
2764             child = _data->_remoteAccessibilityChild.get();
2765         
2766         if (!child)
2767             return nil;
2768         return [NSArray arrayWithObject:child];
2769     }
2770     if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
2771         return NSAccessibilityGroupRole;
2772     if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute])
2773         return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil);
2774     if ([attribute isEqualToString:NSAccessibilityParentAttribute])
2775         return NSAccessibilityUnignoredAncestor([self superview]);
2776     if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
2777         return [NSNumber numberWithBool:YES];
2778     
2779     return [super accessibilityAttributeValue:attribute];
2780 }
2781
2782 - (NSView *)hitTest:(NSPoint)point
2783 {
2784     NSView *hitView = [super hitTest:point];
2785     if (hitView && _data && hitView == _data->_layerHostingView)
2786         hitView = self;
2787
2788     return hitView;
2789 }
2790
2791 - (void)_postFakeMouseMovedEventForFlagsChangedEvent:(NSEvent *)flagsChangedEvent
2792 {
2793     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved location:[[flagsChangedEvent window] mouseLocationOutsideOfEventStream]
2794         modifierFlags:[flagsChangedEvent modifierFlags] timestamp:[flagsChangedEvent timestamp] windowNumber:[flagsChangedEvent windowNumber]
2795         context:[flagsChangedEvent context] eventNumber:0 clickCount:0 pressure:0];
2796     NativeWebMouseEvent webEvent(fakeEvent, self);
2797     _data->_page->handleMouseEvent(webEvent);
2798 }
2799
2800 - (NSInteger)conversationIdentifier
2801 {
2802     return (NSInteger)self;
2803 }
2804
2805 - (float)_intrinsicDeviceScaleFactor
2806 {
2807     NSWindow *window = [self window];
2808     if (window)
2809         return [window backingScaleFactor];
2810     return [[NSScreen mainScreen] backingScaleFactor];
2811 }
2812
2813 - (void)_setDrawingAreaSize:(NSSize)size
2814 {
2815     if (!_data->_page->drawingArea())
2816         return;
2817     
2818     _data->_page->drawingArea()->setSize(IntSize(size), IntSize(0, 0), IntSize(_data->_resizeScrollOffset));
2819     _data->_resizeScrollOffset = NSZeroSize;
2820 }
2821
2822 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
2823 - (void)quickLookWithEvent:(NSEvent *)event
2824 {
2825     NSPoint locationInViewCoordinates = [self convertPoint:[event locationInWindow] fromView:nil];
2826     _data->_page->performDictionaryLookupAtLocation(FloatPoint(locationInViewCoordinates.x, locationInViewCoordinates.y));
2827 }
2828 #endif
2829
2830 - (std::unique_ptr<WebKit::DrawingAreaProxy>)_createDrawingAreaProxy
2831 {
2832     if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"WebKit2UseRemoteLayerTreeDrawingArea"] boolValue])
2833         return std::make_unique<RemoteLayerTreeDrawingAreaProxy>(*_data->_page);
2834
2835     return std::make_unique<TiledCoreAnimationDrawingAreaProxy>(*_data->_page);
2836 }
2837
2838 - (BOOL)_isFocused
2839 {
2840     if (_data->_inBecomeFirstResponder)
2841         return YES;
2842     if (_data->_inResignFirstResponder)
2843         return NO;
2844     return [[self window] firstResponder] == self;
2845 }
2846
2847 - (WebKit::ColorSpaceData)_colorSpace
2848 {
2849     if (!_data->_colorSpace) {
2850         if ([self window])
2851             _data->_colorSpace = [[self window] colorSpace];
2852         else
2853             _data->_colorSpace = [[NSScreen mainScreen] colorSpace];
2854     }
2855         
2856     ColorSpaceData colorSpaceData;
2857     colorSpaceData.cgColorSpace = [_data->_colorSpace CGColorSpace];
2858
2859     return colorSpaceData;    
2860 }
2861
2862 - (void)_processDidExit
2863 {
2864     if (_data->_layerHostingView)
2865         [self _setAcceleratedCompositingModeRootLayer:nil];
2866
2867     [self _updateRemoteAccessibilityRegistration:NO];
2868
2869     _data->_gestureController = nullptr;
2870 }
2871
2872 - (void)_pageClosed
2873 {
2874     [self _updateRemoteAccessibilityRegistration:NO];
2875 }
2876
2877 - (void)_didRelaunchProcess
2878 {
2879     [self _accessibilityRegisterUIProcessTokens];
2880 }
2881
2882 - (void)_preferencesDidChange
2883 {
2884     BOOL needsViewFrameInWindowCoordinates = _data->_page->preferences().pluginsEnabled();
2885
2886     if (!!needsViewFrameInWindowCoordinates == !!_data->_needsViewFrameInWindowCoordinates)
2887         return;
2888
2889     _data->_needsViewFrameInWindowCoordinates = needsViewFrameInWindowCoordinates;
2890     if ([self window])
2891         [self _updateWindowAndViewFrames];
2892 }
2893
2894 - (void)_setUserInterfaceItemState:(NSString *)commandName enabled:(BOOL)isEnabled state:(int)newState
2895 {
2896     ValidationVector items = _data->_validationMap.take(commandName);
2897     size_t size = items.size();
2898     for (size_t i = 0; i < size; ++i) {
2899         ValidationItem item = items[i].get();
2900         [menuItem(item) setState:newState];
2901         [menuItem(item) setEnabled:isEnabled];
2902         [toolbarItem(item) setEnabled:isEnabled];
2903         // FIXME <rdar://problem/8803392>: If the item is neither a menu nor toolbar item, it will be left enabled.
2904     }
2905 }
2906
2907 - (BOOL)_tryPostProcessPluginComplexTextInputKeyDown:(NSEvent *)event
2908 {
2909     if (!_data->_pluginComplexTextInputIdentifier || _data->_pluginComplexTextInputState == PluginComplexTextInputDisabled)
2910         return NO;
2911
2912     // In the legacy text input model, the event has already been sent to the input method.
2913     if (_data->_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy)
2914         return NO;
2915
2916     return [self _handlePluginComplexTextInputKeyDown:event];
2917 }
2918
2919 - (void)_doneWithKeyEvent:(NSEvent *)event eventWasHandled:(BOOL)eventWasHandled
2920 {
2921     if ([event type] != NSKeyDown)
2922         return;
2923
2924     if ([self _tryPostProcessPluginComplexTextInputKeyDown:event])
2925         return;
2926     
2927     if (eventWasHandled) {
2928         [NSCursor setHiddenUntilMouseMoves:YES];
2929         return;
2930     }
2931
2932     // resending the event may destroy this WKView
2933     RetainPtr<WKView> protector(self);
2934
2935     ASSERT(!_data->_keyDownEventBeingResent);
2936     _data->_keyDownEventBeingResent = event;
2937     [NSApp _setCurrentEvent:event];
2938     [NSApp sendEvent:event];
2939
2940     _data->_keyDownEventBeingResent = nullptr;
2941 }
2942
2943 - (NSRect)_convertToDeviceSpace:(NSRect)rect
2944 {
2945     return toDeviceSpace(rect, [self window]);
2946 }
2947
2948 - (NSRect)_convertToUserSpace:(NSRect)rect
2949 {
2950     return toUserSpace(rect, [self window]);
2951 }
2952
2953 // Any non-zero value will do, but using something recognizable might help us debug some day.
2954 #define TRACKING_RECT_TAG 0xBADFACE
2955
2956 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
2957 {
2958     ASSERT(_data->_trackingRectOwner == nil);
2959     _data->_trackingRectOwner = owner;
2960     _data->_trackingRectUserData = data;
2961     return TRACKING_RECT_TAG;
2962 }
2963
2964 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
2965 {
2966     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
2967     ASSERT(_data->_trackingRectOwner == nil);
2968     _data->_trackingRectOwner = owner;
2969     _data->_trackingRectUserData = data;
2970     return TRACKING_RECT_TAG;
2971 }
2972
2973 - (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count
2974 {
2975     ASSERT(count == 1);
2976     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
2977     ASSERT(_data->_trackingRectOwner == nil);
2978     _data->_trackingRectOwner = owner;
2979     _data->_trackingRectUserData = userDataList[0];
2980     trackingNums[0] = TRACKING_RECT_TAG;
2981 }
2982
2983 - (void)removeTrackingRect:(NSTrackingRectTag)tag
2984 {
2985     if (!_data)
2986         return;
2987
2988     if (tag == 0)
2989         return;
2990     
2991     if (tag == TRACKING_RECT_TAG) {
2992         _data->_trackingRectOwner = nil;
2993         return;
2994     }
2995     
2996     if (tag == _data->_lastToolTipTag) {
2997         [super removeTrackingRect:tag];
2998         _data->_lastToolTipTag = 0;
2999         return;
3000     }
3001
3002     // If any other tracking rect is being removed, we don't know how it was created
3003     // and it's possible there's a leak involved (see 3500217)
3004     ASSERT_NOT_REACHED();
3005 }
3006
3007 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count
3008 {
3009     int i;
3010     for (i = 0; i < count; ++i) {
3011         int tag = tags[i];
3012         if (tag == 0)
3013             continue;
3014         ASSERT(tag == TRACKING_RECT_TAG);
3015         if (_data != nil) {
3016             _data->_trackingRectOwner = nil;
3017         }
3018     }
3019 }
3020
3021 - (void)_sendToolTipMouseExited
3022 {
3023     // Nothing matters except window, trackingNumber, and userData.
3024     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited
3025         location:NSMakePoint(0, 0)
3026         modifierFlags:0
3027         timestamp:0
3028         windowNumber:[[self window] windowNumber]
3029         context:NULL
3030         eventNumber:0
3031         trackingNumber:TRACKING_RECT_TAG
3032         userData:_data->_trackingRectUserData];
3033     [_data->_trackingRectOwner mouseExited:fakeEvent];
3034 }
3035
3036 - (void)_sendToolTipMouseEntered
3037 {
3038     // Nothing matters except window, trackingNumber, and userData.
3039     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered
3040         location:NSMakePoint(0, 0)
3041         modifierFlags:0
3042         timestamp:0
3043         windowNumber:[[self window] windowNumber]
3044         context:NULL
3045         eventNumber:0
3046         trackingNumber:TRACKING_RECT_TAG
3047         userData:_data->_trackingRectUserData];
3048     [_data->_trackingRectOwner mouseEntered:fakeEvent];
3049 }
3050
3051 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
3052 {
3053     return nsStringFromWebCoreString(_data->_page->toolTip());
3054 }
3055
3056 - (void)_toolTipChangedFrom:(NSString *)oldToolTip to:(NSString *)newToolTip
3057 {
3058     if (oldToolTip)
3059         [self _sendToolTipMouseExited];
3060
3061     if (newToolTip && [newToolTip length] > 0) {
3062         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
3063         [self removeAllToolTips];
3064         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
3065         _data->_lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL];
3066         [self _sendToolTipMouseEntered];
3067     }
3068 }
3069
3070 - (void)_setTextIndicator:(PassRefPtr<TextIndicator>)textIndicator fadeOut:(BOOL)fadeOut animate:(BOOL)animate animationCompletionHandler:(std::function<void ()>)completionHandler
3071 {
3072     if (!textIndicator) {
3073         _data->_textIndicatorWindow = nullptr;
3074         return;
3075     }
3076
3077     if (!_data->_textIndicatorWindow)
3078         _data->_textIndicatorWindow = std::make_unique<TextIndicatorWindow>(self);
3079
3080     _data->_textIndicatorWindow->setTextIndicator(textIndicator, fadeOut, animate, WTF::move(completionHandler));
3081 }
3082
3083 - (void)_setTextIndicator:(PassRefPtr<TextIndicator>)textIndicator fadeOut:(BOOL)fadeOut animate:(BOOL)animate
3084 {
3085     [self _setTextIndicator:textIndicator fadeOut:fadeOut animate:animate animationCompletionHandler:[] {}];
3086 }
3087
3088 - (CALayer *)_rootLayer
3089 {
3090     return [_data->_layerHostingView layer];
3091 }
3092
3093 - (void)_setAcceleratedCompositingModeRootLayer:(CALayer *)rootLayer
3094 {
3095     [rootLayer web_disableAllActions];
3096
3097     _data->_rootLayer = rootLayer;
3098
3099 #if WK_API_ENABLED
3100     if (_data->_thumbnailView) {
3101         [self _updateThumbnailViewLayer];
3102         return;
3103     }
3104 #endif
3105
3106     [CATransaction begin];
3107     [CATransaction setDisableActions:YES];
3108
3109     if (rootLayer) {
3110         if (!_data->_layerHostingView) {
3111             // Create an NSView that will host our layer tree.
3112             _data->_layerHostingView = adoptNS([[WKFlippedView alloc] initWithFrame:[self bounds]]);
3113             [_data->_layerHostingView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
3114
3115
3116             [self addSubview:_data->_layerHostingView.get() positioned:NSWindowBelow relativeTo:nil];
3117
3118             // Create a root layer that will back the NSView.
3119             RetainPtr<CALayer> layer = adoptNS([[CALayer alloc] init]);
3120             [layer setDelegate:[WebActionDisablingCALayerDelegate shared]];
3121 #ifndef NDEBUG
3122             [layer setName:@"Hosting root layer"];
3123 #endif
3124
3125             [_data->_layerHostingView setLayer:layer.get()];
3126             [_data->_layerHostingView setWantsLayer:YES];
3127         }
3128
3129         [_data->_layerHostingView layer].sublayers = [NSArray arrayWithObject:rootLayer];
3130     } else {
3131         if (_data->_layerHostingView) {
3132             [_data->_layerHostingView removeFromSuperview];
3133             [_data->_layerHostingView setLayer:nil];
3134             [_data->_layerHostingView setWantsLayer:NO];
3135
3136             _data->_layerHostingView = nullptr;
3137         }
3138     }
3139
3140     [CATransaction commit];
3141 }
3142
3143 - (CALayer *)_acceleratedCompositingModeRootLayer
3144 {
3145     return _data->_rootLayer.get();
3146 }
3147
3148 - (PassRefPtr<ViewSnapshot>)_takeViewSnapshot
3149 {
3150     NSWindow *window = self.window;
3151
3152     CGSWindowID windowID = (CGSWindowID)[window windowNumber];
3153     if (!windowID || ![window isVisible])
3154         return nullptr;
3155
3156     RetainPtr<CGImageRef> windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque));
3157
3158     // Work around <rdar://problem/17084993>; re-request the snapshot at kCGWindowImageNominalResolution if it was captured at the wrong scale.
3159     CGFloat desiredSnapshotWidth = window.frame.size.width * window.screen.backingScaleFactor;
3160     if (CGImageGetWidth(windowSnapshotImage.get()) != desiredSnapshotWidth)
3161         windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque | kCGWindowImageNominalResolution));
3162
3163     [self _ensureGestureController];
3164
3165     NSRect windowCaptureRect;
3166     FloatRect boundsForCustomSwipeViews = _data->_gestureController->windowRelativeBoundsForCustomSwipeViews();
3167     if (!boundsForCustomSwipeViews.isEmpty())
3168         windowCaptureRect = boundsForCustomSwipeViews;
3169     else {
3170         NSRect unobscuredBounds = self.bounds;
3171         float topContentInset = _data->_page->topContentInset();
3172         unobscuredBounds.origin.y += topContentInset;
3173         unobscuredBounds.size.height -= topContentInset;
3174         windowCaptureRect = [self convertRect:unobscuredBounds toView:nil];
3175     }
3176
3177     NSRect windowCaptureScreenRect = [window convertRectToScreen:windowCaptureRect];
3178     CGRect windowScreenRect;
3179     CGSGetScreenRectForWindow(CGSMainConnectionID(), (CGSWindowID)[window windowNumber], &windowScreenRect);
3180
3181     NSRect croppedImageRect = windowCaptureRect;
3182     croppedImageRect.origin.y = windowScreenRect.size.height - windowCaptureScreenRect.size.height - NSMinY(windowCaptureRect);
3183
3184     auto croppedSnapshotImage = adoptCF(CGImageCreateWithImageInRect(windowSnapshotImage.get(), NSRectToCGRect([window convertRectToBacking:croppedImageRect])));
3185
3186     auto surface = IOSurface::createFromImage(croppedSnapshotImage.get());
3187     if (!surface)
3188         return nullptr;
3189     surface->setIsVolatile(true);
3190
3191     return ViewSnapshot::create(surface.get(), surface->size(), surface->totalBytes());
3192 }
3193
3194 - (void)_wheelEventWasNotHandledByWebCore:(NSEvent *)event
3195 {
3196     if (_data->_gestureController)
3197         _data->_gestureController->wheelEventWasNotHandledByWebCore(event);
3198 }
3199
3200 - (void)_setAccessibilityWebProcessToken:(NSData *)data
3201 {
3202     _data->_remoteAccessibilityChild = WKAXRemoteElementForToken(data);
3203     [self _updateRemoteAccessibilityRegistration:YES];
3204 }
3205
3206 - (void)_pluginFocusOrWindowFocusChanged:(BOOL)pluginHasFocusAndWindowHasFocus pluginComplexTextInputIdentifier:(uint64_t)pluginComplexTextInputIdentifier
3207 {
3208     BOOL inputSourceChanged = _data->_pluginComplexTextInputIdentifier;
3209
3210     if (pluginHasFocusAndWindowHasFocus) {
3211         // Check if we're already allowing text input for this plug-in.
3212         if (pluginComplexTextInputIdentifier == _data->_pluginComplexTextInputIdentifier)
3213             return;
3214
3215         _data->_pluginComplexTextInputIdentifier = pluginComplexTextInputIdentifier;
3216
3217     } else {
3218         // Check if we got a request to unfocus a plug-in that isn't focused.
3219         if (pluginComplexTextInputIdentifier != _data->_pluginComplexTextInputIdentifier)
3220             return;
3221
3222         _data->_pluginComplexTextInputIdentifier = 0;
3223     }
3224
3225     if (inputSourceChanged) {
3226         // The input source changed, go ahead and discard any entered text.
3227         [[WKTextInputWindowController sharedTextInputWindowController] unmarkText];
3228     }
3229
3230     // This will force the current input context to be updated to its correct value.
3231     [NSApp updateWindows];
3232 }
3233
3234 - (void)_setPluginComplexTextInputState:(PluginComplexTextInputState)pluginComplexTextInputState pluginComplexTextInputIdentifier:(uint64_t)pluginComplexTextInputIdentifier
3235 {
3236     if (pluginComplexTextInputIdentifier != _data->_pluginComplexTextInputIdentifier) {
3237         // We're asked to update the state for a plug-in that doesn't have focus.
3238         return;
3239     }
3240
3241     [self _setPluginComplexTextInputState:pluginComplexTextInputState];
3242 }
3243
3244 - (void)_setDragImage:(NSImage *)image at:(NSPoint)clientPoint linkDrag:(BOOL)linkDrag
3245 {
3246     IntSize size([image size]);
3247     size.scale(1.0 / _data->_page->deviceScaleFactor());
3248     [image setSize:size];
3249     
3250     // The call below could release this WKView.
3251     RetainPtr<WKView> protector(self);
3252     
3253 #pragma clang diagnostic push
3254 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3255     [self dragImage:image
3256                  at:clientPoint
3257              offset:NSZeroSize
3258               event:(linkDrag) ? [NSApp currentEvent] :_data->_mouseDownEvent
3259          pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
3260              source:self
3261           slideBack:YES];
3262 #pragma clang diagnostic pop
3263 }
3264
3265 static bool matchesExtensionOrEquivalent(NSString *filename, NSString *extension)
3266 {
3267     NSString *extensionAsSuffix = [@"." stringByAppendingString:extension];
3268     return hasCaseInsensitiveSuffix(filename, extensionAsSuffix) || (stringIsCaseInsensitiveEqualToString(extension, @"jpeg")
3269                                                                      && hasCaseInsensitiveSuffix(filename, @".jpg"));
3270 }
3271
3272 - (void)_setPromisedData:(WebCore::Image *)image withFileName:(NSString *)filename withExtension:(NSString *)extension withTitle:(NSString *)title withURL:(NSString *)url withVisibleURL:(NSString *)visibleUrl withArchive:(WebCore::SharedBuffer*) archiveBuffer forPasteboard:(NSString *)pasteboardName
3273
3274 {
3275     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:pasteboardName];
3276     RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
3277     
3278     [types addObjectsFromArray:archiveBuffer ? PasteboardTypes::forImagesWithArchive() : PasteboardTypes::forImages()];
3279     [pasteboard declareTypes:types.get() owner:self];
3280     if (!matchesExtensionOrEquivalent(filename, extension))
3281         filename = [[filename stringByAppendingString:@"."] stringByAppendingString:extension];
3282
3283     [pasteboard setString:visibleUrl forType:NSStringPboardType];
3284     [pasteboard setString:visibleUrl forType:PasteboardTypes::WebURLPboardType];
3285     [pasteboard setString:title forType:PasteboardTypes::WebURLNamePboardType];
3286     [pasteboard setPropertyList:[NSArray arrayWithObjects:[NSArray arrayWithObject:visibleUrl], [NSArray arrayWithObject:title], nil] forType:PasteboardTypes::WebURLsWithTitlesPboardType];
3287     [pasteboard setPropertyList:[NSArray arrayWithObject:extension] forType:NSFilesPromisePboardType];
3288
3289     if (archiveBuffer)
3290         [pasteboard setData:archiveBuffer->createNSData().get() forType:PasteboardTypes::WebArchivePboardType];
3291
3292     _data->_promisedImage = image;
3293     _data->_promisedFilename = filename;
3294     _data->_promisedURL = url;
3295 }
3296
3297 - (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
3298 {
3299     _data->_promisedImage = 0;
3300     _data->_promisedFilename = "";
3301     _data->_promisedURL = "";
3302 }
3303
3304 - (void)pasteboard:(NSPasteboard *)pasteboard provideDataForType:(NSString *)type
3305 {
3306     // FIXME: need to support NSRTFDPboardType
3307
3308     if ([type isEqual:NSTIFFPboardType] && _data->_promisedImage) {
3309         [pasteboard setData:(NSData *)_data->_promisedImage->getTIFFRepresentation() forType:NSTIFFPboardType];
3310         _data->_promisedImage = 0;
3311     }
3312 }
3313
3314 static BOOL fileExists(NSString *path)
3315 {
3316     struct stat statBuffer;
3317     return !lstat([path fileSystemRepresentation], &statBuffer);
3318 }
3319
3320 static NSString *pathWithUniqueFilenameForPath(NSString *path)
3321 {
3322     // "Fix" the filename of the path.
3323     NSString *filename = filenameByFixingIllegalCharacters([path lastPathComponent]);
3324     path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:filename];
3325     
3326     if (fileExists(path)) {
3327         // Don't overwrite existing file by appending "-n", "-n.ext" or "-n.ext.ext" to the filename.
3328         NSString *extensions = nil;
3329         NSString *pathWithoutExtensions;
3330         NSString *lastPathComponent = [path lastPathComponent];
3331         NSRange periodRange = [lastPathComponent rangeOfString:@"."];
3332         
3333         if (periodRange.location == NSNotFound) {
3334             pathWithoutExtensions = path;
3335         } else {
3336             extensions = [lastPathComponent substringFromIndex:periodRange.location + 1];
3337             lastPathComponent = [lastPathComponent substringToIndex:periodRange.location];
3338             pathWithoutExtensions = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:lastPathComponent];
3339         }
3340         
3341         for (unsigned i = 1; ; i++) {
3342             NSString *pathWithAppendedNumber = [NSString stringWithFormat:@"%@-%d", pathWithoutExtensions, i];
3343             path = [extensions length] ? [pathWithAppendedNumber stringByAppendingPathExtension:extensions] : pathWithAppendedNumber;
3344             if (!fileExists(path))
3345                 break;
3346         }
3347     }
3348     
3349     return path;
3350 }
3351
3352 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
3353 {
3354     RetainPtr<NSFileWrapper> wrapper;
3355     RetainPtr<NSData> data;
3356     
3357     if (_data->_promisedImage) {
3358         data = _data->_promisedImage->data()->createNSData();
3359         wrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:data.get()]);
3360         [wrapper setPreferredFilename:_data->_promisedFilename];
3361     }
3362     
3363     if (!wrapper) {
3364         LOG_ERROR("Failed to create image file.");
3365         return nil;
3366     }
3367     
3368     // FIXME: Report an error if we fail to create a file.
3369     NSString *path = [[dropDestination path] stringByAppendingPathComponent:[wrapper preferredFilename]];
3370     path = pathWithUniqueFilenameForPath(path);
3371     if (![wrapper writeToURL:[NSURL fileURLWithPath:path] options:NSFileWrapperWritingWithNameUpdating originalContentsURL:nil error:nullptr])
3372         LOG_ERROR("Failed to create image file via -[NSFileWrapper writeToURL:options:originalContentsURL:error:]");
3373
3374     if (!_data->_promisedURL.isEmpty())
3375         WebCore::setMetadataURL(_data->_promisedURL, "", String(path));
3376     
3377     return [NSArray arrayWithObject:[path lastPathComponent]];
3378 }
3379
3380 - (void)_updateSecureInputState
3381 {
3382     if (![[self window] isKeyWindow] || ![self _isFocused]) {
3383         if (_data->_inSecureInputState) {
3384             DisableSecureEventInput();
3385             _data->_inSecureInputState = NO;
3386         }
3387         return;
3388     }
3389     // WKView has a single input context for all editable areas (except for plug-ins).
3390     NSTextInputContext *context = [super inputContext];
3391     bool isInPasswordField = _data->_page->editorState().isInPasswordField;
3392
3393     if (isInPasswordField) {
3394         if (!_data->_inSecureInputState)
3395             EnableSecureEventInput();
3396         static NSArray *romanInputSources = [[NSArray alloc] initWithObjects:&NSAllRomanInputSourcesLocaleIdentifier count:1];
3397         LOG(TextInput, "-> setAllowedInputSourceLocales:romanInputSources");
3398         [context setAllowedInputSourceLocales:romanInputSources];
3399     } else {
3400         if (_data->_inSecureInputState)
3401             DisableSecureEventInput();
3402         LOG(TextInput, "-> setAllowedInputSourceLocales:nil");
3403         [context setAllowedInputSourceLocales:nil];
3404     }
3405     _data->_inSecureInputState = isInPasswordField;
3406 }
3407
3408 - (void)_resetSecureInputState
3409 {
3410     if (_data->_inSecureInputState) {
3411         DisableSecureEventInput();
3412         _data->_inSecureInputState = NO;
3413     }
3414 }
3415
3416 - (void)_notifyInputContextAboutDiscardedComposition
3417 {
3418     // <rdar://problem/9359055>: -discardMarkedText can only be called for active contexts.
3419     // FIXME: We fail to ever notify the input context if something (e.g. a navigation) happens while the window is not key.
3420     // This is not a problem when the window is key, because we discard marked text on resigning first responder.
3421     if (![[self window] isKeyWindow] || self != [[self window] firstResponder])
3422         return;
3423
3424     LOG(TextInput, "-> discardMarkedText");
3425     [[super inputContext] discardMarkedText]; // Inform the input method that we won't have an inline input area despite having been asked to.
3426 }
3427
3428 #if ENABLE(FULLSCREEN_API)
3429 - (BOOL)_hasFullScreenWindowController
3430 {
3431     return (bool)_data->_fullScreenWindowController;
3432 }
3433
3434 - (WKFullScreenWindowController *)_fullScreenWindowController
3435 {
3436     if (!_data->_fullScreenWindowController)
3437         _data->_fullScreenWindowController = adoptNS([[WKFullScreenWindowController alloc] initWithWindow:[self createFullScreenWindow] webView:self]);
3438
3439     return _data->_fullScreenWindowController.get();
3440 }
3441
3442 - (void)_closeFullScreenWindowController
3443 {
3444     if (!_data->_fullScreenWindowController)
3445         return;
3446
3447     [_data->_fullScreenWindowController close];
3448     _data->_fullScreenWindowController = nullptr;
3449 }
3450 #endif
3451
3452 - (bool)_executeSavedCommandBySelector:(SEL)selector
3453 {
3454     LOG(TextInput, "Executing previously saved command %s", sel_getName(selector));
3455     // The sink does two things: 1) Tells us if the responder went unhandled, and
3456     // 2) prevents any NSBeep; we don't ever want to beep here.
3457     RetainPtr<WKResponderChainSink> sink = adoptNS([[WKResponderChainSink alloc] initWithResponderChain:self]);
3458     [super doCommandBySelector:selector];
3459     [sink detach];
3460     return ![sink didReceiveUnhandledCommand];
3461 }
3462
3463 - (void)_setIntrinsicContentSize:(NSSize)intrinsicContentSize
3464 {
3465     // If the intrinsic content size is less than the minimum layout width, the content flowed to fit,
3466     // so we can report that that dimension is flexible. If not, we need to report our intrinsic width
3467     // so that autolayout will know to provide space for us.
3468
3469     NSSize intrinsicContentSizeAcknowledgingFlexibleWidth = intrinsicContentSize;
3470     if (intrinsicContentSize.width < _data->_page->minimumLayoutSize().width())
3471         intrinsicContentSizeAcknowledgingFlexibleWidth.width = NSViewNoInstrinsicMetric;
3472
3473     _data->_intrinsicContentSize = intrinsicContentSizeAcknowledgingFlexibleWidth;
3474     [self invalidateIntrinsicContentSize];
3475 }
3476
3477 - (void)_cacheWindowBottomCornerRect
3478 {
3479     // FIXME: We should remove this code when <rdar://problem/9362085> is resolved.
3480     NSWindow *window = [self window];
3481     if (!window)
3482         return;
3483
3484     _data->_windowBottomCornerIntersectionRect = [window _intersectBottomCorner