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#import "AttributedString.h" 30#import "ChunkedUpdateDrawingAreaProxy.h" 31#import "DataReference.h" 32#import "DrawingAreaProxyImpl.h" 33#import "EditorState.h" 34#import "FindIndicator.h" 35#import "FindIndicatorWindow.h" 36#import "LayerTreeContext.h" 37#import "Logging.h" 38#import "NativeWebKeyboardEvent.h" 39#import "NativeWebMouseEvent.h" 40#import "PDFViewController.h" 41#import "PageClientImpl.h" 42#import "PasteboardTypes.h" 43#import "Region.h" 44#import "RunLoop.h" 45#import "TextChecker.h" 46#import "TextCheckerState.h" 47#import "WKAPICast.h" 48#import "WKFullScreenWindowController.h" 49#import "WKPrintingView.h" 50#import "WKStringCF.h" 51#import "WKTextInputWindowController.h" 52#import "WKViewInternal.h" 53#import "WKViewPrivate.h" 54#import "WebContext.h" 55#import "WebEventFactory.h" 56#import "WebFullScreenManagerProxy.h" 57#import "WebPage.h" 58#import "WebPageProxy.h" 59#import "WebProcessProxy.h" 60#import "WebSystemInterface.h" 61#import <QuartzCore/QuartzCore.h> 62#import <WebCore/ColorMac.h> 63#import <WebCore/DragController.h> 64#import <WebCore/DragData.h> 65#import <WebCore/LocalizedStrings.h> 66#import <WebCore/FloatRect.h> 67#import <WebCore/IntRect.h> 68#import <WebCore/KeyboardEvent.h> 69#import <WebCore/PlatformMouseEvent.h> 70#import <WebCore/PlatformScreen.h> 71#import <WebKitSystemInterface.h> 72#import <wtf/RefPtr.h> 73#import <wtf/RetainPtr.h> 74 75@interface NSApplication (WKNSApplicationDetails) 76- (void)speakString:(NSString *)string; 77- (void)_setCurrentEvent:(NSEvent *)event; 78@end 79 80@interface NSObject (WKNSTextInputContextDetails) 81- (BOOL)wantsToHandleMouseEvents; 82- (BOOL)handleMouseEvent:(NSEvent *)event; 83@end 84 85@interface NSWindow (WKNSWindowDetails) 86- (NSRect)_growBoxRect; 87- (id)_growBoxOwner; 88- (void)_setShowOpaqueGrowBoxForOwner:(id)owner; 89- (BOOL)_updateGrowBoxForWindowFrameChange; 90@end 91 92using namespace WebKit; 93using namespace WebCore; 94 95namespace WebKit { 96 97typedef id <NSValidatedUserInterfaceItem> ValidationItem; 98typedef Vector<RetainPtr<ValidationItem> > ValidationVector; 99typedef HashMap<String, ValidationVector> ValidationMap; 100 101} 102 103struct WKViewInterpretKeyEventsParameters { 104 bool eventInterpretationHadSideEffects; 105 bool consumedByIM; 106 bool executingSavedKeypressCommands; 107 Vector<KeypressCommand>* commands; 108}; 109 110@interface WKViewData : NSObject { 111@public 112 OwnPtr<PageClientImpl> _pageClient; 113 RefPtr<WebPageProxy> _page; 114 115 // For ToolTips. 116 NSToolTipTag _lastToolTipTag; 117 id _trackingRectOwner; 118 void* _trackingRectUserData; 119 120 RetainPtr<NSView> _layerHostingView; 121 122 RetainPtr<id> _remoteAccessibilityChild; 123 124 // For asynchronous validation. 125 ValidationMap _validationMap; 126 127 OwnPtr<PDFViewController> _pdfViewController; 128 129 OwnPtr<FindIndicatorWindow> _findIndicatorWindow; 130 // We keep here the event when resending it to 131 // the application to distinguish the case of a new event from one 132 // that has been already sent to WebCore. 133 RetainPtr<NSEvent> _keyDownEventBeingResent; 134 WKViewInterpretKeyEventsParameters* _interpretKeyEventsParameters; 135 136 NSSize _resizeScrollOffset; 137 138 // The identifier of the plug-in we want to send complex text input to, or 0 if there is none. 139 uint64_t _pluginComplexTextInputIdentifier; 140 141 bool _inBecomeFirstResponder; 142 bool _inResignFirstResponder; 143 NSEvent *_mouseDownEvent; 144 BOOL _ignoringMouseDraggedEvents; 145 BOOL _dragHasStarted; 146 147#if ENABLE(GESTURE_EVENTS) 148 id _endGestureMonitor; 149#endif 150 151#if ENABLE(FULLSCREEN_API) 152 RetainPtr<WKFullScreenWindowController> _fullScreenWindowController; 153#endif 154 155 BOOL _hasSpellCheckerDocumentTag; 156 NSInteger _spellCheckerDocumentTag; 157 158 BOOL _inSecureInputState; 159} 160@end 161 162@interface WKResponderChainSink : NSResponder { 163 NSResponder *_lastResponderInChain; 164 bool _didReceiveUnhandledCommand; 165} 166- (id)initWithResponderChain:(NSResponder *)chain; 167- (void)detach; 168- (bool)didReceiveUnhandledCommand; 169@end 170 171@implementation WKViewData 172@end 173 174@implementation WKView 175 176- (id)initWithFrame:(NSRect)frame 177{ 178 return [self initWithFrame:frame contextRef:toAPI(WebContext::sharedProcessContext())]; 179} 180 181- (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)contextRef 182{ 183 return [self initWithFrame:frame contextRef:contextRef pageGroupRef:nil]; 184} 185 186- (void)_registerDraggedTypes 187{ 188 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:PasteboardTypes::forEditing()]; 189 [types addObjectsFromArray:PasteboardTypes::forURL()]; 190 [self registerForDraggedTypes:[types allObjects]]; 191 [types release]; 192} 193 194- (void)_updateRemoteAccessibilityRegistration:(BOOL)registerProcess 195{ 196#if !defined(BUILDING_ON_SNOW_LEOPARD) 197 // When the tree is connected/disconnected, the remote accessibility registration 198 // needs to be updated with the pid of the remote process. If the process is going 199 // away, that information is not present in WebProcess 200 pid_t pid = 0; 201 if (registerProcess && _data->_page->process()) 202 pid = _data->_page->process()->processIdentifier(); 203 else if (!registerProcess) { 204 pid = WKAXRemoteProcessIdentifier(_data->_remoteAccessibilityChild.get()); 205 _data->_remoteAccessibilityChild = nil; 206 } 207 if (pid) 208 WKAXRegisterRemoteProcess(registerProcess, pid); 209#endif 210} 211 212- (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)contextRef pageGroupRef:(WKPageGroupRef)pageGroupRef 213{ 214 self = [super initWithFrame:frame]; 215 if (!self) 216 return nil; 217 218 [NSApp registerServicesMenuSendTypes:PasteboardTypes::forSelection() returnTypes:PasteboardTypes::forEditing()]; 219 220 InitWebCoreSystemInterface(); 221 RunLoop::initializeMainRunLoop(); 222 223 NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:frame 224 options:(NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect) 225 owner:self 226 userInfo:nil]; 227 [self addTrackingArea:trackingArea]; 228 [trackingArea release]; 229 230 _data = [[WKViewData alloc] init]; 231 232 _data->_pageClient = PageClientImpl::create(self); 233 _data->_page = toImpl(contextRef)->createWebPage(_data->_pageClient.get(), toImpl(pageGroupRef)); 234 _data->_page->initializeWebPage(); 235#if ENABLE(FULLSCREEN_API) 236 _data->_page->fullScreenManager()->setWebView(self); 237#endif 238 _data->_mouseDownEvent = nil; 239 _data->_ignoringMouseDraggedEvents = NO; 240 241 [self _registerDraggedTypes]; 242 243 WebContext::statistics().wkViewCount++; 244 245 return self; 246} 247 248- (void)dealloc 249{ 250 _data->_page->close(); 251 252 ASSERT(!_data->_inSecureInputState); 253 254 [_data release]; 255 _data = nil; 256 257 WebContext::statistics().wkViewCount--; 258 259 [super dealloc]; 260} 261 262- (WKPageRef)pageRef 263{ 264 return toAPI(_data->_page.get()); 265} 266 267- (void)setDrawsBackground:(BOOL)drawsBackground 268{ 269 _data->_page->setDrawsBackground(drawsBackground); 270} 271 272- (BOOL)drawsBackground 273{ 274 return _data->_page->drawsBackground(); 275} 276 277- (void)setDrawsTransparentBackground:(BOOL)drawsTransparentBackground 278{ 279 _data->_page->setDrawsTransparentBackground(drawsTransparentBackground); 280} 281 282- (BOOL)drawsTransparentBackground 283{ 284 return _data->_page->drawsTransparentBackground(); 285} 286 287- (BOOL)acceptsFirstResponder 288{ 289 return YES; 290} 291 292- (BOOL)becomeFirstResponder 293{ 294 NSSelectionDirection direction = [[self window] keyViewSelectionDirection]; 295 296 _data->_inBecomeFirstResponder = true; 297 298 [self _updateSecureInputState]; 299 _data->_page->viewStateDidChange(WebPageProxy::ViewIsFocused); 300 301 _data->_inBecomeFirstResponder = false; 302 303 if (direction != NSDirectSelection) 304 _data->_page->setInitialFocus(direction == NSSelectingNext); 305 306 return YES; 307} 308 309- (BOOL)resignFirstResponder 310{ 311 _data->_inResignFirstResponder = true; 312 313 if (_data->_inSecureInputState) { 314 DisableSecureEventInput(); 315 _data->_inSecureInputState = NO; 316 } 317 _data->_page->viewStateDidChange(WebPageProxy::ViewIsFocused); 318 319 _data->_inResignFirstResponder = false; 320 321 return YES; 322} 323 324- (void)viewWillStartLiveResize 325{ 326 _data->_page->viewWillStartLiveResize(); 327} 328 329- (void)viewDidEndLiveResize 330{ 331 _data->_page->viewWillEndLiveResize(); 332} 333 334- (BOOL)isFlipped 335{ 336 return YES; 337} 338 339- (void)setFrame:(NSRect)rect andScrollBy:(NSSize)offset 340{ 341 ASSERT(NSEqualSizes(_data->_resizeScrollOffset, NSZeroSize)); 342 343 _data->_resizeScrollOffset = offset; 344 [self setFrame:rect]; 345} 346 347- (void)setFrameSize:(NSSize)size 348{ 349 [super setFrameSize:size]; 350 351 if (![self frameSizeUpdatesDisabled]) 352 [self _setDrawingAreaSize:size]; 353} 354 355- (void)_updateWindowAndViewFrames 356{ 357 NSWindow *window = [self window]; 358 ASSERT(window); 359 360 NSRect windowFrameInScreenCoordinates = [window frame]; 361 NSRect viewFrameInWindowCoordinates = [self convertRect:[self frame] toView:nil]; 362 NSPoint accessibilityPosition = [[self accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue]; 363 364 _data->_page->windowAndViewFramesChanged(enclosingIntRect(windowFrameInScreenCoordinates), enclosingIntRect(viewFrameInWindowCoordinates), IntPoint(accessibilityPosition)); 365} 366 367- (void)renewGState 368{ 369 // Hide the find indicator. 370 _data->_findIndicatorWindow = nullptr; 371 372 // Update the view frame. 373 if ([self window]) 374 [self _updateWindowAndViewFrames]; 375 376 [super renewGState]; 377} 378 379typedef HashMap<SEL, String> SelectorNameMap; 380 381// Map selectors into Editor command names. 382// This is not needed for any selectors that have the same name as the Editor command. 383static const SelectorNameMap* createSelectorExceptionMap() 384{ 385 SelectorNameMap* map = new HashMap<SEL, String>; 386 387 map->add(@selector(insertNewlineIgnoringFieldEditor:), "InsertNewline"); 388 map->add(@selector(insertParagraphSeparator:), "InsertNewline"); 389 map->add(@selector(insertTabIgnoringFieldEditor:), "InsertTab"); 390 map->add(@selector(pageDown:), "MovePageDown"); 391 map->add(@selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection"); 392 map->add(@selector(pageUp:), "MovePageUp"); 393 map->add(@selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection"); 394 map->add(@selector(scrollPageDown:), "ScrollPageForward"); 395 map->add(@selector(scrollPageUp:), "ScrollPageBackward"); 396 397 return map; 398} 399 400static String commandNameForSelector(SEL selector) 401{ 402 // Check the exception map first. 403 static const SelectorNameMap* exceptionMap = createSelectorExceptionMap(); 404 SelectorNameMap::const_iterator it = exceptionMap->find(selector); 405 if (it != exceptionMap->end()) 406 return it->second; 407 408 // Remove the trailing colon. 409 // No need to capitalize the command name since Editor command names are 410 // not case sensitive. 411 const char* selectorName = sel_getName(selector); 412 size_t selectorNameLength = strlen(selectorName); 413 if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':') 414 return String(); 415 return String(selectorName, selectorNameLength - 1); 416} 417 418// Editing commands 419 420#define WEBCORE_COMMAND(command) - (void)command:(id)sender { _data->_page->executeEditCommand(commandNameForSelector(_cmd)); } 421 422WEBCORE_COMMAND(alignCenter) 423WEBCORE_COMMAND(alignJustified) 424WEBCORE_COMMAND(alignLeft) 425WEBCORE_COMMAND(alignRight) 426WEBCORE_COMMAND(copy) 427WEBCORE_COMMAND(cut) 428WEBCORE_COMMAND(delete) 429WEBCORE_COMMAND(deleteBackward) 430WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter) 431WEBCORE_COMMAND(deleteForward) 432WEBCORE_COMMAND(deleteToBeginningOfLine) 433WEBCORE_COMMAND(deleteToBeginningOfParagraph) 434WEBCORE_COMMAND(deleteToEndOfLine) 435WEBCORE_COMMAND(deleteToEndOfParagraph) 436WEBCORE_COMMAND(deleteToMark) 437WEBCORE_COMMAND(deleteWordBackward) 438WEBCORE_COMMAND(deleteWordForward) 439WEBCORE_COMMAND(ignoreSpelling) 440WEBCORE_COMMAND(indent) 441WEBCORE_COMMAND(insertBacktab) 442WEBCORE_COMMAND(insertLineBreak) 443WEBCORE_COMMAND(insertNewline) 444WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor) 445WEBCORE_COMMAND(insertParagraphSeparator) 446WEBCORE_COMMAND(insertTab) 447WEBCORE_COMMAND(insertTabIgnoringFieldEditor) 448WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight) 449WEBCORE_COMMAND(makeTextWritingDirectionNatural) 450WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft) 451WEBCORE_COMMAND(moveBackward) 452WEBCORE_COMMAND(moveBackwardAndModifySelection) 453WEBCORE_COMMAND(moveDown) 454WEBCORE_COMMAND(moveDownAndModifySelection) 455WEBCORE_COMMAND(moveForward) 456WEBCORE_COMMAND(moveForwardAndModifySelection) 457WEBCORE_COMMAND(moveLeft) 458WEBCORE_COMMAND(moveLeftAndModifySelection) 459WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection) 460WEBCORE_COMMAND(moveParagraphForwardAndModifySelection) 461WEBCORE_COMMAND(moveRight) 462WEBCORE_COMMAND(moveRightAndModifySelection) 463WEBCORE_COMMAND(moveToBeginningOfDocument) 464WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection) 465WEBCORE_COMMAND(moveToBeginningOfLine) 466WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection) 467WEBCORE_COMMAND(moveToBeginningOfParagraph) 468WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection) 469WEBCORE_COMMAND(moveToBeginningOfSentence) 470WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection) 471WEBCORE_COMMAND(moveToEndOfDocument) 472WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection) 473WEBCORE_COMMAND(moveToEndOfLine) 474WEBCORE_COMMAND(moveToEndOfLineAndModifySelection) 475WEBCORE_COMMAND(moveToEndOfParagraph) 476WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection) 477WEBCORE_COMMAND(moveToEndOfSentence) 478WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection) 479WEBCORE_COMMAND(moveToLeftEndOfLine) 480WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection) 481WEBCORE_COMMAND(moveToRightEndOfLine) 482WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection) 483WEBCORE_COMMAND(moveUp) 484WEBCORE_COMMAND(moveUpAndModifySelection) 485WEBCORE_COMMAND(moveWordBackward) 486WEBCORE_COMMAND(moveWordBackwardAndModifySelection) 487WEBCORE_COMMAND(moveWordForward) 488WEBCORE_COMMAND(moveWordForwardAndModifySelection) 489WEBCORE_COMMAND(moveWordLeft) 490WEBCORE_COMMAND(moveWordLeftAndModifySelection) 491WEBCORE_COMMAND(moveWordRight) 492WEBCORE_COMMAND(moveWordRightAndModifySelection) 493WEBCORE_COMMAND(outdent) 494WEBCORE_COMMAND(pageDown) 495WEBCORE_COMMAND(pageDownAndModifySelection) 496WEBCORE_COMMAND(pageUp) 497WEBCORE_COMMAND(pageUpAndModifySelection) 498WEBCORE_COMMAND(paste) 499WEBCORE_COMMAND(pasteAsPlainText) 500WEBCORE_COMMAND(scrollPageDown) 501WEBCORE_COMMAND(scrollPageUp) 502WEBCORE_COMMAND(scrollToBeginningOfDocument) 503WEBCORE_COMMAND(scrollToEndOfDocument) 504WEBCORE_COMMAND(selectAll) 505WEBCORE_COMMAND(selectLine) 506WEBCORE_COMMAND(selectParagraph) 507WEBCORE_COMMAND(selectSentence) 508WEBCORE_COMMAND(selectToMark) 509WEBCORE_COMMAND(selectWord) 510WEBCORE_COMMAND(setMark) 511WEBCORE_COMMAND(subscript) 512WEBCORE_COMMAND(superscript) 513WEBCORE_COMMAND(swapWithMark) 514WEBCORE_COMMAND(takeFindStringFromSelection) 515WEBCORE_COMMAND(transpose) 516WEBCORE_COMMAND(underline) 517WEBCORE_COMMAND(unscript) 518WEBCORE_COMMAND(yank) 519WEBCORE_COMMAND(yankAndSelect) 520 521#undef WEBCORE_COMMAND 522 523// This method is needed to support Mac OS X services. 524 525- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types 526{ 527 Vector<String> pasteboardTypes; 528 size_t numTypes = [types count]; 529 for (size_t i = 0; i < numTypes; ++i) 530 pasteboardTypes.append([types objectAtIndex:i]); 531 return _data->_page->writeSelectionToPasteboard([pasteboard name], pasteboardTypes); 532} 533 534// This method is needed to support Mac OS X services. 535 536- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType 537{ 538 BOOL isValidSendType = !sendType || ([PasteboardTypes::forSelection() containsObject:sendType] && !_data->_page->editorState().selectionIsNone); 539 BOOL isValidReturnType = NO; 540 if (!returnType) 541 isValidReturnType = YES; 542 else if ([PasteboardTypes::forEditing() containsObject:returnType] && _data->_page->editorState().isContentEditable) { 543 // We can insert strings in any editable context. We can insert other types, like images, only in rich edit contexts. 544 isValidReturnType = _data->_page->editorState().isContentRichlyEditable || [returnType isEqualToString:NSStringPboardType]; 545 } 546 if (isValidSendType && isValidReturnType) 547 return self; 548 return [[self nextResponder] validRequestorForSendType:sendType returnType:returnType]; 549} 550 551// This method is needed to support Mac OS X services. 552 553- (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard 554{ 555 return _data->_page->readSelectionFromPasteboard([pasteboard name]); 556} 557 558/* 559 560When possible, editing-related methods should be implemented in WebCore with the 561EditorCommand mechanism and invoked via WEBCORE_COMMAND, rather than implementing 562individual methods here with Mac-specific code. 563 564Editing-related methods still unimplemented that are implemented in WebKit1: 565 566- (void)capitalizeWord:(id)sender; 567- (void)centerSelectionInVisibleArea:(id)sender; 568- (void)changeFont:(id)sender; 569- (void)complete:(id)sender; 570- (void)copyFont:(id)sender; 571- (void)lowercaseWord:(id)sender; 572- (void)makeBaseWritingDirectionLeftToRight:(id)sender; 573- (void)makeBaseWritingDirectionNatural:(id)sender; 574- (void)makeBaseWritingDirectionRightToLeft:(id)sender; 575- (void)pasteFont:(id)sender; 576- (void)scrollLineDown:(id)sender; 577- (void)scrollLineUp:(id)sender; 578- (void)showGuessPanel:(id)sender; 579- (void)uppercaseWord:(id)sender; 580 581Some other editing-related methods still unimplemented: 582 583- (void)changeCaseOfLetter:(id)sender; 584- (void)copyRuler:(id)sender; 585- (void)insertContainerBreak:(id)sender; 586- (void)insertDoubleQuoteIgnoringSubstitution:(id)sender; 587- (void)insertSingleQuoteIgnoringSubstitution:(id)sender; 588- (void)pasteRuler:(id)sender; 589- (void)toggleRuler:(id)sender; 590- (void)transposeWords:(id)sender; 591 592*/ 593 594// Menu items validation 595 596static NSMenuItem *menuItem(id <NSValidatedUserInterfaceItem> item) 597{ 598 if (![(NSObject *)item isKindOfClass:[NSMenuItem class]]) 599 return nil; 600 return (NSMenuItem *)item; 601} 602 603static NSToolbarItem *toolbarItem(id <NSValidatedUserInterfaceItem> item) 604{ 605 if (![(NSObject *)item isKindOfClass:[NSToolbarItem class]]) 606 return nil; 607 return (NSToolbarItem *)item; 608} 609 610static void validateCommandCallback(WKStringRef commandName, bool isEnabled, int32_t state, WKErrorRef error, void* context) 611{ 612 // If the process exits before the command can be validated, we'll be called back with an error. 613 if (error) 614 return; 615 616 WKView* wkView = static_cast<WKView*>(context); 617 ASSERT(wkView); 618 619 [wkView _setUserInterfaceItemState:nsStringFromWebCoreString(toImpl(commandName)->string()) enabled:isEnabled state:state]; 620} 621 622- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 623{ 624 SEL action = [item action]; 625 626 if (action == @selector(showGuessPanel:)) { 627 if (NSMenuItem *menuItem = ::menuItem(item)) 628 [menuItem setTitle:contextMenuItemTagShowSpellingPanel(![[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible])]; 629 return _data->_page->editorState().isContentEditable; 630 } 631 632 if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:)) 633 return _data->_page->editorState().isContentEditable; 634 635 if (action == @selector(toggleContinuousSpellChecking:)) { 636 bool enabled = TextChecker::isContinuousSpellCheckingAllowed(); 637 bool checked = enabled && TextChecker::state().isContinuousSpellCheckingEnabled; 638 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 639 return enabled; 640 } 641 642 if (action == @selector(toggleGrammarChecking:)) { 643 bool checked = TextChecker::state().isGrammarCheckingEnabled; 644 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 645 return YES; 646 } 647 648 if (action == @selector(toggleAutomaticSpellingCorrection:)) { 649 bool checked = TextChecker::state().isAutomaticSpellingCorrectionEnabled; 650 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 651 return _data->_page->editorState().isContentEditable; 652 } 653 654 if (action == @selector(orderFrontSubstitutionsPanel:)) { 655 if (NSMenuItem *menuItem = ::menuItem(item)) 656 [menuItem setTitle:contextMenuItemTagShowSubstitutions(![[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible])]; 657 return _data->_page->editorState().isContentEditable; 658 } 659 660 if (action == @selector(toggleSmartInsertDelete:)) { 661 bool checked = _data->_page->isSmartInsertDeleteEnabled(); 662 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 663 return _data->_page->editorState().isContentEditable; 664 } 665 666 if (action == @selector(toggleAutomaticQuoteSubstitution:)) { 667 bool checked = TextChecker::state().isAutomaticQuoteSubstitutionEnabled; 668 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 669 return _data->_page->editorState().isContentEditable; 670 } 671 672 if (action == @selector(toggleAutomaticDashSubstitution:)) { 673 bool checked = TextChecker::state().isAutomaticDashSubstitutionEnabled; 674 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 675 return _data->_page->editorState().isContentEditable; 676 } 677 678 if (action == @selector(toggleAutomaticLinkDetection:)) { 679 bool checked = TextChecker::state().isAutomaticLinkDetectionEnabled; 680 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 681 return _data->_page->editorState().isContentEditable; 682 } 683 684 if (action == @selector(toggleAutomaticTextReplacement:)) { 685 bool checked = TextChecker::state().isAutomaticTextReplacementEnabled; 686 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 687 return _data->_page->editorState().isContentEditable; 688 } 689 690 if (action == @selector(uppercaseWord:) || action == @selector(lowercaseWord:) || action == @selector(capitalizeWord:)) 691 return _data->_page->editorState().selectionIsRange && _data->_page->editorState().isContentEditable; 692 693 if (action == @selector(stopSpeaking:)) 694 return [NSApp isSpeaking]; 695 696 // Next, handle editor commands. Start by returning YES for anything that is not an editor command. 697 // Returning YES is the default thing to do in an AppKit validate method for any selector that is not recognized. 698 String commandName = commandNameForSelector([item action]); 699 if (!Editor::commandIsSupportedFromMenuOrKeyBinding(commandName)) 700 return YES; 701 702 // Add this item to the vector of items for a given command that are awaiting validation. 703 pair<ValidationMap::iterator, bool> addResult = _data->_validationMap.add(commandName, ValidationVector()); 704 addResult.first->second.append(item); 705 if (addResult.second) { 706 // If we are not already awaiting validation for this command, start the asynchronous validation process. 707 // FIXME: Theoretically, there is a race here; when we get the answer it might be old, from a previous time 708 // we asked for the same command; there is no guarantee the answer is still valid. 709 _data->_page->validateCommand(commandName, ValidateCommandCallback::create(self, validateCommandCallback)); 710 } 711 712 // Treat as enabled until we get the result back from the web process and _setUserInterfaceItemState is called. 713 // FIXME <rdar://problem/8803459>: This means disabled items will flash enabled at first for a moment. 714 // But returning NO here would be worse; that would make keyboard commands such as command-C fail. 715 return YES; 716} 717 718static void speakString(WKStringRef string, WKErrorRef error, void*) 719{ 720 if (error) 721 return; 722 if (!string) 723 return; 724 725 NSString *convertedString = toImpl(string)->string(); 726 [NSApp speakString:convertedString]; 727} 728 729- (IBAction)startSpeaking:(id)sender 730{ 731 _data->_page->getSelectionOrContentsAsString(StringCallback::create(0, speakString)); 732} 733 734- (IBAction)stopSpeaking:(id)sender 735{ 736 [NSApp stopSpeaking:sender]; 737} 738 739- (IBAction)showGuessPanel:(id)sender 740{ 741 NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; 742 if (!checker) { 743 LOG_ERROR("No NSSpellChecker"); 744 return; 745 } 746 747 NSPanel *spellingPanel = [checker spellingPanel]; 748 if ([spellingPanel isVisible]) { 749 [spellingPanel orderOut:sender]; 750 return; 751 } 752 753 _data->_page->advanceToNextMisspelling(true); 754 [spellingPanel orderFront:sender]; 755} 756 757- (IBAction)checkSpelling:(id)sender 758{ 759 _data->_page->advanceToNextMisspelling(false); 760} 761 762- (void)changeSpelling:(id)sender 763{ 764 NSString *word = [[sender selectedCell] stringValue]; 765 766 _data->_page->changeSpellingToWord(word); 767} 768 769- (IBAction)toggleContinuousSpellChecking:(id)sender 770{ 771 bool spellCheckingEnabled = !TextChecker::state().isContinuousSpellCheckingEnabled; 772 TextChecker::setContinuousSpellCheckingEnabled(spellCheckingEnabled); 773 774 _data->_page->process()->updateTextCheckerState(); 775} 776 777- (BOOL)isGrammarCheckingEnabled 778{ 779 return TextChecker::state().isGrammarCheckingEnabled; 780} 781 782- (void)setGrammarCheckingEnabled:(BOOL)flag 783{ 784 if (static_cast<bool>(flag) == TextChecker::state().isGrammarCheckingEnabled) 785 return; 786 787 TextChecker::setGrammarCheckingEnabled(flag); 788 _data->_page->process()->updateTextCheckerState(); 789} 790 791- (IBAction)toggleGrammarChecking:(id)sender 792{ 793 bool grammarCheckingEnabled = !TextChecker::state().isGrammarCheckingEnabled; 794 TextChecker::setGrammarCheckingEnabled(grammarCheckingEnabled); 795 796 _data->_page->process()->updateTextCheckerState(); 797} 798 799- (IBAction)toggleAutomaticSpellingCorrection:(id)sender 800{ 801 TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled); 802 803 _data->_page->process()->updateTextCheckerState(); 804} 805 806- (void)orderFrontSubstitutionsPanel:(id)sender 807{ 808 NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; 809 if (!checker) { 810 LOG_ERROR("No NSSpellChecker"); 811 return; 812 } 813 814 NSPanel *substitutionsPanel = [checker substitutionsPanel]; 815 if ([substitutionsPanel isVisible]) { 816 [substitutionsPanel orderOut:sender]; 817 return; 818 } 819 [substitutionsPanel orderFront:sender]; 820} 821 822- (IBAction)toggleSmartInsertDelete:(id)sender 823{ 824 _data->_page->setSmartInsertDeleteEnabled(!_data->_page->isSmartInsertDeleteEnabled()); 825} 826 827- (BOOL)isAutomaticQuoteSubstitutionEnabled 828{ 829 return TextChecker::state().isAutomaticQuoteSubstitutionEnabled; 830} 831 832- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag 833{ 834 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticQuoteSubstitutionEnabled) 835 return; 836 837 TextChecker::setAutomaticQuoteSubstitutionEnabled(flag); 838 _data->_page->process()->updateTextCheckerState(); 839} 840 841- (void)toggleAutomaticQuoteSubstitution:(id)sender 842{ 843 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled); 844 _data->_page->process()->updateTextCheckerState(); 845} 846 847- (BOOL)isAutomaticDashSubstitutionEnabled 848{ 849 return TextChecker::state().isAutomaticDashSubstitutionEnabled; 850} 851 852- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag 853{ 854 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticDashSubstitutionEnabled) 855 return; 856 857 TextChecker::setAutomaticDashSubstitutionEnabled(flag); 858 _data->_page->process()->updateTextCheckerState(); 859} 860 861- (void)toggleAutomaticDashSubstitution:(id)sender 862{ 863 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled); 864 _data->_page->process()->updateTextCheckerState(); 865} 866 867- (BOOL)isAutomaticLinkDetectionEnabled 868{ 869 return TextChecker::state().isAutomaticLinkDetectionEnabled; 870} 871 872- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag 873{ 874 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticLinkDetectionEnabled) 875 return; 876 877 TextChecker::setAutomaticLinkDetectionEnabled(flag); 878 _data->_page->process()->updateTextCheckerState(); 879} 880 881- (void)toggleAutomaticLinkDetection:(id)sender 882{ 883 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled); 884 _data->_page->process()->updateTextCheckerState(); 885} 886 887- (BOOL)isAutomaticTextReplacementEnabled 888{ 889 return TextChecker::state().isAutomaticTextReplacementEnabled; 890} 891 892- (void)setAutomaticTextReplacementEnabled:(BOOL)flag 893{ 894 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticTextReplacementEnabled) 895 return; 896 897 TextChecker::setAutomaticTextReplacementEnabled(flag); 898 _data->_page->process()->updateTextCheckerState(); 899} 900 901- (void)toggleAutomaticTextReplacement:(id)sender 902{ 903 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled); 904 _data->_page->process()->updateTextCheckerState(); 905} 906 907- (void)uppercaseWord:(id)sender 908{ 909 _data->_page->uppercaseWord(); 910} 911 912- (void)lowercaseWord:(id)sender 913{ 914 _data->_page->lowercaseWord(); 915} 916 917- (void)capitalizeWord:(id)sender 918{ 919 _data->_page->capitalizeWord(); 920} 921 922// Events 923 924// Override this so that AppKit will send us arrow keys as key down events so we can 925// support them via the key bindings mechanism. 926- (BOOL)_wantsKeyDownForEvent:(NSEvent *)event 927{ 928 return YES; 929} 930 931- (void)_setMouseDownEvent:(NSEvent *)event 932{ 933 ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown); 934 935 if (event == _data->_mouseDownEvent) 936 return; 937 938 [_data->_mouseDownEvent release]; 939 _data->_mouseDownEvent = [event retain]; 940} 941 942#define NATIVE_MOUSE_EVENT_HANDLER(Selector) \ 943 - (void)Selector:(NSEvent *)theEvent \ 944 { \ 945 if ([[self inputContext] handleEvent:theEvent]) { \ 946 LOG(TextInput, "%s was handled by text input context", String(#Selector).substring(0, String(#Selector).find("Internal")).ascii().data()); \ 947 return; \ 948 } \ 949 NativeWebMouseEvent webEvent(theEvent, self); \ 950 _data->_page->handleMouseEvent(webEvent); \ 951 } 952 953NATIVE_MOUSE_EVENT_HANDLER(mouseEntered) 954NATIVE_MOUSE_EVENT_HANDLER(mouseExited) 955NATIVE_MOUSE_EVENT_HANDLER(mouseMovedInternal) 956NATIVE_MOUSE_EVENT_HANDLER(mouseDownInternal) 957NATIVE_MOUSE_EVENT_HANDLER(mouseUpInternal) 958NATIVE_MOUSE_EVENT_HANDLER(mouseDraggedInternal) 959NATIVE_MOUSE_EVENT_HANDLER(otherMouseDown) 960NATIVE_MOUSE_EVENT_HANDLER(otherMouseDragged) 961NATIVE_MOUSE_EVENT_HANDLER(otherMouseMoved) 962NATIVE_MOUSE_EVENT_HANDLER(otherMouseUp) 963NATIVE_MOUSE_EVENT_HANDLER(rightMouseDown) 964NATIVE_MOUSE_EVENT_HANDLER(rightMouseDragged) 965NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp) 966 967#undef NATIVE_MOUSE_EVENT_HANDLER 968 969#define EVENT_HANDLER(Selector, Type) \ 970 - (void)Selector:(NSEvent *)theEvent \ 971 { \ 972 Web##Type##Event webEvent = WebEventFactory::createWeb##Type##Event(theEvent, self); \ 973 _data->_page->handle##Type##Event(webEvent); \ 974 } 975 976EVENT_HANDLER(scrollWheel, Wheel) 977 978#undef EVENT_HANDLER 979 980- (void)mouseMoved:(NSEvent *)event 981{ 982 // When a view is first responder, it gets mouse moved events even when the mouse is outside its visible rect. 983 if (self == [[self window] firstResponder] && !NSPointInRect([self convertPoint:[event locationInWindow] fromView:nil], [self visibleRect])) 984 return; 985 986 [self mouseMovedInternal:event]; 987} 988 989- (void)mouseDown:(NSEvent *)event 990{ 991 [self _setMouseDownEvent:event]; 992 _data->_ignoringMouseDraggedEvents = NO; 993 _data->_dragHasStarted = NO; 994 [self mouseDownInternal:event]; 995} 996 997- (void)mouseUp:(NSEvent *)event 998{ 999 [self _setMouseDownEvent:nil]; 1000 [self mouseUpInternal:event]; 1001} 1002 1003- (void)mouseDragged:(NSEvent *)event 1004{ 1005 if (_data->_ignoringMouseDraggedEvents) 1006 return; 1007 [self mouseDraggedInternal:event]; 1008} 1009 1010- (BOOL)acceptsFirstMouse:(NSEvent *)event 1011{ 1012 // There's a chance that responding to this event will run a nested event loop, and 1013 // fetching a new event might release the old one. Retaining and then autoreleasing 1014 // the current event prevents that from causing a problem inside WebKit or AppKit code. 1015 [[event retain] autorelease]; 1016 1017 if (![self hitTest:[event locationInWindow]]) 1018 return NO; 1019 1020 [self _setMouseDownEvent:event]; 1021 bool result = _data->_page->acceptsFirstMouse([event eventNumber], WebEventFactory::createWebMouseEvent(event, self)); 1022 [self _setMouseDownEvent:nil]; 1023 return result; 1024} 1025 1026- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event 1027{ 1028 // If this is the active window or we don't have a range selection, there is no need to perform additional checks 1029 // and we can avoid making a synchronous call to the WebProcess. 1030 if ([[self window] isKeyWindow] || _data->_page->editorState().selectionIsNone || !_data->_page->editorState().selectionIsRange) 1031 return NO; 1032 1033 // There's a chance that responding to this event will run a nested event loop, and 1034 // fetching a new event might release the old one. Retaining and then autoreleasing 1035 // the current event prevents that from causing a problem inside WebKit or AppKit code. 1036 [[event retain] autorelease]; 1037 1038 if (![self hitTest:[event locationInWindow]]) 1039 return NO; 1040 1041 [self _setMouseDownEvent:event]; 1042 bool result = _data->_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, self)); 1043 [self _setMouseDownEvent:nil]; 1044 return result; 1045} 1046 1047#if ENABLE(GESTURE_EVENTS) 1048 1049static const short kIOHIDEventTypeScroll = 6; 1050 1051- (void)shortCircuitedEndGestureWithEvent:(NSEvent *)event 1052{ 1053 if ([event subtype] != kIOHIDEventTypeScroll) 1054 return; 1055 1056 WebGestureEvent webEvent = WebEventFactory::createWebGestureEvent(event, self); 1057 _data->_page->handleGestureEvent(webEvent); 1058 1059 if (_data->_endGestureMonitor) { 1060 [NSEvent removeMonitor:_data->_endGestureMonitor]; 1061 _data->_endGestureMonitor = nil; 1062 } 1063} 1064 1065- (void)beginGestureWithEvent:(NSEvent *)event 1066{ 1067 if ([event subtype] != kIOHIDEventTypeScroll) 1068 return; 1069 1070 WebGestureEvent webEvent = WebEventFactory::createWebGestureEvent(event, self); 1071 _data->_page->handleGestureEvent(webEvent); 1072 1073 if (!_data->_endGestureMonitor) { 1074 _data->_endGestureMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskEndGesture handler:^(NSEvent *blockEvent) { 1075 [self shortCircuitedEndGestureWithEvent:blockEvent]; 1076 return blockEvent; 1077 }]; 1078 } 1079} 1080#endif 1081 1082- (void)doCommandBySelector:(SEL)selector 1083{ 1084 LOG(TextInput, "doCommandBySelector:\"%s\"", sel_getName(selector)); 1085 1086 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1087 if (parameters) 1088 parameters->consumedByIM = false; 1089 1090 // As in insertText:replacementRange:, we assume that the call comes from an input method if there is marked text. 1091 bool isFromInputMethod = _data->_page->editorState().hasComposition; 1092 1093 if (parameters && !isFromInputMethod) 1094 parameters->commands->append(KeypressCommand(NSStringFromSelector(selector))); 1095 else { 1096 // FIXME: Send the command to Editor synchronously and only send it along the 1097 // responder chain if it's a selector that does not correspond to an editing command. 1098 [super doCommandBySelector:selector]; 1099 } 1100} 1101 1102- (void)insertText:(id)string 1103{ 1104 // Unlike and NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context, 1105 // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText 1106 // command ensures that a keypress event is dispatched as appropriate. 1107 [self insertText:string replacementRange:NSMakeRange(NSNotFound, 0)]; 1108} 1109 1110- (void)insertText:(id)string replacementRange:(NSRange)replacementRange 1111{ 1112 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; 1113 ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]); 1114 1115 if (replacementRange.location != NSNotFound) 1116 LOG(TextInput, "insertText:\"%@\" replacementRange:(%u, %u)", isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length); 1117 else 1118 LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string); 1119 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1120 if (parameters) 1121 parameters->consumedByIM = false; 1122 1123 NSString *text; 1124 bool isFromInputMethod = _data->_page->editorState().hasComposition; 1125 1126 if (isAttributedString) { 1127 // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data. 1128 text = [string string]; 1129 } else 1130 text = string; 1131 1132 // insertText can be called for several reasons: 1133 // - If it's from normal key event processing (including key bindings), we may need to save the action to perform it later. 1134 // - 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. 1135 // 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. 1136 // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse), 1137 // then we also execute it immediately, as there will be no other chance. 1138 if (parameters && !isFromInputMethod) { 1139 ASSERT(replacementRange.location == NSNotFound); 1140 parameters->commands->append(KeypressCommand("insertText:", text)); 1141 return; 1142 } 1143 1144 String eventText = text; 1145 eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore 1146 bool eventHandled = _data->_page->insertText(eventText, replacementRange.location, NSMaxRange(replacementRange)); 1147 1148 if (parameters) 1149 parameters->eventInterpretationHadSideEffects |= eventHandled; 1150} 1151 1152- (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event 1153{ 1154 if (!_data->_page->editorState().isContentEditable) 1155 return NO; 1156 1157 if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) != NSCommandKeyMask) 1158 return NO; 1159 1160 // Here we special case cmd+b and cmd+i but not cmd+u, for historic reason. 1161 // This should not be changed, since it could break some Mac applications that 1162 // rely on this inherent behavior. 1163 // See https://bugs.webkit.org/show_bug.cgi?id=24943 1164 1165 NSString *string = [event characters]; 1166 if ([string caseInsensitiveCompare:@"b"] == NSOrderedSame) { 1167 _data->_page->executeEditCommand("ToggleBold"); 1168 return YES; 1169 } 1170 if ([string caseInsensitiveCompare:@"i"] == NSOrderedSame) { 1171 _data->_page->executeEditCommand("ToggleItalic"); 1172 return YES; 1173 } 1174 1175 return NO; 1176} 1177 1178- (BOOL)performKeyEquivalent:(NSEvent *)event 1179{ 1180 // There's a chance that responding to this event will run a nested event loop, and 1181 // fetching a new event might release the old one. Retaining and then autoreleasing 1182 // the current event prevents that from causing a problem inside WebKit or AppKit code. 1183 [[event retain] autorelease]; 1184 1185 BOOL eventWasSentToWebCore = (_data->_keyDownEventBeingResent == event); 1186 1187 // Pass key combos through WebCore if there is a key binding available for 1188 // this event. This lets web pages have a crack at intercepting key-modified keypresses. 1189 // But don't do it if we have already handled the event. 1190 // Pressing Esc results in a fake event being sent - don't pass it to WebCore. 1191 if (!eventWasSentToWebCore && event == [NSApp currentEvent] && self == [[self window] firstResponder]) { 1192 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, self)); 1193 return YES; 1194 } 1195 1196 return [self _handleStyleKeyEquivalent:event] || [super performKeyEquivalent:event]; 1197} 1198 1199- (void)keyUp:(NSEvent *)theEvent 1200{ 1201 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self)); 1202} 1203 1204- (void)keyDown:(NSEvent *)theEvent 1205{ 1206 // There's a chance that responding to this event will run a nested event loop, and 1207 // fetching a new event might release the old one. Retaining and then autoreleasing 1208 // the current event prevents that from causing a problem inside WebKit or AppKit code. 1209 [[theEvent retain] autorelease]; 1210 1211 if (_data->_pluginComplexTextInputIdentifier) { 1212 // Try feeding the keyboard event directly to the plug-in. 1213 NSString *string = nil; 1214 if ([[WKTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:theEvent string:&string]) { 1215 if (string) 1216 _data->_page->sendComplexTextInputToPlugin(_data->_pluginComplexTextInputIdentifier, string); 1217 return; 1218 } 1219 } 1220 1221 // We could be receiving a key down from AppKit if we have re-sent an event 1222 // that maps to an action that is currently unavailable (for example a copy when 1223 // there is no range selection). 1224 // If this is the case we should ignore the key down. 1225 if (_data->_keyDownEventBeingResent == theEvent) { 1226 [super keyDown:theEvent]; 1227 return; 1228 } 1229 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self)); 1230} 1231 1232- (void)flagsChanged:(NSEvent *)theEvent 1233{ 1234 // There's a chance that responding to this event will run a nested event loop, and 1235 // fetching a new event might release the old one. Retaining and then autoreleasing 1236 // the current event prevents that from causing a problem inside WebKit or AppKit code. 1237 [[theEvent retain] autorelease]; 1238 1239 unsigned short keyCode = [theEvent keyCode]; 1240 1241 // Don't make an event from the num lock and function keys 1242 if (!keyCode || keyCode == 10 || keyCode == 63) 1243 return; 1244 1245 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self)); 1246} 1247 1248- (void)_executeSavedKeypressCommands 1249{ 1250 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1251 if (!parameters || parameters->commands->isEmpty()) 1252 return; 1253 1254 // We could be called again if the execution of one command triggers a call to selectedRange. 1255 // In this case, the state is up to date, and we don't need to execute any more saved commands to return a result. 1256 if (parameters->executingSavedKeypressCommands) 1257 return; 1258 1259 parameters->executingSavedKeypressCommands = true; 1260 parameters->eventInterpretationHadSideEffects |= _data->_page->executeKeypressCommands(*parameters->commands); 1261 parameters->commands->clear(); 1262 parameters->executingSavedKeypressCommands = false; 1263} 1264 1265- (NSTextInputContext *)inputContext 1266{ 1267 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1268 1269 if (_data->_pluginComplexTextInputIdentifier && !parameters) 1270 return [[WKTextInputWindowController sharedTextInputWindowController] inputContext]; 1271 1272 // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working. 1273 if (!_data->_page->editorState().isContentEditable) 1274 return nil; 1275 1276 return [super inputContext]; 1277} 1278 1279- (NSRange)selectedRange 1280{ 1281 [self _executeSavedKeypressCommands]; 1282 1283 uint64_t selectionStart; 1284 uint64_t selectionLength; 1285 _data->_page->getSelectedRange(selectionStart, selectionLength); 1286 1287 NSRange result = NSMakeRange(selectionStart, selectionLength); 1288 if (result.location == NSNotFound) 1289 LOG(TextInput, "selectedRange -> (NSNotFound, %u)", result.length); 1290 else 1291 LOG(TextInput, "selectedRange -> (%u, %u)", result.location, result.length); 1292 1293 return result; 1294} 1295 1296- (BOOL)hasMarkedText 1297{ 1298 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1299 1300 BOOL result; 1301 if (parameters) { 1302 result = _data->_page->editorState().hasComposition; 1303 if (result) { 1304 // A saved command can confirm a composition, but it cannot start a new one. 1305 [self _executeSavedKeypressCommands]; 1306 result = _data->_page->editorState().hasComposition; 1307 } 1308 } else { 1309 uint64_t location; 1310 uint64_t length; 1311 _data->_page->getMarkedRange(location, length); 1312 result = location != NSNotFound; 1313 } 1314 1315 LOG(TextInput, "hasMarkedText -> %u", result); 1316 return result; 1317} 1318 1319- (void)unmarkText 1320{ 1321 [self _executeSavedKeypressCommands]; 1322 1323 LOG(TextInput, "unmarkText"); 1324 1325 // Use pointer to get parameters passed to us by the caller of interpretKeyEvents. 1326 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1327 1328 if (parameters) { 1329 parameters->eventInterpretationHadSideEffects = true; 1330 parameters->consumedByIM = false; 1331 } 1332 1333 _data->_page->confirmComposition(); 1334} 1335 1336- (NSArray *)validAttributesForMarkedText 1337{ 1338 static NSArray *validAttributes; 1339 if (!validAttributes) { 1340 validAttributes = [[NSArray alloc] initWithObjects: 1341 NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName, 1342 NSMarkedClauseSegmentAttributeName, nil]; 1343 // NSText also supports the following attributes, but it's 1344 // hard to tell which are really required for text input to 1345 // work well; I have not seen any input method make use of them yet. 1346 // NSFontAttributeName, NSForegroundColorAttributeName, 1347 // NSBackgroundColorAttributeName, NSLanguageAttributeName. 1348 CFRetain(validAttributes); 1349 } 1350 LOG(TextInput, "validAttributesForMarkedText -> (...)"); 1351 return validAttributes; 1352} 1353 1354static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnderline>& result) 1355{ 1356 int length = [[string string] length]; 1357 1358 int i = 0; 1359 while (i < length) { 1360 NSRange range; 1361 NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&range inRange:NSMakeRange(i, length - i)]; 1362 1363 if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) { 1364 Color color = Color::black; 1365 if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName]) 1366 color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]); 1367 result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] > 1)); 1368 } 1369 1370 i = range.location + range.length; 1371 } 1372} 1373 1374- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange replacementRange:(NSRange)replacementRange 1375{ 1376 [self _executeSavedKeypressCommands]; 1377 1378 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; 1379 ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]); 1380 1381 LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelRange.location, newSelRange.length); 1382 1383 // Use pointer to get parameters passed to us by the caller of interpretKeyEvents. 1384 WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters; 1385 1386 if (parameters) { 1387 parameters->eventInterpretationHadSideEffects = true; 1388 parameters->consumedByIM = false; 1389 } 1390 1391 Vector<CompositionUnderline> underlines; 1392 NSString *text; 1393 1394 if (isAttributedString) { 1395 // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation. 1396 text = [string string]; 1397 extractUnderlines(string, underlines); 1398 } else 1399 text = string; 1400 1401 if (_data->_page->editorState().isInPasswordField) { 1402 // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField. 1403 // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard. 1404 ASSERT(!_data->_page->editorState().hasComposition); 1405 [[super inputContext] discardMarkedText]; // Inform the input method that we won't have an inline input area despite having been asked to. 1406 if ([text length] == 1 && [[text decomposedStringWithCanonicalMapping] characterAtIndex:0] < 0x80) { 1407 _data->_page->insertText(text, replacementRange.location, NSMaxRange(replacementRange)); 1408 } else 1409 NSBeep(); 1410 return; 1411 } 1412 1413 _data->_page->setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange), replacementRange.location, NSMaxRange(replacementRange)); 1414} 1415 1416- (NSRange)markedRange 1417{ 1418 [self _executeSavedKeypressCommands]; 1419 1420 uint64_t location; 1421 uint64_t length; 1422 _data->_page->getMarkedRange(location, length); 1423 1424 LOG(TextInput, "markedRange -> (%u, %u)", location, length); 1425 return NSMakeRange(location, length); 1426} 1427 1428- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange 1429{ 1430 [self _executeSavedKeypressCommands]; 1431 1432 if (!_data->_page->editorState().isContentEditable) { 1433 LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length); 1434 return nil; 1435 } 1436 1437 if (_data->_page->editorState().isInPasswordField) 1438 return nil; 1439 1440 AttributedString result; 1441 _data->_page->getAttributedSubstringFromRange(nsRange.location, NSMaxRange(nsRange), result); 1442 1443 if (actualRange) 1444 *actualRange = nsRange; 1445 1446 LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%@\"", nsRange.location, nsRange.length, [result.string.get() string]); 1447 return [[result.string.get() retain] autorelease]; 1448} 1449 1450- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 1451{ 1452 [self _executeSavedKeypressCommands]; 1453 1454 NSWindow *window = [self window]; 1455 1456 if (window) 1457 thePoint = [window convertScreenToBase:thePoint]; 1458 thePoint = [self convertPoint:thePoint fromView:nil]; // the point is relative to the main frame 1459 1460 uint64_t result = _data->_page->characterIndexForPoint(IntPoint(thePoint)); 1461 LOG(TextInput, "characterIndexForPoint:(%f, %f) -> %u", thePoint.x, thePoint.y, result); 1462 return result; 1463} 1464 1465- (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange 1466{ 1467 [self _executeSavedKeypressCommands]; 1468 1469 // Just to match NSTextView's behavior. Regression tests cannot detect this; 1470 // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682 1471 // (type something; try ranges (1, -1) and (2, -1). 1472 if ((theRange.location + theRange.length < theRange.location) && (theRange.location + theRange.length != 0)) 1473 theRange.length = 0; 1474 1475 NSRect resultRect = _data->_page->firstRectForCharacterRange(theRange.location, theRange.length); 1476 resultRect = [self convertRect:resultRect toView:nil]; 1477 1478 NSWindow *window = [self window]; 1479 if (window) 1480 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; 1481 1482 if (actualRange) 1483 *actualRange = theRange; 1484 1485 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); 1486 return resultRect; 1487} 1488 1489- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation 1490{ 1491 NSPoint windowImageLoc = [[self window] convertScreenToBase:aPoint]; 1492 NSPoint windowMouseLoc = windowImageLoc; 1493 1494 // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event. 1495 _data->_ignoringMouseDraggedEvents = YES; 1496 1497 _data->_page->dragEnded(IntPoint(windowMouseLoc), globalPoint(windowMouseLoc, [self window]), operation); 1498} 1499 1500- (DragApplicationFlags)applicationFlags:(id <NSDraggingInfo>)draggingInfo 1501{ 1502 uint32_t flags = 0; 1503 if ([NSApp modalWindow]) 1504 flags = DragApplicationIsModal; 1505 if ([[self window] attachedSheet]) 1506 flags |= DragApplicationHasAttachedSheet; 1507 if ([draggingInfo draggingSource] == self) 1508 flags |= DragApplicationIsSource; 1509 if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) 1510 flags |= DragApplicationIsCopyKeyDown; 1511 return static_cast<DragApplicationFlags>(flags); 1512} 1513 1514- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo 1515{ 1516 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1517 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1518 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1519 1520 _data->_page->resetDragOperation(); 1521 _data->_page->dragEntered(&dragData, [[draggingInfo draggingPasteboard] name]); 1522 return NSDragOperationCopy; 1523} 1524 1525- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo 1526{ 1527 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1528 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1529 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1530 _data->_page->dragUpdated(&dragData, [[draggingInfo draggingPasteboard] name]); 1531 return _data->_page->dragOperation(); 1532} 1533 1534- (void)draggingExited:(id <NSDraggingInfo>)draggingInfo 1535{ 1536 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1537 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1538 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1539 _data->_page->dragExited(&dragData, [[draggingInfo draggingPasteboard] name]); 1540 _data->_page->resetDragOperation(); 1541} 1542 1543- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo 1544{ 1545 return YES; 1546} 1547 1548// FIXME: This code is more or less copied from Pasteboard::getBestURL. 1549// It would be nice to be able to share the code somehow. 1550static void maybeCreateSandboxExtensionFromPasteboard(NSPasteboard *pasteboard, SandboxExtension::Handle& sandboxExtensionHandle) 1551{ 1552 NSArray *types = [pasteboard types]; 1553 if (![types containsObject:NSFilenamesPboardType]) 1554 return; 1555 1556 NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType]; 1557 if ([files count] != 1) 1558 return; 1559 1560 NSString *file = [files objectAtIndex:0]; 1561 BOOL isDirectory; 1562 if (![[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory]) 1563 return; 1564 1565 if (isDirectory) 1566 return; 1567 1568 SandboxExtension::createHandle("/", SandboxExtension::ReadOnly, sandboxExtensionHandle); 1569} 1570 1571- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo 1572{ 1573 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1574 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1575 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1576 1577 SandboxExtension::Handle sandboxExtensionHandle; 1578 maybeCreateSandboxExtensionFromPasteboard([draggingInfo draggingPasteboard], sandboxExtensionHandle); 1579 1580 _data->_page->performDrag(&dragData, [[draggingInfo draggingPasteboard] name], sandboxExtensionHandle); 1581 1582 return YES; 1583} 1584 1585// This code is needed to support drag and drop when the drag types cannot be matched. 1586// This is the case for elements that do not place content 1587// in the drag pasteboard automatically when the drag start (i.e. dragging a DIV element). 1588- (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types 1589{ 1590 if ([[self superview] mouse:*point inRect:[self frame]]) 1591 return self; 1592 return nil; 1593} 1594 1595- (void)_updateWindowVisibility 1596{ 1597 _data->_page->updateWindowIsVisible(![[self window] isMiniaturized]); 1598} 1599 1600- (BOOL)_ownsWindowGrowBox 1601{ 1602 NSWindow* window = [self window]; 1603 if (!window) 1604 return NO; 1605 1606 NSView *superview = [self superview]; 1607 if (!superview) 1608 return NO; 1609 1610 NSRect growBoxRect = [window _growBoxRect]; 1611 if (NSIsEmptyRect(growBoxRect)) 1612 return NO; 1613 1614 NSRect visibleRect = [self visibleRect]; 1615 if (NSIsEmptyRect(visibleRect)) 1616 return NO; 1617 1618 NSRect visibleRectInWindowCoords = [self convertRect:visibleRect toView:nil]; 1619 if (!NSIntersectsRect(growBoxRect, visibleRectInWindowCoords)) 1620 return NO; 1621 1622 return YES; 1623} 1624 1625- (BOOL)_updateGrowBoxForWindowFrameChange 1626{ 1627 // Temporarily enable the resize indicator to make a the _ownsWindowGrowBox calculation work. 1628 BOOL wasShowingIndicator = [[self window] showsResizeIndicator]; 1629 if (!wasShowingIndicator) 1630 [[self window] setShowsResizeIndicator:YES]; 1631 1632 BOOL ownsGrowBox = [self _ownsWindowGrowBox]; 1633 _data->_page->setWindowResizerSize(ownsGrowBox ? enclosingIntRect([[self window] _growBoxRect]).size() : IntSize()); 1634 1635 if (ownsGrowBox) 1636 [[self window] _setShowOpaqueGrowBoxForOwner:(_data->_page->hasHorizontalScrollbar() || _data->_page->hasVerticalScrollbar() ? self : nil)]; 1637 else 1638 [[self window] _setShowOpaqueGrowBoxForOwner:nil]; 1639 1640 // Once WebCore can draw the window resizer, this should read: 1641 // if (wasShowingIndicator) 1642 // [[self window] setShowsResizeIndicator:!ownsGrowBox]; 1643 if (!wasShowingIndicator) 1644 [[self window] setShowsResizeIndicator:NO]; 1645 1646 return ownsGrowBox; 1647} 1648 1649- (void)addWindowObserversForWindow:(NSWindow *)window 1650{ 1651 if (window) { 1652 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) 1653 name:NSWindowDidBecomeKeyNotification object:nil]; 1654 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) 1655 name:NSWindowDidResignKeyNotification object:nil]; 1656 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidMiniaturize:) 1657 name:NSWindowDidMiniaturizeNotification object:window]; 1658 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidDeminiaturize:) 1659 name:NSWindowDidDeminiaturizeNotification object:window]; 1660 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowFrameDidChange:) 1661 name:NSWindowDidMoveNotification object:window]; 1662 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowFrameDidChange:) 1663 name:NSWindowDidResizeNotification object:window]; 1664 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOffScreen:) 1665 name:@"NSWindowDidOrderOffScreenNotification" object:window]; 1666 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOnScreen:) 1667 name:@"_NSWindowDidBecomeVisible" object:window]; 1668 } 1669} 1670 1671- (void)removeWindowObservers 1672{ 1673 NSWindow *window = [self window]; 1674 if (!window) 1675 return; 1676 1677 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; 1678 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; 1679 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMiniaturizeNotification object:window]; 1680 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window]; 1681 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMoveNotification object:window]; 1682 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:window]; 1683 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window]; 1684 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window]; 1685} 1686 1687- (void)viewWillMoveToWindow:(NSWindow *)window 1688{ 1689 NSWindow *currentWindow = [self window]; 1690 if (window == currentWindow) 1691 return; 1692 1693 [self removeWindowObservers]; 1694 [self addWindowObserversForWindow:window]; 1695 1696 if ([currentWindow _growBoxOwner] == self) 1697 [currentWindow _setShowOpaqueGrowBoxForOwner:nil]; 1698} 1699 1700- (void)viewDidMoveToWindow 1701{ 1702 // We want to make sure to update the active state while hidden, so if the view is about to become visible, we 1703 // update the active state first and then make it visible. If the view is about to be hidden, we hide it first and then 1704 // update the active state. 1705 if ([self window]) { 1706 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive); 1707 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible | WebPageProxy::ViewIsInWindow); 1708 [self _updateWindowVisibility]; 1709 [self _updateWindowAndViewFrames]; 1710 1711 // Initialize remote accessibility when the window connection has been established. 1712#if !defined(BUILDING_ON_SNOW_LEOPARD) 1713 NSData *remoteElementToken = WKAXRemoteTokenForElement(self); 1714 NSData *remoteWindowToken = WKAXRemoteTokenForElement([self accessibilityAttributeValue:NSAccessibilityWindowAttribute]); 1715 CoreIPC::DataReference elementToken = CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([remoteElementToken bytes]), [remoteElementToken length]); 1716 CoreIPC::DataReference windowToken = CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([remoteWindowToken bytes]), [remoteWindowToken length]); 1717 _data->_page->registerUIProcessAccessibilityTokens(elementToken, windowToken); 1718#endif 1719 1720 } else { 1721 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1722 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive | WebPageProxy::ViewIsInWindow); 1723 1724#if ENABLE(GESTURE_EVENTS) 1725 if (_data->_endGestureMonitor) { 1726 [NSEvent removeMonitor:_data->_endGestureMonitor]; 1727 _data->_endGestureMonitor = nil; 1728 } 1729#endif 1730#if !defined(BUILDING_ON_SNOW_LEOPARD) 1731 WKHideWordDefinitionWindow(); 1732#endif 1733 } 1734} 1735 1736- (void)_windowDidBecomeKey:(NSNotification *)notification 1737{ 1738 NSWindow *keyWindow = [notification object]; 1739 if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) { 1740 [self _updateSecureInputState]; 1741 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive); 1742 } 1743} 1744 1745- (void)_windowDidResignKey:(NSNotification *)notification 1746{ 1747 NSWindow *formerKeyWindow = [notification object]; 1748 if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) { 1749 [self _updateSecureInputState]; 1750 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive); 1751 } 1752} 1753 1754- (void)_windowDidMiniaturize:(NSNotification *)notification 1755{ 1756 [self _updateWindowVisibility]; 1757} 1758 1759- (void)_windowDidDeminiaturize:(NSNotification *)notification 1760{ 1761 [self _updateWindowVisibility]; 1762} 1763 1764- (void)_windowFrameDidChange:(NSNotification *)notification 1765{ 1766 [self _updateWindowAndViewFrames]; 1767} 1768 1769- (void)_windowDidOrderOffScreen:(NSNotification *)notification 1770{ 1771 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1772} 1773 1774- (void)_windowDidOrderOnScreen:(NSNotification *)notification 1775{ 1776 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1777} 1778 1779static void drawPageBackground(CGContextRef context, WebPageProxy* page, const IntRect& rect) 1780{ 1781 if (!page->drawsBackground()) 1782 return; 1783 1784 CGContextSaveGState(context); 1785 CGContextSetBlendMode(context, kCGBlendModeCopy); 1786 1787 CGColorRef backgroundColor; 1788 if (page->drawsTransparentBackground()) 1789 backgroundColor = CGColorGetConstantColor(kCGColorClear); 1790 else 1791 backgroundColor = CGColorGetConstantColor(kCGColorWhite); 1792 1793 CGContextSetFillColorWithColor(context, backgroundColor); 1794 CGContextFillRect(context, rect); 1795 1796 CGContextRestoreGState(context); 1797} 1798 1799- (void)drawRect:(NSRect)rect 1800{ 1801 LOG(View, "drawRect: x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 1802 _data->_page->endPrinting(); 1803 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); 1804 1805 if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(_data->_page->drawingArea())) { 1806 const NSRect *rectsBeingDrawn; 1807 NSInteger numRectsBeingDrawn; 1808 [self getRectsBeingDrawn:&rectsBeingDrawn count:&numRectsBeingDrawn]; 1809 for (NSInteger i = 0; i < numRectsBeingDrawn; ++i) { 1810 Region unpaintedRegion; 1811 IntRect rect = enclosingIntRect(rectsBeingDrawn[i]); 1812 drawingArea->paint(context, rect, unpaintedRegion); 1813 1814 Vector<IntRect> unpaintedRects = unpaintedRegion.rects(); 1815 for (size_t i = 0; i < unpaintedRects.size(); ++i) 1816 drawPageBackground(context, _data->_page.get(), unpaintedRects[i]); 1817 } 1818 } else 1819 drawPageBackground(context, _data->_page.get(), enclosingIntRect(rect)); 1820 1821 _data->_page->didDraw(); 1822} 1823 1824- (BOOL)isOpaque 1825{ 1826 return _data->_page->drawsBackground(); 1827} 1828 1829- (BOOL)mouseDownCanMoveWindow 1830{ 1831 // -[NSView mouseDownCanMoveWindow] returns YES when the NSView is transparent, 1832 // but we don't want a drag in the NSView to move the window, even if it's transparent. 1833 return NO; 1834} 1835 1836- (void)viewDidHide 1837{ 1838 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1839} 1840 1841- (void)viewDidUnhide 1842{ 1843 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1844} 1845 1846- (id)accessibilityFocusedUIElement 1847{ 1848 if (_data->_pdfViewController) 1849 return NSAccessibilityUnignoredDescendant(_data->_pdfViewController->pdfView()); 1850 1851 return _data->_remoteAccessibilityChild.get(); 1852} 1853 1854- (BOOL)accessibilityIsIgnored 1855{ 1856 return NO; 1857} 1858 1859- (id)accessibilityHitTest:(NSPoint)point 1860{ 1861 if (_data->_pdfViewController) 1862 return [_data->_pdfViewController->pdfView() accessibilityHitTest:point]; 1863 1864 return _data->_remoteAccessibilityChild.get(); 1865} 1866 1867- (id)accessibilityAttributeValue:(NSString*)attribute 1868{ 1869 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { 1870 1871 id child = nil; 1872 if (_data->_pdfViewController) 1873 child = NSAccessibilityUnignoredDescendant(_data->_pdfViewController->pdfView()); 1874 else if (_data->_remoteAccessibilityChild) 1875 child = _data->_remoteAccessibilityChild.get(); 1876 1877 if (!child) 1878 return nil; 1879 return [NSArray arrayWithObject:child]; 1880 } 1881 if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) 1882 return NSAccessibilityGroupRole; 1883 if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) 1884 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil); 1885 if ([attribute isEqualToString:NSAccessibilityParentAttribute]) 1886 return NSAccessibilityUnignoredAncestor([self superview]); 1887 if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) 1888 return [NSNumber numberWithBool:YES]; 1889 1890 return [super accessibilityAttributeValue:attribute]; 1891} 1892 1893- (NSView *)hitTest:(NSPoint)point 1894{ 1895 NSView *hitView = [super hitTest:point]; 1896 if (hitView && _data && hitView == _data->_layerHostingView) 1897 hitView = self; 1898 1899 return hitView; 1900} 1901 1902- (NSInteger)conversationIdentifier 1903{ 1904 return (NSInteger)self; 1905} 1906 1907 1908- (BOOL)canChangeFrameLayout:(WKFrameRef)frameRef 1909{ 1910 // PDF documents are already paginated, so we can't change them to add headers and footers. 1911 return !toImpl(frameRef)->isMainFrame() || !_data->_pdfViewController; 1912} 1913 1914- (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo forFrame:(WKFrameRef)frameRef 1915{ 1916 LOG(View, "Creating an NSPrintOperation for frame '%s'", toImpl(frameRef)->url().utf8().data()); 1917 1918 // Only the top frame can currently contain a PDF view. 1919 if (_data->_pdfViewController) { 1920 if (!toImpl(frameRef)->isMainFrame()) 1921 return 0; 1922 return _data->_pdfViewController->makePrintOperation(printInfo); 1923 } else { 1924 RetainPtr<WKPrintingView> printingView(AdoptNS, [[WKPrintingView alloc] initWithFrameProxy:toImpl(frameRef) view:self]); 1925 // NSPrintOperation takes ownership of the view. 1926 NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:printingView.get()]; 1927 [printOperation setCanSpawnSeparateThread:YES]; 1928 [printOperation setJobTitle:toImpl(frameRef)->title()]; 1929 printingView->_printOperation = printOperation; 1930 return printOperation; 1931 } 1932} 1933 1934@end 1935 1936@implementation WKView (Internal) 1937 1938- (PassOwnPtr<WebKit::DrawingAreaProxy>)_createDrawingAreaProxy 1939{ 1940 return DrawingAreaProxyImpl::create(_data->_page.get()); 1941} 1942 1943- (BOOL)_isFocused 1944{ 1945 if (_data->_inBecomeFirstResponder) 1946 return YES; 1947 if (_data->_inResignFirstResponder) 1948 return NO; 1949 return [[self window] firstResponder] == self; 1950} 1951 1952- (void)_processDidCrash 1953{ 1954 [self setNeedsDisplay:YES]; 1955 [self _updateRemoteAccessibilityRegistration:NO]; 1956} 1957 1958- (void)_pageClosed 1959{ 1960 [self _updateRemoteAccessibilityRegistration:NO]; 1961} 1962 1963- (void)_didRelaunchProcess 1964{ 1965 [self setNeedsDisplay:YES]; 1966} 1967 1968- (void)_setCursor:(NSCursor *)cursor 1969{ 1970 if ([NSCursor currentCursor] == cursor) 1971 return; 1972 [cursor set]; 1973} 1974 1975- (void)_setUserInterfaceItemState:(NSString *)commandName enabled:(BOOL)isEnabled state:(int)newState 1976{ 1977 ValidationVector items = _data->_validationMap.take(commandName); 1978 size_t size = items.size(); 1979 for (size_t i = 0; i < size; ++i) { 1980 ValidationItem item = items[i].get(); 1981 [menuItem(item) setState:newState]; 1982 [menuItem(item) setEnabled:isEnabled]; 1983 [toolbarItem(item) setEnabled:isEnabled]; 1984 // FIXME <rdar://problem/8803392>: If the item is neither a menu nor toolbar item, it will be left enabled. 1985 } 1986} 1987 1988- (void)_resendKeyDownEvent:(NSEvent *)event 1989{ 1990 ASSERT(!_data->_keyDownEventBeingResent); 1991 _data->_keyDownEventBeingResent = event; 1992 [NSApp _setCurrentEvent:event]; 1993 [NSApp sendEvent:event]; 1994 1995 _data->_keyDownEventBeingResent = nullptr; 1996} 1997 1998- (BOOL)_interpretKeyEvent:(NSEvent *)event savingCommandsTo:(Vector<WebCore::KeypressCommand>&)commands 1999{ 2000 ASSERT(!_data->_interpretKeyEventsParameters); 2001 ASSERT(commands.isEmpty()); 2002 2003 if ([event type] == NSFlagsChanged) 2004 return NO; 2005 2006 WKViewInterpretKeyEventsParameters parameters; 2007 parameters.eventInterpretationHadSideEffects = false; 2008 parameters.executingSavedKeypressCommands = false; 2009 // We assume that an input method has consumed the event, and only change this assumption if one of the NSTextInput methods is called. 2010 // We assume the IM will *not* consume hotkey sequences. 2011 parameters.consumedByIM = !([event modifierFlags] & NSCommandKeyMask); 2012 parameters.commands = &commands; 2013 _data->_interpretKeyEventsParameters = ¶meters; 2014 2015 [self interpretKeyEvents:[NSArray arrayWithObject:event]]; 2016 2017 _data->_interpretKeyEventsParameters = 0; 2018 2019 // An input method may consume an event and not tell us (e.g. when displaying a candidate window), 2020 // in which case we should not bubble the event up the DOM. 2021 if (parameters.consumedByIM) 2022 return YES; 2023 2024 // 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. 2025 return parameters.eventInterpretationHadSideEffects; 2026} 2027 2028- (NSRect)_convertToDeviceSpace:(NSRect)rect 2029{ 2030 return toDeviceSpace(rect, [self window]); 2031} 2032 2033- (NSRect)_convertToUserSpace:(NSRect)rect 2034{ 2035 return toUserSpace(rect, [self window]); 2036} 2037 2038// Any non-zero value will do, but using something recognizable might help us debug some day. 2039#define TRACKING_RECT_TAG 0xBADFACE 2040 2041- (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside 2042{ 2043 ASSERT(_data->_trackingRectOwner == nil); 2044 _data->_trackingRectOwner = owner; 2045 _data->_trackingRectUserData = data; 2046 return TRACKING_RECT_TAG; 2047} 2048 2049- (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag 2050{ 2051 ASSERT(tag == 0 || tag == TRACKING_RECT_TAG); 2052 ASSERT(_data->_trackingRectOwner == nil); 2053 _data->_trackingRectOwner = owner; 2054 _data->_trackingRectUserData = data; 2055 return TRACKING_RECT_TAG; 2056} 2057 2058- (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count 2059{ 2060 ASSERT(count == 1); 2061 ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG); 2062 ASSERT(_data->_trackingRectOwner == nil); 2063 _data->_trackingRectOwner = owner; 2064 _data->_trackingRectUserData = userDataList[0]; 2065 trackingNums[0] = TRACKING_RECT_TAG; 2066} 2067 2068- (void)removeTrackingRect:(NSTrackingRectTag)tag 2069{ 2070 if (!_data) 2071 return; 2072 2073 if (tag == 0) 2074 return; 2075 2076 if (tag == TRACKING_RECT_TAG) { 2077 _data->_trackingRectOwner = nil; 2078 return; 2079 } 2080 2081 if (tag == _data->_lastToolTipTag) { 2082 [super removeTrackingRect:tag]; 2083 _data->_lastToolTipTag = 0; 2084 return; 2085 } 2086 2087 // If any other tracking rect is being removed, we don't know how it was created 2088 // and it's possible there's a leak involved (see 3500217) 2089 ASSERT_NOT_REACHED(); 2090} 2091 2092- (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count 2093{ 2094 int i; 2095 for (i = 0; i < count; ++i) { 2096 int tag = tags[i]; 2097 if (tag == 0) 2098 continue; 2099 ASSERT(tag == TRACKING_RECT_TAG); 2100 if (_data != nil) { 2101 _data->_trackingRectOwner = nil; 2102 } 2103 } 2104} 2105 2106- (void)_sendToolTipMouseExited 2107{ 2108 // Nothing matters except window, trackingNumber, and userData. 2109 NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited 2110 location:NSMakePoint(0, 0) 2111 modifierFlags:0 2112 timestamp:0 2113 windowNumber:[[self window] windowNumber] 2114 context:NULL 2115 eventNumber:0 2116 trackingNumber:TRACKING_RECT_TAG 2117 userData:_data->_trackingRectUserData]; 2118 [_data->_trackingRectOwner mouseExited:fakeEvent]; 2119} 2120 2121- (void)_sendToolTipMouseEntered 2122{ 2123 // Nothing matters except window, trackingNumber, and userData. 2124 NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered 2125 location:NSMakePoint(0, 0) 2126 modifierFlags:0 2127 timestamp:0 2128 windowNumber:[[self window] windowNumber] 2129 context:NULL 2130 eventNumber:0 2131 trackingNumber:TRACKING_RECT_TAG 2132 userData:_data->_trackingRectUserData]; 2133 [_data->_trackingRectOwner mouseEntered:fakeEvent]; 2134} 2135 2136- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data 2137{ 2138 return nsStringFromWebCoreString(_data->_page->toolTip()); 2139} 2140 2141- (void)_toolTipChangedFrom:(NSString *)oldToolTip to:(NSString *)newToolTip 2142{ 2143 if (oldToolTip) 2144 [self _sendToolTipMouseExited]; 2145 2146 if (newToolTip && [newToolTip length] > 0) { 2147 // See radar 3500217 for why we remove all tooltips rather than just the single one we created. 2148 [self removeAllToolTips]; 2149 NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000); 2150 _data->_lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL]; 2151 [self _sendToolTipMouseEntered]; 2152 } 2153} 2154 2155- (void)_setFindIndicator:(PassRefPtr<FindIndicator>)findIndicator fadeOut:(BOOL)fadeOut 2156{ 2157 if (!findIndicator) { 2158 _data->_findIndicatorWindow = 0; 2159 return; 2160 } 2161 2162 if (!_data->_findIndicatorWindow) 2163 _data->_findIndicatorWindow = FindIndicatorWindow::create(self); 2164 2165 _data->_findIndicatorWindow->setFindIndicator(findIndicator, fadeOut); 2166} 2167 2168- (void)_enterAcceleratedCompositingMode:(const LayerTreeContext&)layerTreeContext 2169{ 2170 ASSERT(!_data->_layerHostingView); 2171 ASSERT(!layerTreeContext.isEmpty()); 2172 2173 // Create an NSView that will host our layer tree. 2174 _data->_layerHostingView.adoptNS([[NSView alloc] initWithFrame:[self bounds]]); 2175 [_data->_layerHostingView.get() setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 2176 2177 [CATransaction begin]; 2178 [CATransaction setDisableActions:YES]; 2179 [self addSubview:_data->_layerHostingView.get()]; 2180 2181 // Create a root layer that will back the NSView. 2182 RetainPtr<CALayer> rootLayer(AdoptNS, [[CALayer alloc] init]); 2183#ifndef NDEBUG 2184 [rootLayer.get() setName:@"Hosting root layer"]; 2185#endif 2186 2187 CALayer *renderLayer = WKMakeRenderLayer(layerTreeContext.contextID); 2188 [rootLayer.get() addSublayer:renderLayer]; 2189 2190 [_data->_layerHostingView.get() setLayer:rootLayer.get()]; 2191 [_data->_layerHostingView.get() setWantsLayer:YES]; 2192 2193 [CATransaction commit]; 2194} 2195 2196- (void)_exitAcceleratedCompositingMode 2197{ 2198 ASSERT(_data->_layerHostingView); 2199 2200 [_data->_layerHostingView.get() removeFromSuperview]; 2201 [_data->_layerHostingView.get() setLayer:nil]; 2202 [_data->_layerHostingView.get() setWantsLayer:NO]; 2203 2204 _data->_layerHostingView = nullptr; 2205} 2206 2207- (void)_setAccessibilityWebProcessToken:(NSData *)data 2208{ 2209#if !defined(BUILDING_ON_SNOW_LEOPARD) 2210 _data->_remoteAccessibilityChild = WKAXRemoteElementForToken(data); 2211 [self _updateRemoteAccessibilityRegistration:YES]; 2212#endif 2213} 2214 2215- (void)_setComplexTextInputEnabled:(BOOL)complexTextInputEnabled pluginComplexTextInputIdentifier:(uint64_t)pluginComplexTextInputIdentifier 2216{ 2217 BOOL inputSourceChanged = _data->_pluginComplexTextInputIdentifier; 2218 2219 if (complexTextInputEnabled) { 2220 // Check if we're already allowing text input for this plug-in. 2221 if (pluginComplexTextInputIdentifier == _data->_pluginComplexTextInputIdentifier) 2222 return; 2223 2224 _data->_pluginComplexTextInputIdentifier = pluginComplexTextInputIdentifier; 2225 2226 } else { 2227 // Check if we got a request to disable complex text input for a plug-in that is not the current plug-in. 2228 if (pluginComplexTextInputIdentifier != _data->_pluginComplexTextInputIdentifier) 2229 return; 2230 2231 _data->_pluginComplexTextInputIdentifier = 0; 2232 } 2233 2234 if (inputSourceChanged) { 2235 // Inform the out of line window that the input source changed. 2236 [[WKTextInputWindowController sharedTextInputWindowController] keyboardInputSourceChanged]; 2237 } 2238} 2239 2240- (void)_setPageHasCustomRepresentation:(BOOL)pageHasCustomRepresentation 2241{ 2242 _data->_pdfViewController = nullptr; 2243 2244 if (pageHasCustomRepresentation) 2245 _data->_pdfViewController = PDFViewController::create(self); 2246} 2247 2248- (void)_didFinishLoadingDataForCustomRepresentationWithSuggestedFilename:(const String&)suggestedFilename dataReference:(const CoreIPC::DataReference&)dataReference 2249{ 2250 ASSERT(_data->_pdfViewController); 2251 2252 _data->_pdfViewController->setPDFDocumentData(_data->_page->mainFrame()->mimeType(), suggestedFilename, dataReference); 2253} 2254 2255- (double)_customRepresentationZoomFactor 2256{ 2257 if (!_data->_pdfViewController) 2258 return 1; 2259 2260 return _data->_pdfViewController->zoomFactor(); 2261} 2262 2263- (void)_setCustomRepresentationZoomFactor:(double)zoomFactor 2264{ 2265 if (!_data->_pdfViewController) 2266 return; 2267 2268 _data->_pdfViewController->setZoomFactor(zoomFactor); 2269} 2270 2271- (void)_findStringInCustomRepresentation:(NSString *)string withFindOptions:(WebKit::FindOptions)options maxMatchCount:(NSUInteger)count 2272{ 2273 if (!_data->_pdfViewController) 2274 return; 2275 2276 _data->_pdfViewController->findString(string, options, count); 2277} 2278 2279- (void)_countStringMatchesInCustomRepresentation:(NSString *)string withFindOptions:(WebKit::FindOptions)options maxMatchCount:(NSUInteger)count 2280{ 2281 if (!_data->_pdfViewController) 2282 return; 2283 2284 _data->_pdfViewController->countStringMatches(string, options, count); 2285} 2286 2287- (void)_setDragImage:(NSImage *)image at:(NSPoint)clientPoint linkDrag:(BOOL)linkDrag 2288{ 2289 // We need to prevent re-entering this call to avoid crashing in AppKit. 2290 // Given the asynchronous nature of WebKit2 this can now happen. 2291 if (_data->_dragHasStarted) 2292 return; 2293 2294 _data->_dragHasStarted = YES; 2295 [super dragImage:image 2296 at:clientPoint 2297 offset:NSZeroSize 2298 event:(linkDrag) ? [NSApp currentEvent] :_data->_mouseDownEvent 2299 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] 2300 source:self 2301 slideBack:YES]; 2302 _data->_dragHasStarted = NO; 2303} 2304 2305- (void)_updateSecureInputState 2306{ 2307 if (![[self window] isKeyWindow] || ([[self window] firstResponder] != self && !_data->_inBecomeFirstResponder)) { 2308 if (_data->_inSecureInputState) { 2309 DisableSecureEventInput(); 2310 _data->_inSecureInputState = NO; 2311 } 2312 return; 2313 } 2314 // WKView has a single input context for all editable areas (except for plug-ins). 2315 NSTextInputContext *context = [super inputContext]; 2316 bool isInPasswordField = _data->_page->editorState().isInPasswordField; 2317 2318 if (isInPasswordField) { 2319 if (!_data->_inSecureInputState) 2320 EnableSecureEventInput(); 2321 static NSArray *romanInputSources = [[NSArray alloc] initWithObjects:&NSAllRomanInputSourcesLocaleIdentifier count:1]; 2322 [context setAllowedInputSourceLocales:romanInputSources]; 2323 } else { 2324 if (_data->_inSecureInputState) 2325 DisableSecureEventInput(); 2326 [context setAllowedInputSourceLocales:nil]; 2327 } 2328 _data->_inSecureInputState = isInPasswordField; 2329} 2330 2331- (void)_setDrawingAreaSize:(NSSize)size 2332{ 2333 if (!_data->_page->drawingArea()) 2334 return; 2335 2336 _data->_page->drawingArea()->setSize(IntSize(size), IntSize(_data->_resizeScrollOffset)); 2337 _data->_resizeScrollOffset = NSZeroSize; 2338} 2339 2340- (void)_didChangeScrollbarsForMainFrame 2341{ 2342 [self _updateGrowBoxForWindowFrameChange]; 2343} 2344 2345#if ENABLE(FULLSCREEN_API) 2346- (WKFullScreenWindowController*)fullScreenWindowController 2347{ 2348 if (!_data->_fullScreenWindowController) { 2349 _data->_fullScreenWindowController.adoptNS([[WKFullScreenWindowController alloc] init]); 2350 [_data->_fullScreenWindowController.get() setWebView:self]; 2351 } 2352 return _data->_fullScreenWindowController.get(); 2353} 2354#endif 2355 2356- (bool)_executeSavedCommandBySelector:(SEL)selector 2357{ 2358 // The sink does two things: 1) Tells us if the responder went unhandled, and 2359 // 2) prevents any NSBeep; we don't ever want to beep here. 2360 RetainPtr<WKResponderChainSink> sink(AdoptNS, [[WKResponderChainSink alloc] initWithResponderChain:self]); 2361 [super doCommandBySelector:selector]; 2362 [sink.get() detach]; 2363 return ![sink.get() didReceiveUnhandledCommand]; 2364} 2365 2366@end 2367 2368@implementation WKView (Private) 2369 2370- (void)disableFrameSizeUpdates 2371{ 2372 _frameSizeUpdatesDisabledCount++; 2373} 2374 2375- (void)enableFrameSizeUpdates 2376{ 2377 if (!_frameSizeUpdatesDisabledCount) 2378 return; 2379 2380 if (!(--_frameSizeUpdatesDisabledCount)) 2381 [self _setDrawingAreaSize:[self frame].size]; 2382} 2383 2384- (BOOL)frameSizeUpdatesDisabled 2385{ 2386 return _frameSizeUpdatesDisabledCount > 0; 2387} 2388 2389- (void)performDictionaryLookupAtCurrentMouseLocation 2390{ 2391 NSPoint thePoint = [NSEvent mouseLocation]; 2392 thePoint = [[self window] convertScreenToBase:thePoint]; 2393 thePoint = [self convertPoint:thePoint fromView:nil]; 2394 2395 _data->_page->performDictionaryLookupAtLocation(FloatPoint(thePoint.x, thePoint.y)); 2396} 2397 2398- (NSInteger)spellCheckerDocumentTag 2399{ 2400 if (!_data->_hasSpellCheckerDocumentTag) { 2401 _data->_spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag]; 2402 _data->_hasSpellCheckerDocumentTag = YES; 2403 } 2404 return _data->_spellCheckerDocumentTag; 2405} 2406 2407- (void)handleCorrectionPanelResult:(NSString*)result 2408{ 2409 _data->_page->handleCorrectionPanelResult(result); 2410} 2411 2412@end 2413 2414@implementation WKResponderChainSink 2415 2416- (id)initWithResponderChain:(NSResponder *)chain 2417{ 2418 self = [super init]; 2419 if (!self) 2420 return nil; 2421 _lastResponderInChain = chain; 2422 while (NSResponder *next = [_lastResponderInChain nextResponder]) 2423 _lastResponderInChain = next; 2424 [_lastResponderInChain setNextResponder:self]; 2425 return self; 2426} 2427 2428- (void)detach 2429{ 2430 [_lastResponderInChain setNextResponder:nil]; 2431 _lastResponderInChain = nil; 2432} 2433 2434- (bool)didReceiveUnhandledCommand 2435{ 2436 return _didReceiveUnhandledCommand; 2437} 2438 2439- (void)noResponderFor:(SEL)selector 2440{ 2441 _didReceiveUnhandledCommand = true; 2442} 2443 2444- (void)doCommandBySelector:(SEL)selector 2445{ 2446 _didReceiveUnhandledCommand = true; 2447} 2448 2449- (BOOL)tryToPerform:(SEL)action with:(id)object 2450{ 2451 _didReceiveUnhandledCommand = true; 2452 return YES; 2453} 2454 2455@end 2456