WKView.mm revision 65f03d4f644ce73618e5f4f50dd694b26f55ae12
1/* 2 * Copyright (C) 2010 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 "WKView.h" 27 28#import "ChunkedUpdateDrawingAreaProxy.h" 29#import "DataReference.h" 30#import "DrawingAreaProxyImpl.h" 31#import "FindIndicator.h" 32#import "FindIndicatorWindow.h" 33#import "LayerBackedDrawingAreaProxy.h" 34#import "Logging.h" 35#import "NativeWebKeyboardEvent.h" 36#import "PDFViewController.h" 37#import "PageClientImpl.h" 38#import "PrintInfo.h" 39#import "RunLoop.h" 40#import "TextChecker.h" 41#import "TextCheckerState.h" 42#import "WKAPICast.h" 43#import "WKStringCF.h" 44#import "WKTextInputWindowController.h" 45#import "WebContext.h" 46#import "WebEventFactory.h" 47#import "WebPage.h" 48#import "WebPageProxy.h" 49#import "WebProcessManager.h" 50#import "WebProcessProxy.h" 51#import "WebSystemInterface.h" 52#import <QuartzCore/QuartzCore.h> 53#import <WebCore/ColorMac.h> 54#import <WebCore/DragController.h> 55#import <WebCore/DragData.h> 56#import <WebCore/FloatRect.h> 57#import <WebCore/IntRect.h> 58#import <WebCore/KeyboardEvent.h> 59#import <WebCore/PlatformMouseEvent.h> 60#import <WebCore/PlatformScreen.h> 61#import <WebKitSystemInterface.h> 62#import <wtf/RefPtr.h> 63#import <wtf/RetainPtr.h> 64 65// FIXME (WebKit2) <rdar://problem/8728860> WebKit2 needs to be localized 66#define UI_STRING(__str, __desc) [NSString stringWithUTF8String:__str] 67 68@interface NSApplication (Details) 69- (void)speakString:(NSString *)string; 70@end 71 72@interface NSView (Details) 73- (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView; 74@end 75 76@interface NSWindow (Details) 77- (NSRect)_growBoxRect; 78- (BOOL)_updateGrowBoxForWindowFrameChange; 79@end 80 81extern "C" { 82 // Need to declare this attribute name because AppKit exports it but does not make it available in API or SPI headers. 83 // <rdar://problem/8631468> tracks the request to make it available. This code should be removed when the bug is closed. 84 extern NSString *NSTextInputReplacementRangeAttributeName; 85} 86 87using namespace WebKit; 88using namespace WebCore; 89 90namespace WebKit { 91 92typedef id <NSValidatedUserInterfaceItem> ValidationItem; 93typedef Vector<RetainPtr<ValidationItem> > ValidationVector; 94typedef HashMap<String, ValidationVector> ValidationMap; 95 96} 97 98@interface WKViewData : NSObject { 99@public 100 OwnPtr<PageClientImpl> _pageClient; 101 RefPtr<WebPageProxy> _page; 102 103 // For ToolTips. 104 NSToolTipTag _lastToolTipTag; 105 id _trackingRectOwner; 106 void* _trackingRectUserData; 107 108#if USE(ACCELERATED_COMPOSITING) 109 NSView *_layerHostingView; 110#endif 111 112 RetainPtr<id> _remoteAccessibilityChild; 113 114 // For asynchronous validation. 115 ValidationMap _validationMap; 116 117 OwnPtr<PDFViewController> _pdfViewController; 118 119 OwnPtr<FindIndicatorWindow> _findIndicatorWindow; 120 // We keep here the event when resending it to 121 // the application to distinguish the case of a new event from one 122 // that has been already sent to WebCore. 123 NSEvent *_keyDownEventBeingResent; 124 Vector<KeypressCommand> _commandsList; 125 126 // The identifier of the plug-in we want to send complex text input to, or 0 if there is none. 127 uint64_t _pluginComplexTextInputIdentifier; 128 129 Vector<CompositionUnderline> _underlines; 130 unsigned _selectionStart; 131 unsigned _selectionEnd; 132 133 Vector<IntRect> _printingPageRects; 134 double _totalScaleFactorForPrinting; 135 136 bool _inBecomeFirstResponder; 137 bool _inResignFirstResponder; 138} 139@end 140 141@implementation WKViewData 142@end 143 144@interface WebFrameWrapper : NSObject { 145@public 146 RefPtr<WebFrameProxy> _frame; 147} 148 149- (id)initWithFrameProxy:(WebFrameProxy*)frame; 150- (WebFrameProxy*)webFrame; 151@end 152 153@implementation WebFrameWrapper 154 155- (id)initWithFrameProxy:(WebFrameProxy*)frame 156{ 157 self = [super init]; 158 if (!self) 159 return nil; 160 161 _frame = frame; 162 return self; 163} 164 165- (WebFrameProxy*)webFrame 166{ 167 return _frame.get(); 168} 169 170@end 171 172NSString * const PrintedFrameKey = @"WebKitPrintedFrameKey"; 173 174@interface NSObject (NSTextInputContextDetails) 175- (BOOL)wantsToHandleMouseEvents; 176- (BOOL)handleMouseEvent:(NSEvent *)event; 177@end 178 179@implementation WKView 180 181static bool useNewDrawingArea() 182{ 183 static bool useNewDrawingArea = getenv("USE_NEW_DRAWING_AREA"); 184 185 return useNewDrawingArea; 186} 187 188- (id)initWithFrame:(NSRect)frame 189{ 190 return [self initWithFrame:frame contextRef:toAPI(WebContext::sharedProcessContext())]; 191} 192 193- (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)contextRef 194{ 195 return [self initWithFrame:frame contextRef:contextRef pageGroupRef:nil]; 196} 197 198static NSString * const WebArchivePboardType = @"Apple Web Archive pasteboard type"; 199static NSString * const WebURLsWithTitlesPboardType = @"WebURLsWithTitlesPboardType"; 200static NSString * const WebURLPboardType = @"public.url"; 201static NSString * const WebURLNamePboardType = @"public.url-name"; 202 203- (void)_registerDraggedTypes 204{ 205 NSArray *editableTypes = [NSArray arrayWithObjects:WebArchivePboardType, NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPDFPboardType, 206#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 207 NSPICTPboardType, 208#endif 209 NSURLPboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, NSColorPboardType, kUTTypePNG, nil]; 210 NSArray *URLTypes = [NSArray arrayWithObjects:WebURLsWithTitlesPboardType, NSURLPboardType, WebURLPboardType, WebURLNamePboardType, NSStringPboardType, NSFilenamesPboardType, nil]; 211 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes]; 212 [types addObjectsFromArray:URLTypes]; 213 [self registerForDraggedTypes:[types allObjects]]; 214 [types release]; 215} 216 217- (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)contextRef pageGroupRef:(WKPageGroupRef)pageGroupRef 218{ 219 self = [super initWithFrame:frame]; 220 if (!self) 221 return nil; 222 223 InitWebCoreSystemInterface(); 224 RunLoop::initializeMainRunLoop(); 225 226 NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:frame 227 options:(NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect) 228 owner:self 229 userInfo:nil]; 230 [self addTrackingArea:trackingArea]; 231 [trackingArea release]; 232 233 _data = [[WKViewData alloc] init]; 234 235 _data->_pageClient = PageClientImpl::create(self); 236 _data->_page = toImpl(contextRef)->createWebPage(_data->_pageClient.get(), toImpl(pageGroupRef)); 237 _data->_page->initializeWebPage(); 238 239 [self _registerDraggedTypes]; 240 241 WebContext::statistics().wkViewCount++; 242 243#if !defined(BUILDING_ON_SNOW_LEOPARD) 244 NSData *remoteToken = (NSData *)WKAXRemoteTokenForElement(self); 245 CoreIPC::DataReference dataToken = CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]); 246 _data->_page->sendAccessibilityPresenterToken(dataToken); 247#endif 248 249 return self; 250} 251 252- (void)dealloc 253{ 254 _data->_page->close(); 255 256 [_data release]; 257 258 WebContext::statistics().wkViewCount--; 259 260 [super dealloc]; 261} 262 263- (WKPageRef)pageRef 264{ 265 return toAPI(_data->_page.get()); 266} 267 268- (void)setDrawsBackground:(BOOL)drawsBackground 269{ 270 _data->_page->setDrawsBackground(drawsBackground); 271} 272 273- (BOOL)drawsBackground 274{ 275 return _data->_page->drawsBackground(); 276} 277 278- (void)setDrawsTransparentBackground:(BOOL)drawsTransparentBackground 279{ 280 _data->_page->setDrawsTransparentBackground(drawsTransparentBackground); 281} 282 283- (BOOL)drawsTransparentBackground 284{ 285 return _data->_page->drawsTransparentBackground(); 286} 287 288- (BOOL)acceptsFirstResponder 289{ 290 return YES; 291} 292 293- (BOOL)becomeFirstResponder 294{ 295 NSSelectionDirection direction = [[self window] keyViewSelectionDirection]; 296 297 _data->_inBecomeFirstResponder = true; 298 _data->_page->viewStateDidChange(WebPageProxy::ViewIsFocused); 299 _data->_inBecomeFirstResponder = false; 300 301 if (direction != NSDirectSelection) 302 _data->_page->setInitialFocus(direction == NSSelectingNext); 303 304 return YES; 305} 306 307- (BOOL)resignFirstResponder 308{ 309 _data->_inResignFirstResponder = true; 310 _data->_page->viewStateDidChange(WebPageProxy::ViewIsFocused); 311 _data->_inResignFirstResponder = false; 312 313 return YES; 314} 315 316- (BOOL)isFlipped 317{ 318 return YES; 319} 320 321- (void)setFrameSize:(NSSize)size 322{ 323 [super setFrameSize:size]; 324 325 if (!_data->_page->drawingArea()) 326 return; 327 328 _data->_page->drawingArea()->setSize(IntSize(size)); 329} 330 331- (void)_updateWindowAndViewFrames 332{ 333 NSWindow *window = [self window]; 334 ASSERT(window); 335 336 NSRect windowFrameInScreenCoordinates = [window frame]; 337 NSRect viewFrameInWindowCoordinates = [self convertRect:[self frame] toView:nil]; 338 NSPoint accessibilityPosition = [[self accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue]; 339 340 _data->_page->windowAndViewFramesChanged(enclosingIntRect(windowFrameInScreenCoordinates), enclosingIntRect(viewFrameInWindowCoordinates), IntPoint(accessibilityPosition)); 341} 342 343- (void)renewGState 344{ 345 // Hide the find indicator. 346 _data->_findIndicatorWindow = nullptr; 347 348 // Update the view frame. 349 if ([self window]) 350 [self _updateWindowAndViewFrames]; 351 352 [super renewGState]; 353} 354 355typedef HashMap<SEL, String> SelectorNameMap; 356 357// Map selectors into Editor command names. 358// This is not needed for any selectors that have the same name as the Editor command. 359static const SelectorNameMap* createSelectorExceptionMap() 360{ 361 SelectorNameMap* map = new HashMap<SEL, String>; 362 363 map->add(@selector(insertNewlineIgnoringFieldEditor:), "InsertNewline"); 364 map->add(@selector(insertParagraphSeparator:), "InsertNewline"); 365 map->add(@selector(insertTabIgnoringFieldEditor:), "InsertTab"); 366 map->add(@selector(pageDown:), "MovePageDown"); 367 map->add(@selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection"); 368 map->add(@selector(pageUp:), "MovePageUp"); 369 map->add(@selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection"); 370 371 return map; 372} 373 374static String commandNameForSelector(SEL selector) 375{ 376 // Check the exception map first. 377 static const SelectorNameMap* exceptionMap = createSelectorExceptionMap(); 378 SelectorNameMap::const_iterator it = exceptionMap->find(selector); 379 if (it != exceptionMap->end()) 380 return it->second; 381 382 // Remove the trailing colon. 383 // No need to capitalize the command name since Editor command names are 384 // not case sensitive. 385 const char* selectorName = sel_getName(selector); 386 size_t selectorNameLength = strlen(selectorName); 387 if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':') 388 return String(); 389 return String(selectorName, selectorNameLength - 1); 390} 391 392// Editing commands 393 394#define WEBCORE_COMMAND(command) - (void)command:(id)sender { _data->_page->executeEditCommand(commandNameForSelector(_cmd)); } 395 396WEBCORE_COMMAND(copy) 397WEBCORE_COMMAND(cut) 398WEBCORE_COMMAND(paste) 399WEBCORE_COMMAND(delete) 400WEBCORE_COMMAND(pasteAsPlainText) 401WEBCORE_COMMAND(selectAll) 402WEBCORE_COMMAND(takeFindStringFromSelection) 403 404#undef WEBCORE_COMMAND 405 406// Menu items validation 407 408static NSMenuItem *menuItem(id <NSValidatedUserInterfaceItem> item) 409{ 410 if (![(NSObject *)item isKindOfClass:[NSMenuItem class]]) 411 return nil; 412 return (NSMenuItem *)item; 413} 414 415static NSToolbarItem *toolbarItem(id <NSValidatedUserInterfaceItem> item) 416{ 417 if (![(NSObject *)item isKindOfClass:[NSToolbarItem class]]) 418 return nil; 419 return (NSToolbarItem *)item; 420} 421 422- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 423{ 424 SEL action = [item action]; 425 426 if (action == @selector(showGuessPanel:)) { 427 if (NSMenuItem *menuItem = ::menuItem(item)) { 428 BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible]; 429 [menuItem setTitle:panelShowing 430 ? UI_STRING("Hide Spelling and Grammar", "menu item title") 431 : UI_STRING("Show Spelling and Grammar", "menu item title")]; 432 } 433 return _data->_page->selectionState().isContentEditable; 434 } 435 436 if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:)) 437 return _data->_page->selectionState().isContentEditable; 438 439 if (action == @selector(toggleContinuousSpellChecking:)) { 440 bool enabled = TextChecker::isContinuousSpellCheckingAllowed(); 441 bool checked = enabled && TextChecker::state().isContinuousSpellCheckingEnabled; 442 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 443 return enabled; 444 } 445 446 if (action == @selector(toggleGrammarChecking:)) { 447 bool checked = TextChecker::state().isGrammarCheckingEnabled; 448 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 449 return YES; 450 } 451 452 if (action == @selector(toggleAutomaticSpellingCorrection:)) { 453 bool checked = TextChecker::state().isAutomaticSpellingCorrectionEnabled; 454 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 455 return _data->_page->selectionState().isContentEditable; 456 } 457 458 if (action == @selector(orderFrontSubstitutionsPanel:)) { 459 if (NSMenuItem *menuItem = ::menuItem(item)) { 460 BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible]; 461 [menuItem setTitle:panelShowing 462 ? UI_STRING("Hide Substitutions", "menu item title") 463 : UI_STRING("Show Substitutions", "menu item title")]; 464 } 465 return _data->_page->selectionState().isContentEditable; 466 } 467 468 if (action == @selector(toggleSmartInsertDelete:)) { 469 bool checked = _data->_page->isSmartInsertDeleteEnabled(); 470 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 471 return _data->_page->selectionState().isContentEditable; 472 } 473 474 if (action == @selector(toggleAutomaticQuoteSubstitution:)) { 475 bool checked = TextChecker::state().isAutomaticQuoteSubstitutionEnabled; 476 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 477 return _data->_page->selectionState().isContentEditable; 478 } 479 480 if (action == @selector(toggleAutomaticDashSubstitution:)) { 481 bool checked = TextChecker::state().isAutomaticDashSubstitutionEnabled; 482 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 483 return _data->_page->selectionState().isContentEditable; 484 } 485 486 if (action == @selector(toggleAutomaticLinkDetection:)) { 487 bool checked = TextChecker::state().isAutomaticLinkDetectionEnabled; 488 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 489 return _data->_page->selectionState().isContentEditable; 490 } 491 492 if (action == @selector(toggleAutomaticTextReplacement:)) { 493 bool checked = TextChecker::state().isAutomaticTextReplacementEnabled; 494 [menuItem(item) setState:checked ? NSOnState : NSOffState]; 495 return _data->_page->selectionState().isContentEditable; 496 } 497 498 if (action == @selector(uppercaseWord:) || action == @selector(lowercaseWord:) || action == @selector(capitalizeWord:)) 499 return _data->_page->selectionState().selectedRangeLength && _data->_page->selectionState().isContentEditable; 500 501 if (action == @selector(stopSpeaking:)) 502 return [NSApp isSpeaking]; 503 504 // Next, handle editor commands. Start by returning YES for anything that is not an editor command. 505 // Returning YES is the default thing to do in an AppKit validate method for any selector that is not recognized. 506 String commandName = commandNameForSelector([item action]); 507 if (!Editor::commandIsSupportedFromMenuOrKeyBinding(commandName)) 508 return YES; 509 510 // Add this item to the vector of items for a given command that are awaiting validation. 511 pair<ValidationMap::iterator, bool> addResult = _data->_validationMap.add(commandName, ValidationVector()); 512 addResult.first->second.append(item); 513 if (addResult.second) { 514 // If we are not already awaiting validation for this command, start the asynchronous validation process. 515 // FIXME: Theoretically, there is a race here; when we get the answer it might be old, from a previous time 516 // we asked for the same command; there is no guarantee the answer is still valid. 517 // FIXME: The function called here should be renamed validateCommand because it is not specific to menu items. 518 _data->_page->validateMenuItem(commandName); 519 } 520 521 // Treat as enabled until we get the result back from the web process and _setUserInterfaceItemState is called. 522 // FIXME <rdar://problem/8803459>: This means disabled items will flash enabled at first for a moment. 523 // But returning NO here would be worse; that would make keyboard commands such as command-C fail. 524 return YES; 525} 526 527static void speakString(WKStringRef string, WKErrorRef error, void*) 528{ 529 if (error) 530 return; 531 if (!string) 532 return; 533 534 NSString *convertedString = toImpl(string)->string(); 535 [NSApp speakString:convertedString]; 536} 537 538- (IBAction)startSpeaking:(id)sender 539{ 540 _data->_page->getSelectionOrContentsAsString(StringCallback::create(0, speakString)); 541} 542 543- (IBAction)stopSpeaking:(id)sender 544{ 545 [NSApp stopSpeaking:sender]; 546} 547 548- (IBAction)showGuessPanel:(id)sender 549{ 550 NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; 551 if (!checker) { 552 LOG_ERROR("No NSSpellChecker"); 553 return; 554 } 555 556 NSPanel *spellingPanel = [checker spellingPanel]; 557 if ([spellingPanel isVisible]) { 558 [spellingPanel orderOut:sender]; 559 return; 560 } 561 562 _data->_page->advanceToNextMisspelling(true); 563 [spellingPanel orderFront:sender]; 564} 565 566- (IBAction)checkSpelling:(id)sender 567{ 568 _data->_page->advanceToNextMisspelling(false); 569} 570 571- (void)changeSpelling:(id)sender 572{ 573 NSString *word = [[sender selectedCell] stringValue]; 574 575 _data->_page->changeSpellingToWord(word); 576} 577 578- (IBAction)toggleContinuousSpellChecking:(id)sender 579{ 580 bool spellCheckingEnabled = !TextChecker::state().isContinuousSpellCheckingEnabled; 581 TextChecker::setContinuousSpellCheckingEnabled(spellCheckingEnabled); 582 583 _data->_page->process()->updateTextCheckerState(); 584 585 if (!spellCheckingEnabled) 586 _data->_page->unmarkAllMisspellings(); 587} 588 589- (IBAction)toggleGrammarChecking:(id)sender 590{ 591 bool grammarCheckingEnabled = !TextChecker::state().isGrammarCheckingEnabled; 592 TextChecker::setGrammarCheckingEnabled(grammarCheckingEnabled); 593 594 _data->_page->process()->updateTextCheckerState(); 595 596 if (!grammarCheckingEnabled) 597 _data->_page->unmarkAllBadGrammar(); 598} 599 600- (IBAction)toggleAutomaticSpellingCorrection:(id)sender 601{ 602 TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled); 603 604 _data->_page->process()->updateTextCheckerState(); 605} 606 607- (void)orderFrontSubstitutionsPanel:(id)sender 608{ 609 NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; 610 if (!checker) { 611 LOG_ERROR("No NSSpellChecker"); 612 return; 613 } 614 615 NSPanel *substitutionsPanel = [checker substitutionsPanel]; 616 if ([substitutionsPanel isVisible]) { 617 [substitutionsPanel orderOut:sender]; 618 return; 619 } 620 [substitutionsPanel orderFront:sender]; 621} 622 623- (IBAction)toggleSmartInsertDelete:(id)sender 624{ 625 _data->_page->setSmartInsertDeleteEnabled(!_data->_page->isSmartInsertDeleteEnabled()); 626} 627 628- (BOOL)isAutomaticQuoteSubstitutionEnabled 629{ 630 return TextChecker::state().isAutomaticQuoteSubstitutionEnabled; 631} 632 633- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag 634{ 635 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticQuoteSubstitutionEnabled) 636 return; 637 638 TextChecker::setAutomaticQuoteSubstitutionEnabled(flag); 639 _data->_page->process()->updateTextCheckerState(); 640} 641 642- (void)toggleAutomaticQuoteSubstitution:(id)sender 643{ 644 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled); 645 _data->_page->process()->updateTextCheckerState(); 646} 647 648- (BOOL)isAutomaticDashSubstitutionEnabled 649{ 650 return TextChecker::state().isAutomaticDashSubstitutionEnabled; 651} 652 653- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag 654{ 655 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticDashSubstitutionEnabled) 656 return; 657 658 TextChecker::setAutomaticDashSubstitutionEnabled(flag); 659 _data->_page->process()->updateTextCheckerState(); 660} 661 662- (void)toggleAutomaticDashSubstitution:(id)sender 663{ 664 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled); 665 _data->_page->process()->updateTextCheckerState(); 666} 667 668- (BOOL)isAutomaticLinkDetectionEnabled 669{ 670 return TextChecker::state().isAutomaticLinkDetectionEnabled; 671} 672 673- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag 674{ 675 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticLinkDetectionEnabled) 676 return; 677 678 TextChecker::setAutomaticLinkDetectionEnabled(flag); 679 _data->_page->process()->updateTextCheckerState(); 680} 681 682- (void)toggleAutomaticLinkDetection:(id)sender 683{ 684 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled); 685 _data->_page->process()->updateTextCheckerState(); 686} 687 688- (BOOL)isAutomaticTextReplacementEnabled 689{ 690 return TextChecker::state().isAutomaticTextReplacementEnabled; 691} 692 693- (void)setAutomaticTextReplacementEnabled:(BOOL)flag 694{ 695 if (static_cast<bool>(flag) == TextChecker::state().isAutomaticTextReplacementEnabled) 696 return; 697 698 TextChecker::setAutomaticTextReplacementEnabled(flag); 699 _data->_page->process()->updateTextCheckerState(); 700} 701 702- (void)toggleAutomaticTextReplacement:(id)sender 703{ 704 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled); 705 _data->_page->process()->updateTextCheckerState(); 706} 707 708- (void)uppercaseWord:(id)sender 709{ 710 _data->_page->uppercaseWord(); 711} 712 713- (void)lowercaseWord:(id)sender 714{ 715 _data->_page->lowercaseWord(); 716} 717 718- (void)capitalizeWord:(id)sender 719{ 720 _data->_page->capitalizeWord(); 721} 722 723// Events 724 725// Override this so that AppKit will send us arrow keys as key down events so we can 726// support them via the key bindings mechanism. 727- (BOOL)_wantsKeyDownForEvent:(NSEvent *)event 728{ 729 return YES; 730} 731 732#define EVENT_HANDLER(Selector, Type) \ 733 - (void)Selector:(NSEvent *)theEvent \ 734 { \ 735 Web##Type##Event webEvent = WebEventFactory::createWeb##Type##Event(theEvent, self); \ 736 _data->_page->handle##Type##Event(webEvent); \ 737 } 738 739EVENT_HANDLER(mouseEntered, Mouse) 740EVENT_HANDLER(mouseExited, Mouse) 741EVENT_HANDLER(mouseMoved, Mouse) 742EVENT_HANDLER(otherMouseDown, Mouse) 743EVENT_HANDLER(otherMouseDragged, Mouse) 744EVENT_HANDLER(otherMouseMoved, Mouse) 745EVENT_HANDLER(otherMouseUp, Mouse) 746EVENT_HANDLER(rightMouseDown, Mouse) 747EVENT_HANDLER(rightMouseDragged, Mouse) 748EVENT_HANDLER(rightMouseMoved, Mouse) 749EVENT_HANDLER(rightMouseUp, Mouse) 750EVENT_HANDLER(scrollWheel, Wheel) 751 752#undef EVENT_HANDLER 753 754#define MOUSE_EVENT_HANDLER(Selector) \ 755 - (void)Selector:(NSEvent *)theEvent \ 756 { \ 757 NSInputManager *currentInputManager = [NSInputManager currentInputManager]; \ 758 if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:theEvent]) \ 759 return; \ 760 WebMouseEvent webEvent = WebEventFactory::createWebMouseEvent(theEvent, self); \ 761 _data->_page->handleMouseEvent(webEvent); \ 762 } 763 764MOUSE_EVENT_HANDLER(mouseDown) 765MOUSE_EVENT_HANDLER(mouseDragged) 766MOUSE_EVENT_HANDLER(mouseUp) 767 768#undef MOUSE_EVENT_HANDLER 769 770- (void)doCommandBySelector:(SEL)selector 771{ 772 if (selector != @selector(noop:)) 773 _data->_commandsList.append(KeypressCommand(commandNameForSelector(selector))); 774} 775 776- (void)insertText:(id)string 777{ 778 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString 779 780 LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string); 781 NSString *text; 782 bool isFromInputMethod = _data->_page->selectionState().hasComposition; 783 784 if (isAttributedString) { 785 text = [string string]; 786 // We deal with the NSTextInputReplacementRangeAttributeName attribute from NSAttributedString here 787 // simply because it is used by at least one Input Method -- it corresonds to the kEventParamTextInputSendReplaceRange 788 // event in TSM. This behaviour matches that of -[WebHTMLView setMarkedText:selectedRange:] when it receives an 789 // NSAttributedString 790 NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, [text length])]; 791 LOG(TextInput, "ReplacementRange: %@", rangeString); 792 if (rangeString) 793 isFromInputMethod = YES; 794 } else 795 text = string; 796 797 String eventText = text; 798 799 if (!isFromInputMethod) 800 _data->_commandsList.append(KeypressCommand("insertText", text)); 801 else { 802 eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore 803 _data->_commandsList.append(KeypressCommand("insertText", eventText)); 804 } 805} 806 807- (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event 808{ 809 if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) != NSCommandKeyMask) 810 return NO; 811 812 // Here we special case cmd+b and cmd+i but not cmd+u, for historic reason. 813 // This should not be changed, since it could break some Mac applications that 814 // rely on this inherent behavior. 815 // See https://bugs.webkit.org/show_bug.cgi?id=24943 816 817 NSString *string = [event characters]; 818 if ([string caseInsensitiveCompare:@"b"] == NSOrderedSame) { 819 _data->_page->executeEditCommand("ToggleBold"); 820 return YES; 821 } 822 if ([string caseInsensitiveCompare:@"i"] == NSOrderedSame) { 823 _data->_page->executeEditCommand("ToggleItalic"); 824 return YES; 825 } 826 827 return NO; 828} 829 830- (BOOL)performKeyEquivalent:(NSEvent *)event 831{ 832 // There's a chance that responding to this event will run a nested event loop, and 833 // fetching a new event might release the old one. Retaining and then autoreleasing 834 // the current event prevents that from causing a problem inside WebKit or AppKit code. 835 [[event retain] autorelease]; 836 837 BOOL eventWasSentToWebCore = (_data->_keyDownEventBeingResent == event); 838 839 // Pass key combos through WebCore if there is a key binding available for 840 // this event. This lets web pages have a crack at intercepting key-modified keypresses. 841 // But don't do it if we have already handled the event. 842 // Pressing Esc results in a fake event being sent - don't pass it to WebCore. 843 if (!eventWasSentToWebCore && event == [NSApp currentEvent] && self == [[self window] firstResponder]) { 844 [_data->_keyDownEventBeingResent release]; 845 _data->_keyDownEventBeingResent = nil; 846 847 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, self)); 848 return YES; 849 } 850 851 return [self _handleStyleKeyEquivalent:event] || [super performKeyEquivalent:event]; 852} 853 854- (void)_setEventBeingResent:(NSEvent *)event 855{ 856 _data->_keyDownEventBeingResent = [event retain]; 857} 858 859- (Vector<KeypressCommand>&)_interceptKeyEvent:(NSEvent *)theEvent 860{ 861 _data->_commandsList.clear(); 862 // interpretKeyEvents will trigger one or more calls to doCommandBySelector or setText 863 // that will populate the commandsList vector. 864 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; 865 return _data->_commandsList; 866} 867 868- (void)_getTextInputState:(unsigned)start selectionEnd:(unsigned)end underlines:(Vector<WebCore::CompositionUnderline>&)lines 869{ 870 start = _data->_selectionStart; 871 end = _data->_selectionEnd; 872 lines = _data->_underlines; 873} 874 875- (void)keyUp:(NSEvent *)theEvent 876{ 877 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self)); 878} 879 880- (void)keyDown:(NSEvent *)theEvent 881{ 882 if (_data->_pluginComplexTextInputIdentifier) { 883 // Try feeding the keyboard event directly to the plug-in. 884 NSString *string = nil; 885 if ([[WKTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:theEvent string:&string]) { 886 if (string) 887 _data->_page->sendComplexTextInputToPlugin(_data->_pluginComplexTextInputIdentifier, string); 888 return; 889 } 890 } 891 892 _data->_underlines.clear(); 893 _data->_selectionStart = 0; 894 _data->_selectionEnd = 0; 895 // We could be receiving a key down from AppKit if we have re-sent an event 896 // that maps to an action that is currently unavailable (for example a copy when 897 // there is no range selection). 898 // If this is the case we should ignore the key down. 899 if (_data->_keyDownEventBeingResent == theEvent) { 900 [_data->_keyDownEventBeingResent release]; 901 _data->_keyDownEventBeingResent = nil; 902 [super keyDown:theEvent]; 903 return; 904 } 905 _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self)); 906} 907 908- (NSTextInputContext *)inputContext { 909 if (_data->_pluginComplexTextInputIdentifier) 910 return [[WKTextInputWindowController sharedTextInputWindowController] inputContext]; 911 912 return [super inputContext]; 913} 914 915- (NSRange)selectedRange 916{ 917 if (_data->_page->selectionState().isNone || !_data->_page->selectionState().isContentEditable) 918 return NSMakeRange(NSNotFound, 0); 919 920 LOG(TextInput, "selectedRange -> (%u, %u)", _data->_page->selectionState().selectedRangeStart, _data->_page->selectionState().selectedRangeLength); 921 return NSMakeRange(_data->_page->selectionState().selectedRangeStart, _data->_page->selectionState().selectedRangeLength); 922} 923 924- (BOOL)hasMarkedText 925{ 926 LOG(TextInput, "hasMarkedText -> %u", _data->_page->selectionState().hasComposition); 927 return _data->_page->selectionState().hasComposition; 928} 929 930- (void)unmarkText 931{ 932 LOG(TextInput, "unmarkText"); 933 934 _data->_commandsList.append(KeypressCommand("unmarkText")); 935} 936 937- (NSArray *)validAttributesForMarkedText 938{ 939 static NSArray *validAttributes; 940 if (!validAttributes) { 941 validAttributes = [[NSArray alloc] initWithObjects: 942 NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName, 943 NSMarkedClauseSegmentAttributeName, NSTextInputReplacementRangeAttributeName, nil]; 944 // NSText also supports the following attributes, but it's 945 // hard to tell which are really required for text input to 946 // work well; I have not seen any input method make use of them yet. 947 // NSFontAttributeName, NSForegroundColorAttributeName, 948 // NSBackgroundColorAttributeName, NSLanguageAttributeName. 949 CFRetain(validAttributes); 950 } 951 LOG(TextInput, "validAttributesForMarkedText -> (...)"); 952 return validAttributes; 953} 954 955static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnderline>& result) 956{ 957 int length = [[string string] length]; 958 959 int i = 0; 960 while (i < length) { 961 NSRange range; 962 NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&range inRange:NSMakeRange(i, length - i)]; 963 964 if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) { 965 Color color = Color::black; 966 if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName]) 967 color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]); 968 result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] > 1)); 969 } 970 971 i = range.location + range.length; 972 } 973} 974 975- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange 976{ 977 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString 978 979 LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelRange.location, newSelRange.length); 980 981 NSString *text = string; 982 983 if (isAttributedString) { 984 text = [string string]; 985 extractUnderlines(string, _data->_underlines); 986 } 987 988 _data->_commandsList.append(KeypressCommand("setMarkedText", text)); 989 _data->_selectionStart = newSelRange.location; 990 _data->_selectionEnd = NSMaxRange(newSelRange); 991} 992 993- (NSRange)markedRange 994{ 995 uint64_t location; 996 uint64_t length; 997 998 _data->_page->getMarkedRange(location, length); 999 LOG(TextInput, "markedRange -> (%u, %u)", location, length); 1000 return NSMakeRange(location, length); 1001} 1002 1003- (NSAttributedString *)attributedSubstringFromRange:(NSRange)nsRange 1004{ 1005 // This is not implemented for now. Need to figure out how to serialize the attributed string across processes. 1006 LOG(TextInput, "attributedSubstringFromRange"); 1007 return nil; 1008} 1009 1010- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 1011{ 1012 NSWindow *window = [self window]; 1013 1014 if (window) 1015 thePoint = [window convertScreenToBase:thePoint]; 1016 thePoint = [self convertPoint:thePoint fromView:nil]; // the point is relative to the main frame 1017 1018 uint64_t result = _data->_page->characterIndexForPoint(IntPoint(thePoint)); 1019 LOG(TextInput, "characterIndexForPoint:(%f, %f) -> %u", thePoint.x, thePoint.y, result); 1020 return result; 1021} 1022 1023- (NSRect)firstRectForCharacterRange:(NSRange)theRange 1024{ 1025 // Just to match NSTextView's behavior. Regression tests cannot detect this; 1026 // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682 1027 // (type something; try ranges (1, -1) and (2, -1). 1028 if ((theRange.location + theRange.length < theRange.location) && (theRange.location + theRange.length != 0)) 1029 theRange.length = 0; 1030 1031 NSRect resultRect = _data->_page->firstRectForCharacterRange(theRange.location, theRange.length); 1032 resultRect = [self convertRect:resultRect toView:nil]; 1033 1034 NSWindow *window = [self window]; 1035 if (window) 1036 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; 1037 1038 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); 1039 return resultRect; 1040} 1041 1042- (DragApplicationFlags)applicationFlags:(id <NSDraggingInfo>)draggingInfo 1043{ 1044 uint32_t flags = 0; 1045 if ([NSApp modalWindow]) 1046 flags = DragApplicationIsModal; 1047 if ([[self window] attachedSheet]) 1048 flags |= DragApplicationHasAttachedSheet; 1049 if ([draggingInfo draggingSource] == self) 1050 flags |= DragApplicationIsSource; 1051 if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) 1052 flags |= DragApplicationIsCopyKeyDown; 1053 return static_cast<DragApplicationFlags>(flags); 1054} 1055 1056- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo 1057{ 1058 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1059 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1060 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1061 1062 _data->_page->performDragControllerAction(DragControllerActionEntered, &dragData, [[draggingInfo draggingPasteboard] name]); 1063 return NSDragOperationCopy; 1064} 1065 1066- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo 1067{ 1068 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1069 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1070 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1071 _data->_page->performDragControllerAction(DragControllerActionUpdated, &dragData, [[draggingInfo draggingPasteboard] name]); 1072 return _data->_page->dragOperation(); 1073} 1074 1075- (void)draggingExited:(id <NSDraggingInfo>)draggingInfo 1076{ 1077 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1078 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1079 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1080 _data->_page->performDragControllerAction(DragControllerActionExited, &dragData, [[draggingInfo draggingPasteboard] name]); 1081 _data->_page->resetDragOperation(); 1082} 1083 1084- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo 1085{ 1086 return YES; 1087} 1088 1089- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo 1090{ 1091 IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]); 1092 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 1093 DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]); 1094 _data->_page->performDragControllerAction(DragControllerActionPerformDrag, &dragData, [[draggingInfo draggingPasteboard] name]); 1095 return YES; 1096} 1097 1098- (void)_updateWindowVisibility 1099{ 1100 _data->_page->updateWindowIsVisible(![[self window] isMiniaturized]); 1101} 1102 1103- (BOOL)_ownsWindowGrowBox 1104{ 1105 NSWindow* window = [self window]; 1106 if (!window) 1107 return NO; 1108 1109 NSView *superview = [self superview]; 1110 if (!superview) 1111 return NO; 1112 1113 NSRect growBoxRect = [window _growBoxRect]; 1114 if (NSIsEmptyRect(growBoxRect)) 1115 return NO; 1116 1117 NSRect visibleRect = [self visibleRect]; 1118 if (NSIsEmptyRect(visibleRect)) 1119 return NO; 1120 1121 NSRect visibleRectInWindowCoords = [self convertRect:visibleRect toView:nil]; 1122 if (!NSIntersectsRect(growBoxRect, visibleRectInWindowCoords)) 1123 return NO; 1124 1125 return YES; 1126} 1127 1128- (BOOL)_updateGrowBoxForWindowFrameChange 1129{ 1130 // Temporarily enable the resize indicator to make a the _ownsWindowGrowBox calculation work. 1131 BOOL wasShowingIndicator = [[self window] showsResizeIndicator]; 1132 [[self window] setShowsResizeIndicator:YES]; 1133 1134 BOOL ownsGrowBox = [self _ownsWindowGrowBox]; 1135 _data->_page->setWindowResizerSize(ownsGrowBox ? enclosingIntRect([[self window] _growBoxRect]).size() : IntSize()); 1136 1137 // Once WebCore can draw the window resizer, this should read: 1138 // if (wasShowingIndicator) 1139 // [[self window] setShowsResizeIndicator:!ownsGrowBox]; 1140 [[self window] setShowsResizeIndicator:wasShowingIndicator]; 1141 1142 return ownsGrowBox; 1143} 1144 1145- (void)addWindowObserversForWindow:(NSWindow *)window 1146{ 1147 if (window) { 1148 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) 1149 name:NSWindowDidBecomeKeyNotification object:nil]; 1150 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) 1151 name:NSWindowDidResignKeyNotification object:nil]; 1152 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidMiniaturize:) 1153 name:NSWindowDidMiniaturizeNotification object:window]; 1154 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidDeminiaturize:) 1155 name:NSWindowDidDeminiaturizeNotification object:window]; 1156 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowFrameDidChange:) 1157 name:NSWindowDidMoveNotification object:window]; 1158 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowFrameDidChange:) 1159 name:NSWindowDidResizeNotification object:window]; 1160 } 1161} 1162 1163- (void)removeWindowObservers 1164{ 1165 NSWindow *window = [self window]; 1166 if (!window) 1167 return; 1168 1169 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; 1170 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; 1171 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMiniaturizeNotification object:window]; 1172 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window]; 1173 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMoveNotification object:window]; 1174 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:window]; 1175} 1176 1177- (void)viewWillMoveToWindow:(NSWindow *)window 1178{ 1179 if (window != [self window]) { 1180 [self removeWindowObservers]; 1181 [self addWindowObserversForWindow:window]; 1182 } 1183} 1184 1185- (void)viewDidMoveToWindow 1186{ 1187 // We want to make sure to update the active state while hidden, so if the view is about to become visible, we 1188 // update the active state first and then make it visible. If the view is about to be hidden, we hide it first and then 1189 // update the active state. 1190 if ([self window]) { 1191 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive); 1192 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible | WebPageProxy::ViewIsInWindow); 1193 [self _updateWindowVisibility]; 1194 [self _updateWindowAndViewFrames]; 1195 } else { 1196 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1197 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive | WebPageProxy::ViewIsInWindow); 1198 } 1199 1200} 1201 1202- (void)_windowDidBecomeKey:(NSNotification *)notification 1203{ 1204 NSWindow *keyWindow = [notification object]; 1205 if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) 1206 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive); 1207} 1208 1209- (void)_windowDidResignKey:(NSNotification *)notification 1210{ 1211 NSWindow *formerKeyWindow = [notification object]; 1212 if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) 1213 _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive); 1214} 1215 1216- (void)_windowDidMiniaturize:(NSNotification *)notification 1217{ 1218 [self _updateWindowVisibility]; 1219} 1220 1221- (void)_windowDidDeminiaturize:(NSNotification *)notification 1222{ 1223 [self _updateWindowVisibility]; 1224} 1225 1226- (void)_windowFrameDidChange:(NSNotification *)notification 1227{ 1228 [self _updateWindowAndViewFrames]; 1229} 1230 1231- (void)drawRect:(NSRect)rect 1232{ 1233 LOG(View, "drawRect: x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 1234 if (useNewDrawingArea()) { 1235 if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(_data->_page->drawingArea())) { 1236 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); 1237 drawingArea->paint(context, enclosingIntRect(rect)); 1238 } else if (_data->_page->drawsBackground()) { 1239 [_data->_page->drawsTransparentBackground() ? [NSColor clearColor] : [NSColor whiteColor] set]; 1240 NSRectFill(rect); 1241 } 1242 1243 _data->_page->didDraw(); 1244 return; 1245 } 1246 1247 if (_data->_page->isValid() && _data->_page->drawingArea()) { 1248 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); 1249 _data->_page->drawingArea()->paint(IntRect(rect), context); 1250 _data->_page->didDraw(); 1251 } else if (_data->_page->drawsBackground()) { 1252 [_data->_page->drawsTransparentBackground() ? [NSColor clearColor] : [NSColor whiteColor] set]; 1253 NSRectFill(rect); 1254 } 1255} 1256 1257- (BOOL)isOpaque 1258{ 1259 return _data->_page->drawsBackground(); 1260} 1261 1262- (void)viewDidHide 1263{ 1264 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1265} 1266 1267- (void)viewDidUnhide 1268{ 1269 _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible); 1270} 1271 1272- (void)_setAccessibilityChildToken:(NSData *)data 1273{ 1274#if !defined(BUILDING_ON_SNOW_LEOPARD) 1275 _data->_remoteAccessibilityChild = WKAXRemoteElementForToken((CFDataRef)data); 1276 WKAXInitializeRemoteElementWithWindow(_data->_remoteAccessibilityChild.get(), [self window]); 1277#endif 1278} 1279 1280- (BOOL)accessibilityIsIgnored 1281{ 1282 return NO; 1283} 1284 1285- (id)accessibilityHitTest:(NSPoint)point 1286{ 1287 return _data->_remoteAccessibilityChild.get(); 1288} 1289 1290- (id)accessibilityAttributeValue:(NSString*)attribute 1291{ 1292 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { 1293 if (!_data->_remoteAccessibilityChild) 1294 return nil; 1295 return [NSArray arrayWithObject:_data->_remoteAccessibilityChild.get()]; 1296 } 1297 if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) 1298 return NSAccessibilityGroupRole; 1299 if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) 1300 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil); 1301 if ([attribute isEqualToString:NSAccessibilityParentAttribute]) 1302 return NSAccessibilityUnignoredAncestor([self superview]); 1303 if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) 1304 return [NSNumber numberWithBool:YES]; 1305 1306 return [super accessibilityAttributeValue:attribute]; 1307} 1308 1309- (NSView *)hitTest:(NSPoint)point 1310{ 1311 NSView *hitView = [super hitTest:point]; 1312#if USE(ACCELERATED_COMPOSITING) 1313 if (hitView && _data && hitView == _data->_layerHostingView) 1314 hitView = self; 1315#endif 1316 return hitView; 1317} 1318 1319- (NSInteger)conversationIdentifier 1320{ 1321 return (NSInteger)self; 1322} 1323 1324static void setFrameBeingPrinted(NSPrintOperation *printOperation, WebFrameProxy* frame) 1325{ 1326 RetainPtr<WebFrameWrapper> frameWrapper(AdoptNS, [[WebFrameWrapper alloc] initWithFrameProxy:frame]); 1327 [[[printOperation printInfo] dictionary] setObject:frameWrapper.get() forKey:PrintedFrameKey]; 1328} 1329 1330static WebFrameProxy* frameBeingPrinted() 1331{ 1332 return [[[[[NSPrintOperation currentOperation] printInfo] dictionary] objectForKey:PrintedFrameKey] webFrame]; 1333} 1334 1335- (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo forFrame:(WKFrameRef)frameRef 1336{ 1337 LOG(View, "Creating an NSPrintOperation for frame '%s'", toImpl(frameRef)->url().utf8().data()); 1338 NSPrintOperation *printOperation; 1339 1340 // Only the top frame can currently contain a PDF view. 1341 if (_data->_pdfViewController) { 1342 ASSERT(toImpl(frameRef)->isMainFrame()); 1343 printOperation = _data->_pdfViewController->makePrintOperation(printInfo); 1344 } else 1345 printOperation = [NSPrintOperation printOperationWithView:self printInfo:printInfo]; 1346 1347 setFrameBeingPrinted(printOperation, toImpl(frameRef)); 1348 return printOperation; 1349} 1350 1351- (BOOL)canChangeFrameLayout:(WKFrameRef)frameRef 1352{ 1353 // PDF documents are already paginated, so we can't change them to add headers and footers. 1354 return !toImpl(frameRef)->isMainFrame() || !_data->_pdfViewController; 1355} 1356 1357// Return the number of pages available for printing 1358- (BOOL)knowsPageRange:(NSRangePointer)range 1359{ 1360 LOG(View, "knowsPageRange:"); 1361 WebFrameProxy* frame = frameBeingPrinted(); 1362 ASSERT(frame); 1363 1364 if (frame->isMainFrame() && _data->_pdfViewController) 1365 return [super knowsPageRange:range]; 1366 1367 _data->_page->computePagesForPrinting(frame, PrintInfo([[NSPrintOperation currentOperation] printInfo]), _data->_printingPageRects, _data->_totalScaleFactorForPrinting); 1368 1369 *range = NSMakeRange(1, _data->_printingPageRects.size()); 1370 return YES; 1371} 1372 1373// Take over printing. AppKit applies incorrect clipping, and doesn't print pages beyond the first one. 1374- (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView 1375{ 1376 // FIXME: This check isn't right for some non-printing cases, such as capturing into a buffer using cacheDisplayInRect:toBitmapImageRep:. 1377 if ([NSGraphicsContext currentContextDrawingToScreen]) { 1378 _data->_page->endPrinting(); 1379 [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect isVisibleRect:isVisibleRect rectIsVisibleRectForView:visibleView topView:topView]; 1380 return; 1381 } 1382 1383 LOG(View, "Printing rect x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 1384 1385 ASSERT(self == visibleView); 1386 ASSERT(frameBeingPrinted()); 1387 1388 WebFrameProxy* frame = frameBeingPrinted(); 1389 ASSERT(frame); 1390 1391 _data->_page->beginPrinting(frame, PrintInfo([[NSPrintOperation currentOperation] printInfo])); 1392 1393 // FIXME: This is optimized for print preview. Get the whole document at once when actually printing. 1394 Vector<uint8_t> pdfData; 1395 _data->_page->drawRectToPDF(frame, IntRect(rect), pdfData); 1396 1397 RetainPtr<CGDataProviderRef> pdfDataProvider(AdoptCF, CGDataProviderCreateWithData(0, pdfData.data(), pdfData.size(), 0)); 1398 RetainPtr<CGPDFDocumentRef> pdfDocument(AdoptCF, CGPDFDocumentCreateWithProvider(pdfDataProvider.get())); 1399 if (!pdfDocument) { 1400 LOG_ERROR("Couldn't create a PDF document with data passed for printing"); 1401 return; 1402 } 1403 1404 CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument.get(), 1); 1405 if (!pdfPage) { 1406 LOG_ERROR("Printing data doesn't have page 1"); 1407 return; 1408 } 1409 1410 NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext]; 1411 CGContextRef context = static_cast<CGContextRef>([nsGraphicsContext graphicsPort]); 1412 1413 CGContextSaveGState(context); 1414 // Flip the destination. 1415 CGContextScaleCTM(context, 1, -1); 1416 CGContextTranslateCTM(context, 0, -rect.size.height); 1417 CGContextDrawPDFPage(context, pdfPage); 1418 CGContextRestoreGState(context); 1419} 1420 1421// FIXME 3491344: This is an AppKit-internal method that we need to override in order 1422// to get our shrink-to-fit to work with a custom pagination scheme. We can do this better 1423// if AppKit makes it SPI/API. 1424- (CGFloat)_provideTotalScaleFactorForPrintOperation:(NSPrintOperation *)printOperation 1425{ 1426 return _data->_totalScaleFactorForPrinting; 1427} 1428 1429// Return the drawing rectangle for a particular page number 1430- (NSRect)rectForPage:(NSInteger)page 1431{ 1432 WebFrameProxy* frame = frameBeingPrinted(); 1433 ASSERT(frame); 1434 1435 if (frame->isMainFrame() && _data->_pdfViewController) 1436 return [super rectForPage:page]; 1437 1438 LOG(View, "rectForPage:%d -> x %d, y %d, width %d, height %d\n", (int)page, _data->_printingPageRects[page - 1].x(), _data->_printingPageRects[page - 1].y(), _data->_printingPageRects[page - 1].width(), _data->_printingPageRects[page - 1].height()); 1439 return _data->_printingPageRects[page - 1]; 1440} 1441 1442@end 1443 1444@implementation WKView (Internal) 1445 1446- (PassOwnPtr<WebKit::DrawingAreaProxy>)_createDrawingAreaProxy 1447{ 1448 if (useNewDrawingArea()) 1449 return DrawingAreaProxyImpl::create(_data->_page.get()); 1450 1451 return ChunkedUpdateDrawingAreaProxy::create(self, _data->_page.get()); 1452} 1453 1454- (BOOL)_isFocused 1455{ 1456 if (_data->_inBecomeFirstResponder) 1457 return YES; 1458 if (_data->_inResignFirstResponder) 1459 return NO; 1460 return [[self window] firstResponder] == self; 1461} 1462 1463- (void)_processDidCrash 1464{ 1465 [self setNeedsDisplay:YES]; 1466} 1467 1468- (void)_didRelaunchProcess 1469{ 1470 [self setNeedsDisplay:YES]; 1471} 1472 1473- (void)_takeFocus:(BOOL)forward 1474{ 1475 if (forward) 1476 [[self window] selectKeyViewFollowingView:self]; 1477 else 1478 [[self window] selectKeyViewPrecedingView:self]; 1479} 1480 1481- (void)_setCursor:(NSCursor *)cursor 1482{ 1483 if ([NSCursor currentCursor] == cursor) 1484 return; 1485 [cursor set]; 1486} 1487 1488- (void)_setUserInterfaceItemState:(NSString *)commandName enabled:(BOOL)isEnabled state:(int)newState 1489{ 1490 ValidationVector items = _data->_validationMap.take(commandName); 1491 size_t size = items.size(); 1492 for (size_t i = 0; i < size; ++i) { 1493 ValidationItem item = items[i].get(); 1494 [menuItem(item) setState:newState]; 1495 [menuItem(item) setEnabled:isEnabled]; 1496 [toolbarItem(item) setEnabled:isEnabled]; 1497 // FIXME <rdar://problem/8803392>: If the item is neither a menu nor toolbar item, it will be left enabled. 1498 } 1499} 1500 1501- (NSRect)_convertToDeviceSpace:(NSRect)rect 1502{ 1503 return toDeviceSpace(rect, [self window]); 1504} 1505 1506- (NSRect)_convertToUserSpace:(NSRect)rect 1507{ 1508 return toUserSpace(rect, [self window]); 1509} 1510 1511// Any non-zero value will do, but using something recognizable might help us debug some day. 1512#define TRACKING_RECT_TAG 0xBADFACE 1513 1514- (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside 1515{ 1516 ASSERT(_data->_trackingRectOwner == nil); 1517 _data->_trackingRectOwner = owner; 1518 _data->_trackingRectUserData = data; 1519 return TRACKING_RECT_TAG; 1520} 1521 1522- (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag 1523{ 1524 ASSERT(tag == 0 || tag == TRACKING_RECT_TAG); 1525 ASSERT(_data->_trackingRectOwner == nil); 1526 _data->_trackingRectOwner = owner; 1527 _data->_trackingRectUserData = data; 1528 return TRACKING_RECT_TAG; 1529} 1530 1531- (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count 1532{ 1533 ASSERT(count == 1); 1534 ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG); 1535 ASSERT(_data->_trackingRectOwner == nil); 1536 _data->_trackingRectOwner = owner; 1537 _data->_trackingRectUserData = userDataList[0]; 1538 trackingNums[0] = TRACKING_RECT_TAG; 1539} 1540 1541- (void)removeTrackingRect:(NSTrackingRectTag)tag 1542{ 1543 if (tag == 0) 1544 return; 1545 1546 if (_data && (tag == TRACKING_RECT_TAG)) { 1547 _data->_trackingRectOwner = nil; 1548 return; 1549 } 1550 1551 if (_data && (tag == _data->_lastToolTipTag)) { 1552 [super removeTrackingRect:tag]; 1553 _data->_lastToolTipTag = 0; 1554 return; 1555 } 1556 1557 // If any other tracking rect is being removed, we don't know how it was created 1558 // and it's possible there's a leak involved (see 3500217) 1559 ASSERT_NOT_REACHED(); 1560} 1561 1562- (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count 1563{ 1564 int i; 1565 for (i = 0; i < count; ++i) { 1566 int tag = tags[i]; 1567 if (tag == 0) 1568 continue; 1569 ASSERT(tag == TRACKING_RECT_TAG); 1570 if (_data != nil) { 1571 _data->_trackingRectOwner = nil; 1572 } 1573 } 1574} 1575 1576- (void)_sendToolTipMouseExited 1577{ 1578 // Nothing matters except window, trackingNumber, and userData. 1579 NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited 1580 location:NSMakePoint(0, 0) 1581 modifierFlags:0 1582 timestamp:0 1583 windowNumber:[[self window] windowNumber] 1584 context:NULL 1585 eventNumber:0 1586 trackingNumber:TRACKING_RECT_TAG 1587 userData:_data->_trackingRectUserData]; 1588 [_data->_trackingRectOwner mouseExited:fakeEvent]; 1589} 1590 1591- (void)_sendToolTipMouseEntered 1592{ 1593 // Nothing matters except window, trackingNumber, and userData. 1594 NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered 1595 location:NSMakePoint(0, 0) 1596 modifierFlags:0 1597 timestamp:0 1598 windowNumber:[[self window] windowNumber] 1599 context:NULL 1600 eventNumber:0 1601 trackingNumber:TRACKING_RECT_TAG 1602 userData:_data->_trackingRectUserData]; 1603 [_data->_trackingRectOwner mouseEntered:fakeEvent]; 1604} 1605 1606- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data 1607{ 1608 return nsStringFromWebCoreString(_data->_page->toolTip()); 1609} 1610 1611- (void)_toolTipChangedFrom:(NSString *)oldToolTip to:(NSString *)newToolTip 1612{ 1613 if (oldToolTip) 1614 [self _sendToolTipMouseExited]; 1615 1616 if (newToolTip && [newToolTip length] > 0) { 1617 // See radar 3500217 for why we remove all tooltips rather than just the single one we created. 1618 [self removeAllToolTips]; 1619 NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000); 1620 _data->_lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL]; 1621 [self _sendToolTipMouseEntered]; 1622 } 1623} 1624 1625- (void)_setFindIndicator:(PassRefPtr<FindIndicator>)findIndicator fadeOut:(BOOL)fadeOut 1626{ 1627 if (!findIndicator) { 1628 _data->_findIndicatorWindow = 0; 1629 return; 1630 } 1631 1632 if (!_data->_findIndicatorWindow) 1633 _data->_findIndicatorWindow = FindIndicatorWindow::create(self); 1634 1635 _data->_findIndicatorWindow->setFindIndicator(findIndicator, fadeOut); 1636} 1637 1638#if USE(ACCELERATED_COMPOSITING) 1639- (void)_startAcceleratedCompositing:(CALayer *)rootLayer 1640{ 1641 if (!_data->_layerHostingView) { 1642 NSView *hostingView = [[NSView alloc] initWithFrame:[self bounds]]; 1643#if !defined(BUILDING_ON_LEOPARD) 1644 [hostingView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 1645#endif 1646 1647 [self addSubview:hostingView]; 1648 [hostingView release]; 1649 _data->_layerHostingView = hostingView; 1650 } 1651 1652 // Make a container layer, which will get sized/positioned by AppKit and CA. 1653 CALayer *viewLayer = [CALayer layer]; 1654 1655#ifndef NDEBUG 1656 [viewLayer setName:@"hosting layer"]; 1657#endif 1658 1659#if defined(BUILDING_ON_LEOPARD) 1660 // Turn off default animations. 1661 NSNull *nullValue = [NSNull null]; 1662 NSDictionary *actions = [NSDictionary dictionaryWithObjectsAndKeys: 1663 nullValue, @"anchorPoint", 1664 nullValue, @"bounds", 1665 nullValue, @"contents", 1666 nullValue, @"contentsRect", 1667 nullValue, @"opacity", 1668 nullValue, @"position", 1669 nullValue, @"sublayerTransform", 1670 nullValue, @"sublayers", 1671 nullValue, @"transform", 1672 nil]; 1673 [viewLayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]]; 1674#endif 1675 1676#if !defined(BUILDING_ON_LEOPARD) 1677 // If we aren't in the window yet, we'll use the screen's scale factor now, and reset the scale 1678 // via -viewDidMoveToWindow. 1679 CGFloat scaleFactor = [self window] ? [[self window] userSpaceScaleFactor] : [[NSScreen mainScreen] userSpaceScaleFactor]; 1680 [viewLayer setTransform:CATransform3DMakeScale(scaleFactor, scaleFactor, 1)]; 1681#endif 1682 1683 [_data->_layerHostingView setLayer:viewLayer]; 1684 [_data->_layerHostingView setWantsLayer:YES]; 1685 1686 // Parent our root layer in the container layer 1687 [viewLayer addSublayer:rootLayer]; 1688} 1689 1690- (void)_stopAcceleratedCompositing 1691{ 1692 if (_data->_layerHostingView) { 1693 [_data->_layerHostingView setLayer:nil]; 1694 [_data->_layerHostingView setWantsLayer:NO]; 1695 [_data->_layerHostingView removeFromSuperview]; 1696 _data->_layerHostingView = nil; 1697 } 1698} 1699 1700- (void)_switchToDrawingAreaTypeIfNecessary:(DrawingAreaInfo::Type)type 1701{ 1702 DrawingAreaInfo::Type existingDrawingAreaType = _data->_page->drawingArea() ? _data->_page->drawingArea()->info().type : DrawingAreaInfo::None; 1703 if (existingDrawingAreaType == type) 1704 return; 1705 1706 OwnPtr<DrawingAreaProxy> newDrawingArea; 1707 switch (type) { 1708 case DrawingAreaInfo::Impl: 1709 case DrawingAreaInfo::None: 1710 break; 1711 case DrawingAreaInfo::ChunkedUpdate: { 1712 newDrawingArea = ChunkedUpdateDrawingAreaProxy::create(self, _data->_page.get()); 1713 break; 1714 } 1715 case DrawingAreaInfo::LayerBacked: { 1716 newDrawingArea = LayerBackedDrawingAreaProxy::create(self, _data->_page.get()); 1717 break; 1718 } 1719 } 1720 1721 newDrawingArea->setSize(IntSize([self frame].size)); 1722 1723 _data->_page->drawingArea()->detachCompositingContext(); 1724 _data->_page->setDrawingArea(newDrawingArea.release()); 1725} 1726 1727- (void)_pageDidEnterAcceleratedCompositing 1728{ 1729 [self _switchToDrawingAreaTypeIfNecessary:DrawingAreaInfo::LayerBacked]; 1730} 1731 1732- (void)_pageDidLeaveAcceleratedCompositing 1733{ 1734 // FIXME: we may want to avoid flipping back to the non-layer-backed drawing area until the next page load, to avoid thrashing. 1735 [self _switchToDrawingAreaTypeIfNecessary:DrawingAreaInfo::ChunkedUpdate]; 1736} 1737#endif // USE(ACCELERATED_COMPOSITING) 1738 1739- (void)_setComplexTextInputEnabled:(BOOL)complexTextInputEnabled pluginComplexTextInputIdentifier:(uint64_t)pluginComplexTextInputIdentifier 1740{ 1741 BOOL inputSourceChanged = _data->_pluginComplexTextInputIdentifier; 1742 1743 if (complexTextInputEnabled) { 1744 // Check if we're already allowing text input for this plug-in. 1745 if (pluginComplexTextInputIdentifier == _data->_pluginComplexTextInputIdentifier) 1746 return; 1747 1748 _data->_pluginComplexTextInputIdentifier = pluginComplexTextInputIdentifier; 1749 1750 } else { 1751 // Check if we got a request to disable complex text input for a plug-in that is not the current plug-in. 1752 if (pluginComplexTextInputIdentifier != _data->_pluginComplexTextInputIdentifier) 1753 return; 1754 1755 _data->_pluginComplexTextInputIdentifier = 0; 1756 } 1757 1758 if (inputSourceChanged) { 1759 // Inform the out of line window that the input source changed. 1760 [[WKTextInputWindowController sharedTextInputWindowController] keyboardInputSourceChanged]; 1761 } 1762} 1763 1764- (void)_setPageHasCustomRepresentation:(BOOL)pageHasCustomRepresentation 1765{ 1766 _data->_pdfViewController = nullptr; 1767 1768 if (pageHasCustomRepresentation) 1769 _data->_pdfViewController = PDFViewController::create(self); 1770} 1771 1772- (void)_didFinishLoadingDataForCustomRepresentation:(const CoreIPC::DataReference&)dataReference 1773{ 1774 ASSERT(_data->_pdfViewController); 1775 1776 _data->_pdfViewController->setPDFDocumentData(_data->_page->mainFrame()->mimeType(), dataReference); 1777} 1778 1779- (double)_customRepresentationZoomFactor 1780{ 1781 if (!_data->_pdfViewController) 1782 return 1; 1783 1784 return _data->_pdfViewController->zoomFactor(); 1785} 1786 1787- (void)_setCustomRepresentationZoomFactor:(double)zoomFactor 1788{ 1789 if (!_data->_pdfViewController) 1790 return; 1791 1792 _data->_pdfViewController->setZoomFactor(zoomFactor); 1793} 1794 1795@end 1796