1/* 2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 David Smith (catfish.man@gmail.com) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#import "WebViewInternal.h" 31#import "WebViewData.h" 32 33#import "DOMCSSStyleDeclarationInternal.h" 34#import "DOMNodeInternal.h" 35#import "DOMRangeInternal.h" 36#import "WebBackForwardListInternal.h" 37#import "WebCache.h" 38#import "WebChromeClient.h" 39#import "WebContextMenuClient.h" 40#import "WebDOMOperationsPrivate.h" 41#import "WebDataSourceInternal.h" 42#import "WebDatabaseManagerInternal.h" 43#import "WebDefaultEditingDelegate.h" 44#import "WebDefaultPolicyDelegate.h" 45#import "WebDefaultUIDelegate.h" 46#import "WebDelegateImplementationCaching.h" 47#import "WebDocument.h" 48#import "WebDocumentInternal.h" 49#import "WebDownload.h" 50#import "WebDownloadInternal.h" 51#import "WebDragClient.h" 52#import "WebDynamicScrollBarsViewInternal.h" 53#import "WebEditingDelegate.h" 54#import "WebEditorClient.h" 55#import "WebFormDelegatePrivate.h" 56#import "WebFrameInternal.h" 57#import "WebFrameViewInternal.h" 58#import "WebHTMLRepresentation.h" 59#import "WebHTMLViewInternal.h" 60#import "WebHistoryItemInternal.h" 61#import "WebIconDatabaseInternal.h" 62#import "WebInspector.h" 63#import "WebInspectorClient.h" 64#import "WebKitErrors.h" 65#import "WebKitLogging.h" 66#import "WebKitNSStringExtras.h" 67#import "WebKitStatisticsPrivate.h" 68#import "WebKitSystemBits.h" 69#import "WebKitVersionChecks.h" 70#import "WebLocalizableStrings.h" 71#import "WebNSDataExtras.h" 72#import "WebNSDataExtrasPrivate.h" 73#import "WebNSDictionaryExtras.h" 74#import "WebNSEventExtras.h" 75#import "WebNSObjectExtras.h" 76#import "WebNSPasteboardExtras.h" 77#import "WebNSPrintOperationExtras.h" 78#import "WebNSURLExtras.h" 79#import "WebNSURLRequestExtras.h" 80#import "WebNSUserDefaultsExtras.h" 81#import "WebNSViewExtras.h" 82#import "WebNodeHighlight.h" 83#import "WebPDFView.h" 84#import "WebPanelAuthenticationHandler.h" 85#import "WebPasteboardHelper.h" 86#import "WebPluginDatabase.h" 87#import "WebPolicyDelegate.h" 88#import "WebPreferenceKeysPrivate.h" 89#import "WebPreferencesPrivate.h" 90#import "WebScriptDebugDelegate.h" 91#import "WebSystemInterface.h" 92#import "WebTextCompletionController.h" 93#import "WebTextIterator.h" 94#import "WebUIDelegate.h" 95#import "WebUIDelegatePrivate.h" 96#import <CoreFoundation/CFSet.h> 97#import <Foundation/NSURLConnection.h> 98#import <WebCore/ApplicationCacheStorage.h> 99#import <WebCore/Cache.h> 100#import <WebCore/ColorMac.h> 101#import <WebCore/Cursor.h> 102#import <WebCore/Document.h> 103#import <WebCore/DocumentLoader.h> 104#import <WebCore/DragController.h> 105#import <WebCore/DragData.h> 106#import <WebCore/Editor.h> 107#import <WebCore/EventHandler.h> 108#import <WebCore/ExceptionHandlers.h> 109#import <WebCore/FocusController.h> 110#import <WebCore/Frame.h> 111#import <WebCore/FrameLoader.h> 112#import <WebCore/FrameTree.h> 113#import <WebCore/FrameView.h> 114#import <WebCore/GCController.h> 115#import <WebCore/HTMLNames.h> 116#import <WebCore/HistoryItem.h> 117#import <WebCore/IconDatabase.h> 118#import <WebCore/Logging.h> 119#import <WebCore/MIMETypeRegistry.h> 120#import <WebCore/Page.h> 121#import <WebCore/PageCache.h> 122#import <WebCore/PageGroup.h> 123#import <WebCore/PlatformMouseEvent.h> 124#import <WebCore/ProgressTracker.h> 125#import <WebCore/ResourceHandle.h> 126#import <WebCore/RuntimeApplicationChecks.h> 127#import <WebCore/ScriptController.h> 128#import <WebCore/ScriptValue.h> 129#import <WebCore/SecurityOrigin.h> 130#import <WebCore/SelectionController.h> 131#import <WebCore/Settings.h> 132#import <WebCore/TextResourceDecoder.h> 133#import <WebCore/ThreadCheck.h> 134#import <WebCore/WebCoreObjCExtras.h> 135#import <WebCore/WebCoreView.h> 136#import <WebCore/Widget.h> 137#import <WebKit/DOM.h> 138#import <WebKit/DOMExtensions.h> 139#import <WebKit/DOMPrivate.h> 140#import <WebKitSystemInterface.h> 141#import <mach-o/dyld.h> 142#import <objc/objc-auto.h> 143#import <objc/objc-runtime.h> 144#import <runtime/ArrayPrototype.h> 145#import <runtime/DateInstance.h> 146#import <runtime/InitializeThreading.h> 147#import <runtime/JSLock.h> 148#import <runtime/JSValue.h> 149#import <wtf/Assertions.h> 150#import <wtf/HashTraits.h> 151#import <wtf/RefCountedLeakCounter.h> 152#import <wtf/RefPtr.h> 153#import <wtf/StdLibExtras.h> 154 155#if ENABLE(DASHBOARD_SUPPORT) 156#import <WebKit/WebDashboardRegion.h> 157#endif 158 159@class NSTextInputContext; 160 161@interface NSResponder (WebNSResponderDetails) 162- (NSTextInputContext *)inputContext; 163@end 164 165@interface NSSpellChecker (WebNSSpellCheckerDetails) 166- (void)_preflightChosenSpellServer; 167@end 168 169@interface NSView (WebNSViewDetails) 170- (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types; 171- (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta; 172- (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo; 173@end 174 175@interface NSWindow (WebNSWindowDetails) 176- (id)_oldFirstResponderBeforeBecoming; 177@end 178 179using namespace WebCore; 180using namespace JSC; 181 182#if defined(__ppc__) || defined(__ppc64__) 183#define PROCESSOR "PPC" 184#elif defined(__i386__) || defined(__x86_64__) 185#define PROCESSOR "Intel" 186#else 187#error Unknown architecture 188#endif 189 190#define FOR_EACH_RESPONDER_SELECTOR(macro) \ 191macro(alignCenter) \ 192macro(alignJustified) \ 193macro(alignLeft) \ 194macro(alignRight) \ 195macro(capitalizeWord) \ 196macro(centerSelectionInVisibleArea) \ 197macro(changeAttributes) \ 198macro(changeBaseWritingDirection) \ 199macro(changeBaseWritingDirectionToLTR) \ 200macro(changeBaseWritingDirectionToRTL) \ 201macro(changeColor) \ 202macro(changeDocumentBackgroundColor) \ 203macro(changeFont) \ 204macro(changeSpelling) \ 205macro(checkSpelling) \ 206macro(complete) \ 207macro(copy) \ 208macro(copyFont) \ 209macro(cut) \ 210macro(delete) \ 211macro(deleteBackward) \ 212macro(deleteBackwardByDecomposingPreviousCharacter) \ 213macro(deleteForward) \ 214macro(deleteToBeginningOfLine) \ 215macro(deleteToBeginningOfParagraph) \ 216macro(deleteToEndOfLine) \ 217macro(deleteToEndOfParagraph) \ 218macro(deleteToMark) \ 219macro(deleteWordBackward) \ 220macro(deleteWordForward) \ 221macro(ignoreSpelling) \ 222macro(indent) \ 223macro(insertBacktab) \ 224macro(insertLineBreak) \ 225macro(insertNewline) \ 226macro(insertNewlineIgnoringFieldEditor) \ 227macro(insertParagraphSeparator) \ 228macro(insertTab) \ 229macro(insertTabIgnoringFieldEditor) \ 230macro(lowercaseWord) \ 231macro(makeBaseWritingDirectionLeftToRight) \ 232macro(makeBaseWritingDirectionRightToLeft) \ 233macro(makeTextWritingDirectionLeftToRight) \ 234macro(makeTextWritingDirectionNatural) \ 235macro(makeTextWritingDirectionRightToLeft) \ 236macro(moveBackward) \ 237macro(moveBackwardAndModifySelection) \ 238macro(moveDown) \ 239macro(moveDownAndModifySelection) \ 240macro(moveForward) \ 241macro(moveForwardAndModifySelection) \ 242macro(moveLeft) \ 243macro(moveLeftAndModifySelection) \ 244macro(moveParagraphBackwardAndModifySelection) \ 245macro(moveParagraphForwardAndModifySelection) \ 246macro(moveRight) \ 247macro(moveRightAndModifySelection) \ 248macro(moveToBeginningOfDocument) \ 249macro(moveToBeginningOfDocumentAndModifySelection) \ 250macro(moveToBeginningOfLine) \ 251macro(moveToBeginningOfLineAndModifySelection) \ 252macro(moveToBeginningOfParagraph) \ 253macro(moveToBeginningOfParagraphAndModifySelection) \ 254macro(moveToBeginningOfSentence) \ 255macro(moveToBeginningOfSentenceAndModifySelection) \ 256macro(moveToEndOfDocument) \ 257macro(moveToEndOfDocumentAndModifySelection) \ 258macro(moveToEndOfLine) \ 259macro(moveToEndOfLineAndModifySelection) \ 260macro(moveToEndOfParagraph) \ 261macro(moveToEndOfParagraphAndModifySelection) \ 262macro(moveToEndOfSentence) \ 263macro(moveToEndOfSentenceAndModifySelection) \ 264macro(moveToLeftEndOfLine) \ 265macro(moveToLeftEndOfLineAndModifySelection) \ 266macro(moveToRightEndOfLine) \ 267macro(moveToRightEndOfLineAndModifySelection) \ 268macro(moveUp) \ 269macro(moveUpAndModifySelection) \ 270macro(moveWordBackward) \ 271macro(moveWordBackwardAndModifySelection) \ 272macro(moveWordForward) \ 273macro(moveWordForwardAndModifySelection) \ 274macro(moveWordLeft) \ 275macro(moveWordLeftAndModifySelection) \ 276macro(moveWordRight) \ 277macro(moveWordRightAndModifySelection) \ 278macro(outdent) \ 279macro(orderFrontSubstitutionsPanel) \ 280macro(pageDown) \ 281macro(pageDownAndModifySelection) \ 282macro(pageUp) \ 283macro(pageUpAndModifySelection) \ 284macro(paste) \ 285macro(pasteAsPlainText) \ 286macro(pasteAsRichText) \ 287macro(pasteFont) \ 288macro(performFindPanelAction) \ 289macro(scrollLineDown) \ 290macro(scrollLineUp) \ 291macro(scrollPageDown) \ 292macro(scrollPageUp) \ 293macro(scrollToBeginningOfDocument) \ 294macro(scrollToEndOfDocument) \ 295macro(selectAll) \ 296macro(selectLine) \ 297macro(selectParagraph) \ 298macro(selectSentence) \ 299macro(selectToMark) \ 300macro(selectWord) \ 301macro(setMark) \ 302macro(showGuessPanel) \ 303macro(startSpeaking) \ 304macro(stopSpeaking) \ 305macro(subscript) \ 306macro(superscript) \ 307macro(swapWithMark) \ 308macro(takeFindStringFromSelection) \ 309macro(toggleBaseWritingDirection) \ 310macro(transpose) \ 311macro(underline) \ 312macro(unscript) \ 313macro(uppercaseWord) \ 314macro(yank) \ 315macro(yankAndSelect) \ 316 317#define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin" 318#define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin" 319 320#define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange" 321#define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode") 322#define UniversalAccessDomain CFSTR("com.apple.universalaccess") 323 324#if USE(ACCELERATED_COMPOSITING) 325#define UsingAcceleratedCompositingProperty @"_isUsingAcceleratedCompositing" 326#endif 327 328static BOOL s_didSetCacheModel; 329static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer; 330 331static WebView *lastMouseoverView; 332 333#ifndef NDEBUG 334static const char webViewIsOpen[] = "At least one WebView is still open."; 335#endif 336 337#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 338@interface NSObject (NSTextInputContextDetails) 339- (BOOL)wantsToHandleMouseEvents; 340- (BOOL)handleMouseEvent:(NSEvent *)event; 341@end 342#endif 343 344@interface NSObject (WebValidateWithoutDelegate) 345- (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item; 346@end 347 348@interface _WebSafeForwarder : NSObject 349{ 350 id target; // Non-retained. Don't retain delegates. 351 id defaultTarget; 352 BOOL catchExceptions; 353} 354- (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions; 355@end 356 357@interface WebView (WebFileInternal) 358- (WebFrame *)_selectedOrMainFrame; 359- (BOOL)_isLoading; 360- (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point; 361- (WebFrame *)_focusedFrame; 362+ (void)_preflightSpellChecker; 363- (BOOL)_continuousCheckingAllowed; 364- (NSResponder *)_responderForResponderOperations; 365#if USE(ACCELERATED_COMPOSITING) 366- (void)_clearLayerSyncLoopObserver; 367#endif 368@end 369 370static void patchMailRemoveAttributesMethod(); 371 372NSString *WebElementDOMNodeKey = @"WebElementDOMNode"; 373NSString *WebElementFrameKey = @"WebElementFrame"; 374NSString *WebElementImageKey = @"WebElementImage"; 375NSString *WebElementImageAltStringKey = @"WebElementImageAltString"; 376NSString *WebElementImageRectKey = @"WebElementImageRect"; 377NSString *WebElementImageURLKey = @"WebElementImageURL"; 378NSString *WebElementIsSelectedKey = @"WebElementIsSelected"; 379NSString *WebElementLinkLabelKey = @"WebElementLinkLabel"; 380NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame"; 381NSString *WebElementLinkTitleKey = @"WebElementLinkTitle"; 382NSString *WebElementLinkURLKey = @"WebElementLinkURL"; 383NSString *WebElementSpellingToolTipKey = @"WebElementSpellingToolTip"; 384NSString *WebElementTitleKey = @"WebElementTitle"; 385NSString *WebElementLinkIsLiveKey = @"WebElementLinkIsLive"; 386NSString *WebElementIsContentEditableKey = @"WebElementIsContentEditableKey"; 387 388NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification"; 389NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification"; 390NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification"; 391 392NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification"; 393NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification"; 394NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification"; 395NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification"; 396NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification"; 397 398enum { WebViewVersion = 4 }; 399 400#define timedLayoutSize 4096 401 402static NSMutableSet *schemesWithRepresentationsSet; 403 404NSString *_WebCanGoBackKey = @"canGoBack"; 405NSString *_WebCanGoForwardKey = @"canGoForward"; 406NSString *_WebEstimatedProgressKey = @"estimatedProgress"; 407NSString *_WebIsLoadingKey = @"isLoading"; 408NSString *_WebMainFrameIconKey = @"mainFrameIcon"; 409NSString *_WebMainFrameTitleKey = @"mainFrameTitle"; 410NSString *_WebMainFrameURLKey = @"mainFrameURL"; 411NSString *_WebMainFrameDocumentKey = @"mainFrameDocument"; 412 413@interface WebProgressItem : NSObject 414{ 415@public 416 long long bytesReceived; 417 long long estimatedLength; 418} 419@end 420 421@implementation WebProgressItem 422@end 423 424static BOOL continuousSpellCheckingEnabled; 425#ifndef BUILDING_ON_TIGER 426static BOOL grammarCheckingEnabled; 427#endif 428#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 429static BOOL automaticQuoteSubstitutionEnabled; 430static BOOL automaticLinkDetectionEnabled; 431static BOOL automaticDashSubstitutionEnabled; 432static BOOL automaticTextReplacementEnabled; 433static BOOL automaticSpellingCorrectionEnabled; 434#endif 435 436@implementation WebView (AllWebViews) 437 438static CFSetCallBacks NonRetainingSetCallbacks = { 439 0, 440 NULL, 441 NULL, 442 CFCopyDescription, 443 CFEqual, 444 CFHash 445}; 446 447static CFMutableSetRef allWebViewsSet; 448 449+ (void)_makeAllWebViewsPerformSelector:(SEL)selector 450{ 451 if (!allWebViewsSet) 452 return; 453 454 [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector]; 455} 456 457- (void)_removeFromAllWebViewsSet 458{ 459 if (allWebViewsSet) 460 CFSetRemoveValue(allWebViewsSet, self); 461} 462 463- (void)_addToAllWebViewsSet 464{ 465 if (!allWebViewsSet) 466 allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks); 467 468 CFSetSetValue(allWebViewsSet, self); 469} 470 471@end 472 473@implementation WebView (WebPrivate) 474 475static inline int callGestalt(OSType selector) 476{ 477 SInt32 value = 0; 478 Gestalt(selector, &value); 479 return value; 480} 481 482// Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4. 483static NSString *createMacOSXVersionString() 484{ 485 // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want. 486 int major = callGestalt(gestaltSystemVersionMajor); 487 ASSERT(major); 488 489 int minor = callGestalt(gestaltSystemVersionMinor); 490 int bugFix = callGestalt(gestaltSystemVersionBugFix); 491 if (bugFix) 492 return [[NSString alloc] initWithFormat:@"%d_%d_%d", major, minor, bugFix]; 493 if (minor) 494 return [[NSString alloc] initWithFormat:@"%d_%d", major, minor]; 495 return [[NSString alloc] initWithFormat:@"%d", major]; 496} 497 498static NSString *createUserVisibleWebKitVersionString() 499{ 500 // If the version is 4 digits long or longer, then the first digit represents 501 // the version of the OS. Our user agent string should not include this first digit, 502 // so strip it off and report the rest as the version. <rdar://problem/4997547> 503 NSString *fullVersion = [[NSBundle bundleForClass:[WebView class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; 504 NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; 505 if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4) 506 return [[fullVersion substringFromIndex:1] copy]; 507 if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4) 508 return [[fullVersion substringFromIndex:1] copy]; 509 return [fullVersion copy]; 510} 511 512+ (NSString *)_standardUserAgentWithApplicationName:(NSString *)applicationName 513{ 514 // Note: Do *not* move the initialization of osVersion nor webKitVersion into the declaration. 515 // Garbage collection won't correctly mark the global variable in that case <rdar://problem/5733674>. 516 static NSString *osVersion; 517 static NSString *webKitVersion; 518 if (!osVersion) 519 osVersion = createMacOSXVersionString(); 520 if (!webKitVersion) 521 webKitVersion = createUserVisibleWebKitVersionString(); 522 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode]; 523 if ([applicationName length]) 524 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko) %@", osVersion, language, webKitVersion, applicationName]; 525 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko)", osVersion, language, webKitVersion]; 526} 527 528static void WebKitInitializeApplicationCachePathIfNecessary() 529{ 530 static BOOL initialized = NO; 531 if (initialized) 532 return; 533 534 NSString *appName = [[NSBundle mainBundle] bundleIdentifier]; 535 if (!appName) 536 appName = [[NSProcessInfo processInfo] processName]; 537 538 ASSERT(appName); 539 540 NSString* cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:appName]; 541 542 cacheStorage().setCacheDirectory(cacheDir); 543 initialized = YES; 544} 545 546static bool runningLeopardMail() 547{ 548#ifdef BUILDING_ON_LEOPARD 549 return applicationIsAppleMail(); 550#endif 551 return NO; 552} 553 554static bool runningTigerMail() 555{ 556#ifdef BUILDING_ON_TIGER 557 return applicationIsAppleMail(); 558#endif 559 return NO; 560} 561 562- (void)_dispatchPendingLoadRequests 563{ 564 cache()->loader()->servePendingRequests(); 565} 566 567- (void)_registerDraggedTypes 568{ 569 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes]; 570 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL]; 571 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes]; 572 [types addObjectsFromArray:URLTypes]; 573 [self registerForDraggedTypes:[types allObjects]]; 574 [types release]; 575} 576 577- (BOOL)_usesDocumentViews 578{ 579 return _private->usesDocumentViews; 580} 581 582- (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews 583{ 584 WebCoreThreadViolationCheckRoundTwo(); 585 586#ifndef NDEBUG 587 WTF::RefCountedLeakCounter::suppressMessages(webViewIsOpen); 588#endif 589 590 WebPreferences *standardPreferences = [WebPreferences standardPreferences]; 591 [standardPreferences willAddToWebView]; 592 593 _private->preferences = [standardPreferences retain]; 594 _private->catchesDelegateExceptions = YES; 595 _private->mainFrameDocumentReady = NO; 596 _private->drawsBackground = YES; 597 _private->backgroundColor = [[NSColor colorWithDeviceWhite:1 alpha:1] retain]; 598 _private->usesDocumentViews = usesDocumentViews; 599 600 WebFrameView *frameView = nil; 601 if (_private->usesDocumentViews) { 602 NSRect f = [self frame]; 603 frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)]; 604 [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 605 [self addSubview:frameView]; 606 [frameView release]; 607 } 608 609 static bool didOneTimeInitialization = false; 610 if (!didOneTimeInitialization) { 611 WebKitInitializeLoggingChannelsIfNecessary(); 612 WebCore::InitializeLoggingChannelsIfNecessary(); 613 [WebHistoryItem initWindowWatcherIfNecessary]; 614#if ENABLE(DATABASE) 615 WebKitInitializeDatabasesIfNecessary(); 616#endif 617 WebKitInitializeApplicationCachePathIfNecessary(); 618 patchMailRemoveAttributesMethod(); 619 didOneTimeInitialization = true; 620 } 621 622 _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self)); 623 624 _private->page->settings()->setLocalStorageDatabasePath([[self preferences] _localStorageDatabasePath]); 625 626 [WebFrame _createMainFrameWithPage:_private->page frameName:frameName frameView:frameView]; 627 628#ifndef BUILDING_ON_TIGER 629 NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; 630#else 631 NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 632#endif 633 634 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOADING_DURING_COMMON_RUNLOOP_MODES)) 635 [self scheduleInRunLoop:runLoop forMode:(NSString *)kCFRunLoopCommonModes]; 636 else 637 [self scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode]; 638 639 [self _addToAllWebViewsSet]; 640 [self setGroupName:groupName]; 641 642 // If there's already a next key view (e.g., from a nib), wire it up to our 643 // contained frame view. In any case, wire our next key view up to the our 644 // contained frame view. This works together with our becomeFirstResponder 645 // and setNextKeyView overrides. 646 NSView *nextKeyView = [self nextKeyView]; 647 if (nextKeyView && nextKeyView != frameView) 648 [frameView setNextKeyView:nextKeyView]; 649 [super setNextKeyView:frameView]; 650 651 ++WebViewCount; 652 653 [self _registerDraggedTypes]; 654 655 WebPreferences *prefs = [self preferences]; 656 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) 657 name:WebPreferencesChangedNotification object:prefs]; 658 659 // Post a notification so the WebCore settings update. 660 [[self preferences] _postPreferencesChangesNotification]; 661 662 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION)) { 663 // Originally, we allowed all local loads. 664 FrameLoader::setLocalLoadPolicy(FrameLoader::AllowLocalLoadsForAll); 665 } else if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MORE_STRICT_LOCAL_RESOURCE_SECURITY_RESTRICTION)) { 666 // Later, we allowed local loads for local URLs and documents loaded 667 // with substitute data. 668 FrameLoader::setLocalLoadPolicy(FrameLoader::AllowLocalLoadsForLocalAndSubstituteData); 669 } 670 671 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_CONTENT_SNIFFING_FOR_FILE_URLS)) 672 ResourceHandle::forceContentSniffing(); 673} 674 675- (id)_initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews 676{ 677 self = [super initWithFrame:f]; 678 if (!self) 679 return nil; 680 681#ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH 682 // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which 683 // may not work with other WebKit applications. Unsetting DYLD_FRAMEWORK_PATH removes the 684 // need for Safari to unset it to prevent it from being passed to applications it launches. 685 // Unsetting it when a WebView is first created is as good a place as any. 686 // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details. 687 if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) { 688 unsetenv("DYLD_FRAMEWORK_PATH"); 689 unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH"); 690 } 691#endif 692 693 _private = [[WebViewPrivate alloc] init]; 694 [self _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:usesDocumentViews]; 695 [self setMaintainsBackForwardList: YES]; 696 return self; 697} 698 699- (BOOL)_mustDrawUnionedRect:(NSRect)rect singleRects:(const NSRect *)rects count:(NSInteger)count 700{ 701 // If count == 0 here, use the rect passed in for drawing. This is a workaround for: 702 // <rdar://problem/3908282> REGRESSION (Mail): No drag image dragging selected text in Blot and Mail 703 // The reason for the workaround is that this method is called explicitly from the code 704 // to generate a drag image, and at that time, getRectsBeingDrawn:count: will return a zero count. 705 const int cRectThreshold = 10; 706 const float cWastedSpaceThreshold = 0.75f; 707 BOOL useUnionedRect = (count <= 1) || (count > cRectThreshold); 708 if (!useUnionedRect) { 709 // Attempt to guess whether or not we should use the unioned rect or the individual rects. 710 // We do this by computing the percentage of "wasted space" in the union. If that wasted space 711 // is too large, then we will do individual rect painting instead. 712 float unionPixels = (rect.size.width * rect.size.height); 713 float singlePixels = 0; 714 for (int i = 0; i < count; ++i) 715 singlePixels += rects[i].size.width * rects[i].size.height; 716 float wastedSpace = 1 - (singlePixels / unionPixels); 717 if (wastedSpace <= cWastedSpaceThreshold) 718 useUnionedRect = YES; 719 } 720 return useUnionedRect; 721} 722 723- (void)drawSingleRect:(NSRect)rect 724{ 725 ASSERT(!_private->usesDocumentViews); 726 727 [NSGraphicsContext saveGraphicsState]; 728 NSRectClip(rect); 729 730 @try { 731 [[self mainFrame] _drawRect:rect contentsOnly:NO]; 732 733 WebView *webView = [self _webView]; 734 [[webView _UIDelegateForwarder] webView:webView didDrawRect:rect]; 735 736 if (WebNodeHighlight *currentHighlight = [webView currentNodeHighlight]) 737 [currentHighlight setNeedsUpdateInTargetViewRect:rect]; 738 739 [NSGraphicsContext restoreGraphicsState]; 740 } @catch (NSException *localException) { 741 [NSGraphicsContext restoreGraphicsState]; 742 LOG_ERROR("Exception caught while drawing: %@", localException); 743 [localException raise]; 744 } 745} 746 747- (BOOL)isFlipped 748{ 749 return _private && !_private->usesDocumentViews; 750} 751 752- (void)setFrameSize:(NSSize)size 753{ 754 if (!_private->usesDocumentViews && !NSEqualSizes(_private->lastLayoutSize, size)) { 755 Frame* frame = [self _mainCoreFrame]; 756 // FIXME: Viewless WebKit is broken with Safari banners (e.g., the Find banner). We'll have to figure out a way for 757 // Safari to communicate that this space is being consumed. For WebKit with document views, there's no 758 // need to do an explicit resize, since WebFrameViews have auto resizing turned on and will handle changing 759 // their bounds automatically. See <rdar://problem/6835573> for details. 760 frame->view()->resize(IntSize(size)); 761 frame->view()->setNeedsLayout(); 762 [self setNeedsDisplay:YES]; 763 _private->lastLayoutSize = size; 764 } 765 766 [super setFrameSize:size]; 767} 768 769#if USE(ACCELERATED_COMPOSITING) || !defined(BUILDING_ON_TIGER) 770 771- (void)_viewWillDrawInternal 772{ 773 Frame* frame = [self _mainCoreFrame]; 774 if (frame && frame->view()) 775 frame->view()->layoutIfNeededRecursive(); 776} 777 778#endif 779 780#ifndef BUILDING_ON_TIGER 781 782- (void)viewWillDraw 783{ 784 if (!_private->usesDocumentViews) 785 [self _viewWillDrawInternal]; 786 [super viewWillDraw]; 787} 788 789#endif 790 791 792- (void)drawRect:(NSRect)rect 793{ 794 if (_private->usesDocumentViews) 795 return [super drawRect:rect]; 796 797 ASSERT_MAIN_THREAD(); 798 799 const NSRect *rects; 800 NSInteger count; 801 [self getRectsBeingDrawn:&rects count:&count]; 802 803 804 if ([self _mustDrawUnionedRect:rect singleRects:rects count:count]) 805 [self drawSingleRect:rect]; 806 else 807 for (int i = 0; i < count; ++i) 808 [self drawSingleRect:rects[i]]; 809} 810 811+ (NSArray *)_supportedMIMETypes 812{ 813 // Load the plug-in DB allowing plug-ins to install types. 814 [WebPluginDatabase sharedDatabase]; 815 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys]; 816} 817 818+ (NSArray *)_supportedFileExtensions 819{ 820 NSMutableSet *extensions = [[NSMutableSet alloc] init]; 821 NSArray *MIMETypes = [self _supportedMIMETypes]; 822 NSEnumerator *enumerator = [MIMETypes objectEnumerator]; 823 NSString *MIMEType; 824 while ((MIMEType = [enumerator nextObject]) != nil) { 825 NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType); 826 if (extensionsForType) { 827 [extensions addObjectsFromArray:extensionsForType]; 828 } 829 } 830 NSArray *uniqueExtensions = [extensions allObjects]; 831 [extensions release]; 832 return uniqueExtensions; 833} 834 835+ (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType 836{ 837 MIMEType = [MIMEType lowercaseString]; 838 Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType]; 839 Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType]; 840 841 if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) { 842 // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed. 843 // Load the plug-in DB allowing plug-ins to install types. 844 [WebPluginDatabase sharedDatabase]; 845 846 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types. 847 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType]; 848 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType]; 849 } 850 851 if (viewClass && repClass) { 852 // Special-case WebHTMLView for text types that shouldn't be shown. 853 if (viewClass == [WebHTMLView class] && 854 repClass == [WebHTMLRepresentation class] && 855 [[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) { 856 return NO; 857 } 858 if (vClass) 859 *vClass = viewClass; 860 if (rClass) 861 *rClass = repClass; 862 return YES; 863 } 864 865 return NO; 866} 867 868- (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType 869{ 870 if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType]) 871 return YES; 872 873 if (_private->pluginDatabase) { 874 WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType]; 875 if (pluginPackage) { 876 if (vClass) 877 *vClass = [WebHTMLView class]; 878 if (rClass) 879 *rClass = [WebHTMLRepresentation class]; 880 return YES; 881 } 882 } 883 884 return NO; 885} 886 887+ (void)_setAlwaysUseATSU:(BOOL)f 888{ 889 [self _setAlwaysUsesComplexTextCodePath:f]; 890} 891 892+ (void)_setAlwaysUsesComplexTextCodePath:(BOOL)f 893{ 894 Font::setCodePath(f ? Font::Complex : Font::Auto); 895} 896 897+ (BOOL)canCloseAllWebViews 898{ 899 return DOMWindow::dispatchAllPendingBeforeUnloadEvents(); 900} 901 902+ (void)closeAllWebViews 903{ 904 DOMWindow::dispatchAllPendingUnloadEvents(); 905 906 // This will close the WebViews in a random order. Change this if close order is important. 907 NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator]; 908 while (WebView *webView = [enumerator nextObject]) 909 [webView close]; 910} 911 912+ (BOOL)canShowFile:(NSString *)path 913{ 914 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]]; 915} 916 917+ (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type 918{ 919 return WKGetPreferredExtensionForMIMEType(type); 920} 921 922- (BOOL)_isClosed 923{ 924 return !_private || _private->closed; 925} 926 927- (void)_closePluginDatabases 928{ 929 pluginDatabaseClientCount--; 930 931 // Close both sets of plug-in databases because plug-ins need an opportunity to clean up files, etc. 932 933 // Unload the WebView local plug-in database. 934 if (_private->pluginDatabase) { 935 [_private->pluginDatabase destroyAllPluginInstanceViews]; 936 [_private->pluginDatabase close]; 937 [_private->pluginDatabase release]; 938 _private->pluginDatabase = nil; 939 } 940 941 // Keep the global plug-in database active until the app terminates to avoid having to reload plug-in bundles. 942 if (!pluginDatabaseClientCount && applicationIsTerminating) 943 [WebPluginDatabase closeSharedDatabase]; 944} 945 946- (void)_closeWithFastTeardown 947{ 948#ifndef NDEBUG 949 WTF::RefCountedLeakCounter::suppressMessages("At least one WebView was closed with fast teardown."); 950#endif 951 952 _private->closed = YES; 953 954 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 955 [[NSNotificationCenter defaultCenter] removeObserver:self]; 956 957 [self _closePluginDatabases]; 958} 959 960static bool fastDocumentTeardownEnabled() 961{ 962#ifdef NDEBUG 963 static bool enabled = ![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; 964#else 965 static bool initialized = false; 966 static bool enabled = false; 967 if (!initialized) { 968 // This allows debug builds to default to not have fast teardown, so leak checking still works. 969 // But still allow the WebKitEnableFullDocumentTeardown default to override it if present. 970 NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; 971 if (setting) 972 enabled = ![setting boolValue]; 973 initialized = true; 974 } 975#endif 976 return enabled; 977} 978 979// _close is here only for backward compatibility; clients and subclasses should use 980// public method -close instead. 981- (void)_close 982{ 983 if (!_private || _private->closed) 984 return; 985 986 if (lastMouseoverView == self) 987 lastMouseoverView = nil; 988 989#ifndef NDEBUG 990 WTF::RefCountedLeakCounter::cancelMessageSuppression(webViewIsOpen); 991#endif 992 993 // To quit the apps fast we skip document teardown, except plugins 994 // need to be destroyed and unloaded. 995 if (applicationIsTerminating && fastDocumentTeardownEnabled()) { 996 [self _closeWithFastTeardown]; 997 return; 998 } 999 1000 if (Frame* mainFrame = [self _mainCoreFrame]) 1001 mainFrame->loader()->detachFromParent(); 1002 1003 [self _removeFromAllWebViewsSet]; 1004 [self setHostWindow:nil]; 1005 1006 [self setDownloadDelegate:nil]; 1007 [self setEditingDelegate:nil]; 1008 [self setFrameLoadDelegate:nil]; 1009 [self setPolicyDelegate:nil]; 1010 [self setResourceLoadDelegate:nil]; 1011 [self setScriptDebugDelegate:nil]; 1012 [self setUIDelegate:nil]; 1013 1014 [_private->inspector webViewClosed]; 1015 1016 // setHostWindow:nil must be called before this value is set (see 5408186) 1017 _private->closed = YES; 1018 1019 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint. 1020 [self removeDragCaret]; 1021 1022 // Deleteing the WebCore::Page will clear the page cache so we call destroy on 1023 // all the plug-ins in the page cache to break any retain cycles. 1024 // See comment in HistoryItem::releaseAllPendingPageCaches() for more information. 1025 delete _private->page; 1026 _private->page = 0; 1027 1028 if (_private->hasSpellCheckerDocumentTag) { 1029 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag]; 1030 _private->hasSpellCheckerDocumentTag = NO; 1031 } 1032 1033#if USE(ACCELERATED_COMPOSITING) 1034 [self _clearLayerSyncLoopObserver]; 1035#endif 1036 1037 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 1038 [[NSNotificationCenter defaultCenter] removeObserver:self]; 1039 1040 [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]]; 1041 1042 WebPreferences *preferences = _private->preferences; 1043 _private->preferences = nil; 1044 [preferences didRemoveFromWebView]; 1045 [preferences release]; 1046 1047 [self _closePluginDatabases]; 1048 1049#ifndef NDEBUG 1050 // Need this to make leak messages accurate. 1051 if (applicationIsTerminating) { 1052 gcController().garbageCollectNow(); 1053 [WebCache setDisabled:YES]; 1054 } 1055#endif 1056} 1057 1058// Indicates if the WebView is in the midst of a user gesture. 1059- (BOOL)_isProcessingUserGesture 1060{ 1061 WebFrame *frame = [self mainFrame]; 1062 return core(frame)->loader()->isProcessingUserGesture(); 1063} 1064 1065+ (NSString *)_MIMETypeForFile:(NSString *)path 1066{ 1067 NSString *extension = [path pathExtension]; 1068 NSString *MIMEType = nil; 1069 1070 // Get the MIME type from the extension. 1071 if ([extension length] != 0) { 1072 MIMEType = WKGetMIMETypeForExtension(extension); 1073 } 1074 1075 // If we can't get a known MIME type from the extension, sniff. 1076 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) { 1077 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; 1078 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH]; 1079 [handle closeFile]; 1080 if ([data length] != 0) { 1081 MIMEType = [data _webkit_guessedMIMEType]; 1082 } 1083 if ([MIMEType length] == 0) { 1084 MIMEType = @"application/octet-stream"; 1085 } 1086 } 1087 1088 return MIMEType; 1089} 1090 1091- (WebDownload *)_downloadURL:(NSURL *)URL 1092{ 1093 ASSERT(URL); 1094 1095 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL]; 1096 WebDownload *download = [WebDownload _downloadWithRequest:request 1097 delegate:_private->downloadDelegate 1098 directory:nil]; 1099 [request release]; 1100 1101 return download; 1102} 1103 1104- (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request 1105{ 1106 NSDictionary *features = [[NSDictionary alloc] init]; 1107 WebView *newWindowWebView = [[self _UIDelegateForwarder] webView:self 1108 createWebViewWithRequest:nil 1109 windowFeatures:features]; 1110 [features release]; 1111 if (!newWindowWebView) 1112 return nil; 1113 1114 CallUIDelegate(newWindowWebView, @selector(webViewShow:)); 1115 return newWindowWebView; 1116} 1117 1118- (WebInspector *)inspector 1119{ 1120 if (!_private->inspector) 1121 _private->inspector = [[WebInspector alloc] initWithWebView:self]; 1122 return _private->inspector; 1123} 1124 1125- (WebCore::Page*)page 1126{ 1127 return _private->page; 1128} 1129 1130- (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items 1131{ 1132 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate] webView:self contextMenuItemsForElement:element defaultMenuItems:items]; 1133 1134 NSArray *menuItems = CallUIDelegate(self, @selector(webView:contextMenuItemsForElement:defaultMenuItems:), element, defaultMenuItems); 1135 if (!menuItems) 1136 return nil; 1137 1138 unsigned count = [menuItems count]; 1139 if (!count) 1140 return nil; 1141 1142 NSMenu *menu = [[NSMenu alloc] init]; 1143 for (unsigned i = 0; i < count; i++) 1144 [menu addItem:[menuItems objectAtIndex:i]]; 1145 1146 return [menu autorelease]; 1147} 1148 1149- (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(NSUInteger)modifierFlags 1150{ 1151 // We originally intended to call this delegate method sometimes with a nil dictionary, but due to 1152 // a bug dating back to WebKit 1.0 this delegate was never called with nil! Unfortunately we can't 1153 // start calling this with nil since it will break Adobe Help Viewer, and possibly other clients. 1154 if (!dictionary) 1155 return; 1156 CallUIDelegate(self, @selector(webView:mouseDidMoveOverElement:modifierFlags:), dictionary, modifierFlags); 1157} 1158 1159- (void)_loadBackForwardListFromOtherView:(WebView *)otherView 1160{ 1161 if (!_private->page) 1162 return; 1163 1164 if (!otherView->_private->page) 1165 return; 1166 1167 // It turns out the right combination of behavior is done with the back/forward load 1168 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items 1169 // in the back forward list, and go to the current one. 1170 1171 BackForwardList* backForwardList = _private->page->backForwardList(); 1172 ASSERT(!backForwardList->currentItem()); // destination list should be empty 1173 1174 BackForwardList* otherBackForwardList = otherView->_private->page->backForwardList(); 1175 if (!otherBackForwardList->currentItem()) 1176 return; // empty back forward list, bail 1177 1178 HistoryItem* newItemToGoTo = 0; 1179 1180 int lastItemIndex = otherBackForwardList->forwardListCount(); 1181 for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) { 1182 if (i == 0) { 1183 // If this item is showing , save away its current scroll and form state, 1184 // since that might have changed since loading and it is normally not saved 1185 // until we leave that page. 1186 otherView->_private->page->mainFrame()->loader()->saveDocumentAndScrollState(); 1187 } 1188 RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy(); 1189 if (i == 0) 1190 newItemToGoTo = newItem.get(); 1191 backForwardList->addItem(newItem.release()); 1192 } 1193 1194 ASSERT(newItemToGoTo); 1195 _private->page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward); 1196} 1197 1198- (void)_setFormDelegate: (id<WebFormDelegate>)delegate 1199{ 1200 _private->formDelegate = delegate; 1201} 1202 1203- (id<WebFormDelegate>)_formDelegate 1204{ 1205 return _private->formDelegate; 1206} 1207 1208- (BOOL)_needsAdobeFrameReloadingQuirk 1209{ 1210 static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0) 1211 || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0) 1212 || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0) 1213 || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0) 1214 || WKAppVersionCheckLessThan(@"com.adobe.Contribute", -1, 4.2) 1215 || WKAppVersionCheckLessThan(@"com.adobe.dreamweaver-9.0", -1, 9.1) 1216 || WKAppVersionCheckLessThan(@"com.macromedia.fireworks", -1, 9.1) 1217 || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1) 1218 || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1) 1219 || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2); 1220 1221 return needsQuirk; 1222} 1223 1224- (BOOL)_needsLinkElementTextCSSQuirk 1225{ 1226 static BOOL needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LINK_ELEMENT_TEXT_CSS_QUIRK) 1227 && WKAppVersionCheckLessThan(@"com.e-frontier.shade10", -1, 10.6); 1228 return needsQuirk; 1229} 1230 1231- (BOOL)_needsKeyboardEventDisambiguationQuirks 1232{ 1233 static BOOL needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) && !applicationIsSafari(); 1234 return needsQuirks; 1235} 1236 1237- (BOOL)_needsFrameLoadDelegateRetainQuirk 1238{ 1239 static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.equinux.iSale5", -1, 5.6); 1240 return needsQuirk; 1241} 1242 1243- (void)_preferencesChangedNotification:(NSNotification *)notification 1244{ 1245 WebPreferences *preferences = (WebPreferences *)[notification object]; 1246 ASSERT(preferences == [self preferences]); 1247 1248 if (!_private->userAgentOverridden) 1249 _private->userAgent = String(); 1250 1251 // Cache this value so we don't have to read NSUserDefaults on each page load 1252 _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing]; 1253 1254 // Update corresponding WebCore Settings object. 1255 if (!_private->page) 1256 return; 1257 1258 Settings* settings = _private->page->settings(); 1259 1260 settings->setCursiveFontFamily([preferences cursiveFontFamily]); 1261 settings->setDefaultFixedFontSize([preferences defaultFixedFontSize]); 1262 settings->setDefaultFontSize([preferences defaultFontSize]); 1263 settings->setDefaultTextEncodingName([preferences defaultTextEncodingName]); 1264 settings->setUsesEncodingDetector([preferences usesEncodingDetector]); 1265 settings->setFantasyFontFamily([preferences fantasyFontFamily]); 1266 settings->setFixedFontFamily([preferences fixedFontFamily]); 1267 settings->setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]); 1268 settings->setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]); 1269 settings->setLocalStorageDatabasePath([preferences _localStorageDatabasePath]); 1270 settings->setJavaEnabled([preferences isJavaEnabled]); 1271 settings->setJavaScriptEnabled([preferences isJavaScriptEnabled]); 1272 settings->setWebSecurityEnabled([preferences isWebSecurityEnabled]); 1273 settings->setAllowUniversalAccessFromFileURLs([preferences allowUniversalAccessFromFileURLs]); 1274 settings->setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]); 1275 settings->setMinimumFontSize([preferences minimumFontSize]); 1276 settings->setMinimumLogicalFontSize([preferences minimumLogicalFontSize]); 1277 settings->setPluginsEnabled([preferences arePlugInsEnabled]); 1278 settings->setDatabasesEnabled([preferences databasesEnabled]); 1279 settings->setLocalStorageEnabled([preferences localStorageEnabled]); 1280 settings->setPrivateBrowsingEnabled([preferences privateBrowsingEnabled]); 1281 settings->setSansSerifFontFamily([preferences sansSerifFontFamily]); 1282 settings->setSerifFontFamily([preferences serifFontFamily]); 1283 settings->setStandardFontFamily([preferences standardFontFamily]); 1284 settings->setLoadsImagesAutomatically([preferences loadsImagesAutomatically]); 1285 settings->setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]); 1286 settings->setTextAreasAreResizable([preferences textAreasAreResizable]); 1287 settings->setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]); 1288 settings->setEditableLinkBehavior(core([preferences editableLinkBehavior])); 1289 settings->setTextDirectionSubmenuInclusionBehavior(core([preferences textDirectionSubmenuInclusionBehavior])); 1290 settings->setDOMPasteAllowed([preferences isDOMPasteAllowed]); 1291 settings->setUsesPageCache([self usesPageCache]); 1292 settings->setShowsURLsInToolTips([preferences showsURLsInToolTips]); 1293 settings->setDeveloperExtrasEnabled([preferences developerExtrasEnabled]); 1294 settings->setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]); 1295 settings->setApplicationChromeMode([preferences applicationChromeModeEnabled]); 1296 if ([preferences userStyleSheetEnabled]) { 1297 NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString]; 1298 settings->setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]); 1299 } else 1300 settings->setUserStyleSheetLocation([NSURL URLWithString:@""]); 1301 settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]); 1302 settings->setTreatsAnyTextCSSLinkAsStylesheet([self _needsLinkElementTextCSSQuirk]); 1303 settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]); 1304 settings->setNeedsLeopardMailQuirks(runningLeopardMail()); 1305 settings->setNeedsTigerMailQuirks(runningTigerMail()); 1306 settings->setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing); 1307 settings->setWebArchiveDebugModeEnabled([preferences webArchiveDebugModeEnabled]); 1308 settings->setLocalFileContentSniffingEnabled([preferences localFileContentSniffingEnabled]); 1309 settings->setOfflineWebApplicationCacheEnabled([preferences offlineWebApplicationCacheEnabled]); 1310 settings->setZoomsTextOnly([preferences zoomsTextOnly]); 1311 settings->setXSSAuditorEnabled([preferences isXSSAuditorEnabled]); 1312 settings->setEnforceCSSMIMETypeInStrictMode(!WKAppVersionCheckLessThan(@"com.apple.iWeb", -1, 2.1)); 1313 settings->setAcceleratedCompositingEnabled([preferences acceleratedCompositingEnabled]); 1314} 1315 1316static inline IMP getMethod(id o, SEL s) 1317{ 1318 return [o respondsToSelector:s] ? [o methodForSelector:s] : 0; 1319} 1320 1321- (void)_cacheResourceLoadDelegateImplementations 1322{ 1323 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations; 1324 id delegate = _private->resourceProgressDelegate; 1325 1326 if (!delegate) { 1327 bzero(cache, sizeof(WebResourceDelegateImplementationCache)); 1328 return; 1329 } 1330 1331 cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)); 1332 cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:)); 1333 cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:)); 1334 cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:)); 1335 cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)); 1336 cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:)); 1337 cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:)); 1338 cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:)); 1339 cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:)); 1340 cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:)); 1341 cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)); 1342 cache->shouldUseCredentialStorageFunc = getMethod(delegate, @selector(webView:resource:shouldUseCredentialStorageForDataSource:)); 1343} 1344 1345- (void)_cacheFrameLoadDelegateImplementations 1346{ 1347 WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations; 1348 id delegate = _private->frameLoadDelegate; 1349 1350 if (!delegate) { 1351 bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache)); 1352 return; 1353 } 1354 1355 cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:)); 1356 cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:)); 1357 cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:)); 1358 cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:)); 1359 cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:)); 1360 cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:)); 1361 cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:)); 1362 cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:)); 1363 cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:)); 1364 cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:)); 1365 cache->didFirstVisuallyNonEmptyLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:)); 1366 cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:)); 1367 cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:)); 1368 cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:)); 1369 cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:)); 1370 cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:)); 1371 cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:)); 1372 cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:)); 1373 cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:)); 1374} 1375 1376- (void)_cacheScriptDebugDelegateImplementations 1377{ 1378 WebScriptDebugDelegateImplementationCache *cache = &_private->scriptDebugDelegateImplementations; 1379 id delegate = _private->scriptDebugDelegate; 1380 1381 if (!delegate) { 1382 bzero(cache, sizeof(WebScriptDebugDelegateImplementationCache)); 1383 return; 1384 } 1385 1386 cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:)); 1387 if (cache->didParseSourceFunc) 1388 cache->didParseSourceExpectsBaseLineNumber = YES; 1389 else 1390 cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:)); 1391 1392 cache->failedToParseSourceFunc = getMethod(delegate, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:)); 1393 cache->didEnterCallFrameFunc = getMethod(delegate, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:)); 1394 cache->willExecuteStatementFunc = getMethod(delegate, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:)); 1395 cache->willLeaveCallFrameFunc = getMethod(delegate, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:)); 1396 cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:)); 1397} 1398 1399- (id)_policyDelegateForwarder 1400{ 1401 if (!_private->policyDelegateForwarder) 1402 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate] catchExceptions:_private->catchesDelegateExceptions]; 1403 return _private->policyDelegateForwarder; 1404} 1405 1406- (id)_UIDelegateForwarder 1407{ 1408 if (!_private->UIDelegateForwarder) 1409 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate] catchExceptions:_private->catchesDelegateExceptions]; 1410 return _private->UIDelegateForwarder; 1411} 1412 1413- (id)_editingDelegateForwarder 1414{ 1415 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in. 1416 // Not sure if that is a bug or not. 1417 if (!_private) 1418 return nil; 1419 1420 if (!_private->editingDelegateForwarder) 1421 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate] catchExceptions:_private->catchesDelegateExceptions]; 1422 return _private->editingDelegateForwarder; 1423} 1424 1425- (void)_closeWindow 1426{ 1427 [[self _UIDelegateForwarder] webViewClose:self]; 1428} 1429 1430+ (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType 1431{ 1432 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType]; 1433 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType]; 1434 1435 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) 1436 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner 1437 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness 1438 MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType); 1439} 1440 1441+ (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme 1442{ 1443 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme]; 1444 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType]; 1445 1446 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) 1447 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner 1448 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness 1449 if ([viewClass class] == [WebHTMLView class]) 1450 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType); 1451 1452 // This is used to make _representationExistsForURLScheme faster. 1453 // Without this set, we'd have to create the MIME type each time. 1454 if (schemesWithRepresentationsSet == nil) { 1455 schemesWithRepresentationsSet = [[NSMutableSet alloc] init]; 1456 } 1457 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]]; 1458} 1459 1460+ (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme 1461{ 1462 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]]; 1463} 1464 1465+ (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme 1466{ 1467 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]]; 1468} 1469 1470+ (BOOL)_canHandleRequest:(NSURLRequest *)request forMainFrame:(BOOL)forMainFrame 1471{ 1472 // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed. 1473 if (!request) 1474 return NO; 1475 1476 if ([NSURLConnection canHandleRequest:request]) 1477 return YES; 1478 1479 NSString *scheme = [[request URL] scheme]; 1480 1481 // Representations for URL schemes work at the top level. 1482 if (forMainFrame && [self _representationExistsForURLScheme:scheme]) 1483 return YES; 1484 1485 return [scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"]; 1486} 1487 1488+ (BOOL)_canHandleRequest:(NSURLRequest *)request 1489{ 1490 return [self _canHandleRequest:request forMainFrame:YES]; 1491} 1492 1493+ (NSString *)_decodeData:(NSData *)data 1494{ 1495 HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet 1496 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/html"); // bookmark files are HTML 1497 String result = decoder->decode(static_cast<const char*>([data bytes]), [data length]); 1498 result += decoder->flush(); 1499 return result; 1500} 1501 1502- (void)_pushPerformingProgrammaticFocus 1503{ 1504 _private->programmaticFocusCount++; 1505} 1506 1507- (void)_popPerformingProgrammaticFocus 1508{ 1509 _private->programmaticFocusCount--; 1510} 1511 1512- (BOOL)_isPerformingProgrammaticFocus 1513{ 1514 return _private->programmaticFocusCount != 0; 1515} 1516 1517- (void)_didChangeValueForKey: (NSString *)key 1518{ 1519 LOG (Bindings, "calling didChangeValueForKey: %@", key); 1520 [self didChangeValueForKey: key]; 1521} 1522 1523- (void)_willChangeValueForKey: (NSString *)key 1524{ 1525 LOG (Bindings, "calling willChangeValueForKey: %@", key); 1526 [self willChangeValueForKey: key]; 1527} 1528 1529+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { 1530 static NSSet *manualNotifyKeys = nil; 1531 if (!manualNotifyKeys) 1532 manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, 1533 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, 1534#if USE(ACCELERATED_COMPOSITING) 1535 UsingAcceleratedCompositingProperty, // used by DRT 1536#endif 1537 nil]; 1538 if ([manualNotifyKeys containsObject:key]) 1539 return NO; 1540 return YES; 1541} 1542 1543- (NSArray *)_declaredKeys { 1544 static NSArray *declaredKeys = nil; 1545 if (!declaredKeys) 1546 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, 1547 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil]; 1548 return declaredKeys; 1549} 1550 1551- (void)setObservationInfo:(void *)info 1552{ 1553 _private->observationInfo = info; 1554} 1555 1556- (void *)observationInfo 1557{ 1558 return _private->observationInfo; 1559} 1560 1561- (void)_willChangeBackForwardKeys 1562{ 1563 [self _willChangeValueForKey: _WebCanGoBackKey]; 1564 [self _willChangeValueForKey: _WebCanGoForwardKey]; 1565} 1566 1567- (void)_didChangeBackForwardKeys 1568{ 1569 [self _didChangeValueForKey: _WebCanGoBackKey]; 1570 [self _didChangeValueForKey: _WebCanGoForwardKey]; 1571} 1572 1573- (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame 1574{ 1575 [self _willChangeBackForwardKeys]; 1576 if (frame == [self mainFrame]){ 1577 // Force an observer update by sending a will/did. 1578 [self _willChangeValueForKey: _WebIsLoadingKey]; 1579 [self _didChangeValueForKey: _WebIsLoadingKey]; 1580 1581 [self _willChangeValueForKey: _WebMainFrameURLKey]; 1582 } 1583 1584 [NSApp setWindowsNeedUpdate:YES]; 1585} 1586 1587- (void)_didCommitLoadForFrame:(WebFrame *)frame 1588{ 1589 if (frame == [self mainFrame]) 1590 [self _didChangeValueForKey: _WebMainFrameURLKey]; 1591 [NSApp setWindowsNeedUpdate:YES]; 1592} 1593 1594- (void)_didFinishLoadForFrame:(WebFrame *)frame 1595{ 1596 [self _didChangeBackForwardKeys]; 1597 if (frame == [self mainFrame]){ 1598 // Force an observer update by sending a will/did. 1599 [self _willChangeValueForKey: _WebIsLoadingKey]; 1600 [self _didChangeValueForKey: _WebIsLoadingKey]; 1601 } 1602 [NSApp setWindowsNeedUpdate:YES]; 1603} 1604 1605- (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 1606{ 1607 [self _didChangeBackForwardKeys]; 1608 if (frame == [self mainFrame]){ 1609 // Force an observer update by sending a will/did. 1610 [self _willChangeValueForKey: _WebIsLoadingKey]; 1611 [self _didChangeValueForKey: _WebIsLoadingKey]; 1612 } 1613 [NSApp setWindowsNeedUpdate:YES]; 1614} 1615 1616- (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 1617{ 1618 [self _didChangeBackForwardKeys]; 1619 if (frame == [self mainFrame]){ 1620 // Force an observer update by sending a will/did. 1621 [self _willChangeValueForKey: _WebIsLoadingKey]; 1622 [self _didChangeValueForKey: _WebIsLoadingKey]; 1623 1624 [self _didChangeValueForKey: _WebMainFrameURLKey]; 1625 } 1626 [NSApp setWindowsNeedUpdate:YES]; 1627} 1628 1629- (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL 1630{ 1631 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL]; 1632 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]]; 1633 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 1634 [request release]; 1635 return cachedResponse; 1636} 1637 1638- (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 1639{ 1640 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey]; 1641 DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey]; 1642 [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey]) 1643 element:domElement 1644 URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey] 1645 title:[element objectForKey:WebElementImageAltStringKey] 1646 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive] 1647 types:types 1648 source:nil]; 1649} 1650 1651- (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 1652{ 1653 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey] 1654 andTitle:[element objectForKey:WebElementLinkLabelKey] 1655 types:types]; 1656} 1657 1658- (void)_setInitiatedDrag:(BOOL)initiatedDrag 1659{ 1660 if (!_private->page) 1661 return; 1662 _private->page->dragController()->setDidInitiateDrag(initiatedDrag); 1663} 1664 1665#if ENABLE(DASHBOARD_SUPPORT) 1666 1667#define DASHBOARD_CONTROL_LABEL @"control" 1668 1669- (void)_addControlRect:(NSRect)bounds clip:(NSRect)clip fromView:(NSView *)view toDashboardRegions:(NSMutableDictionary *)regions 1670{ 1671 NSRect adjustedBounds = bounds; 1672 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:view]; 1673 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y; 1674 adjustedBounds.size = bounds.size; 1675 1676 NSRect adjustedClip; 1677 adjustedClip.origin = [self convertPoint:clip.origin fromView:view]; 1678 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y; 1679 adjustedClip.size = clip.size; 1680 1681 WebDashboardRegion *region = [[WebDashboardRegion alloc] initWithRect:adjustedBounds 1682 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle]; 1683 NSMutableArray *scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL]; 1684 if (!scrollerRegions) { 1685 scrollerRegions = [[NSMutableArray alloc] init]; 1686 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL]; 1687 [scrollerRegions release]; 1688 } 1689 [scrollerRegions addObject:region]; 1690 [region release]; 1691} 1692 1693- (void)_addScrollerDashboardRegionsForFrameView:(FrameView*)frameView dashboardRegions:(NSMutableDictionary *)regions 1694{ 1695 NSView *documentView = [[kit(frameView->frame()) frameView] documentView]; 1696 1697 const HashSet<RefPtr<Widget> >* children = frameView->children(); 1698 HashSet<RefPtr<Widget> >::const_iterator end = children->end(); 1699 for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { 1700 Widget* widget = (*it).get(); 1701 if (widget->isFrameView()) { 1702 [self _addScrollerDashboardRegionsForFrameView:static_cast<FrameView*>(widget) dashboardRegions:regions]; 1703 continue; 1704 } 1705 1706 if (!widget->isScrollbar()) 1707 continue; 1708 1709 // FIXME: This should really pass an appropriate clip, but our first try got it wrong, and 1710 // it's not common to need this to be correct in Dashboard widgets. 1711 NSRect bounds = widget->frameRect(); 1712 [self _addControlRect:bounds clip:bounds fromView:documentView toDashboardRegions:regions]; 1713 } 1714} 1715 1716- (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views 1717{ 1718 // Add scroller regions for NSScroller and WebCore scrollbars 1719 NSUInteger count = [views count]; 1720 for (NSUInteger i = 0; i < count; i++) { 1721 NSView *view = [views objectAtIndex:i]; 1722 1723 if ([view isKindOfClass:[WebHTMLView class]]) { 1724 if (Frame* coreFrame = core([(WebHTMLView*)view _frame])) { 1725 if (FrameView* coreView = coreFrame->view()) 1726 [self _addScrollerDashboardRegionsForFrameView:coreView dashboardRegions:regions]; 1727 } 1728 } else if ([view isKindOfClass:[NSScroller class]]) { 1729 // AppKit places absent scrollers at -100,-100 1730 if ([view frame].origin.y < 0) 1731 continue; 1732 [self _addControlRect:[view bounds] clip:[view visibleRect] fromView:view toDashboardRegions:regions]; 1733 } 1734 [self _addScrollerDashboardRegions:regions from:[view subviews]]; 1735 } 1736} 1737 1738- (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions 1739{ 1740 [self _addScrollerDashboardRegions:regions from:[self subviews]]; 1741} 1742 1743- (NSDictionary *)_dashboardRegions 1744{ 1745 // Only return regions from main frame. 1746 Frame* mainFrame = [self _mainCoreFrame]; 1747 if (!mainFrame) 1748 return nil; 1749 NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary(); 1750 [self _addScrollerDashboardRegions:regions]; 1751 return regions; 1752} 1753 1754- (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag 1755{ 1756 // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement 1757 // specific support for the backward compatibility mode flag. 1758 if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page) 1759 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(true); 1760 1761 switch (behavior) { 1762 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: { 1763 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag; 1764 break; 1765 } 1766 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: { 1767 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag; 1768 break; 1769 } 1770 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: { 1771 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag; 1772 break; 1773 } 1774 case WebDashboardBehaviorAllowWheelScrolling: { 1775 _private->dashboardBehaviorAllowWheelScrolling = flag; 1776 break; 1777 } 1778 case WebDashboardBehaviorUseBackwardCompatibilityMode: { 1779 if (_private->page) 1780 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(flag); 1781 break; 1782 } 1783 } 1784} 1785 1786- (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior 1787{ 1788 switch (behavior) { 1789 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: { 1790 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows; 1791 } 1792 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: { 1793 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns; 1794 } 1795 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: { 1796 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse; 1797 } 1798 case WebDashboardBehaviorAllowWheelScrolling: { 1799 return _private->dashboardBehaviorAllowWheelScrolling; 1800 } 1801 case WebDashboardBehaviorUseBackwardCompatibilityMode: { 1802 return _private->page && _private->page->settings()->usesDashboardBackwardCompatibilityMode(); 1803 } 1804 } 1805 return NO; 1806} 1807 1808#endif /* ENABLE(DASHBOARD_SUPPORT) */ 1809 1810+ (void)_setShouldUseFontSmoothing:(BOOL)f 1811{ 1812 Font::setShouldUseSmoothing(f); 1813} 1814 1815+ (BOOL)_shouldUseFontSmoothing 1816{ 1817 return Font::shouldUseSmoothing(); 1818} 1819 1820+ (void)_setUsesTestModeFocusRingColor:(BOOL)f 1821{ 1822 setUsesTestModeFocusRingColor(f); 1823} 1824 1825+ (BOOL)_usesTestModeFocusRingColor 1826{ 1827 return usesTestModeFocusRingColor(); 1828} 1829 1830- (void)setAlwaysShowVerticalScroller:(BOOL)flag 1831{ 1832 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1833 if (flag) { 1834 [scrollview setVerticalScrollingMode:ScrollbarAlwaysOn andLock:YES]; 1835 } else { 1836 [scrollview setVerticalScrollingModeLocked:NO]; 1837 [scrollview setVerticalScrollingMode:ScrollbarAuto andLock:NO]; 1838 } 1839} 1840 1841- (BOOL)alwaysShowVerticalScroller 1842{ 1843 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1844 return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == ScrollbarAlwaysOn; 1845} 1846 1847- (void)setAlwaysShowHorizontalScroller:(BOOL)flag 1848{ 1849 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1850 if (flag) { 1851 [scrollview setHorizontalScrollingMode:ScrollbarAlwaysOn andLock:YES]; 1852 } else { 1853 [scrollview setHorizontalScrollingModeLocked:NO]; 1854 [scrollview setHorizontalScrollingMode:ScrollbarAuto andLock:NO]; 1855 } 1856} 1857 1858- (void)setProhibitsMainFrameScrolling:(BOOL)prohibits 1859{ 1860 if (Frame* mainFrame = [self _mainCoreFrame]) 1861 mainFrame->view()->setProhibitsScrolling(prohibits); 1862} 1863 1864- (BOOL)alwaysShowHorizontalScroller 1865{ 1866 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1867 return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == ScrollbarAlwaysOn; 1868} 1869 1870- (void)_setInViewSourceMode:(BOOL)flag 1871{ 1872 if (Frame* mainFrame = [self _mainCoreFrame]) 1873 mainFrame->setInViewSourceMode(flag); 1874} 1875 1876- (BOOL)_inViewSourceMode 1877{ 1878 Frame* mainFrame = [self _mainCoreFrame]; 1879 return mainFrame && mainFrame->inViewSourceMode(); 1880} 1881 1882- (void)_setUseFastImageScalingMode:(BOOL)flag 1883{ 1884 if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) { 1885 _private->page->setInLowQualityImageInterpolationMode(flag); 1886 [self setNeedsDisplay:YES]; 1887 } 1888} 1889 1890- (BOOL)_inFastImageScalingMode 1891{ 1892 if (_private->page) 1893 return _private->page->inLowQualityImageInterpolationMode(); 1894 return NO; 1895} 1896 1897- (BOOL)_cookieEnabled 1898{ 1899 if (_private->page) 1900 return _private->page->cookieEnabled(); 1901 return YES; 1902} 1903 1904- (void)_setCookieEnabled:(BOOL)enable 1905{ 1906 if (_private->page) 1907 _private->page->setCookieEnabled(enable); 1908} 1909 1910- (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths 1911{ 1912 if (!_private->pluginDatabase) 1913 _private->pluginDatabase = [[WebPluginDatabase alloc] init]; 1914 1915 [_private->pluginDatabase setPlugInPaths:newPaths]; 1916 [_private->pluginDatabase refresh]; 1917} 1918 1919- (void)_attachScriptDebuggerToAllFrames 1920{ 1921 for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) 1922 [kit(frame) _attachScriptDebugger]; 1923} 1924 1925- (void)_detachScriptDebuggerFromAllFrames 1926{ 1927 for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) 1928 [kit(frame) _detachScriptDebugger]; 1929} 1930 1931- (void)setBackgroundColor:(NSColor *)backgroundColor 1932{ 1933 if ([_private->backgroundColor isEqual:backgroundColor]) 1934 return; 1935 1936 id old = _private->backgroundColor; 1937 _private->backgroundColor = [backgroundColor retain]; 1938 [old release]; 1939 1940 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; 1941} 1942 1943- (NSColor *)backgroundColor 1944{ 1945 return _private->backgroundColor; 1946} 1947 1948- (BOOL)defersCallbacks 1949{ 1950 if (!_private->page) 1951 return NO; 1952 return _private->page->defersLoading(); 1953} 1954 1955- (void)setDefersCallbacks:(BOOL)defer 1956{ 1957 if (!_private->page) 1958 return; 1959 return _private->page->setDefersLoading(defer); 1960} 1961 1962// For backwards compatibility with the WebBackForwardList API, we honor both 1963// a per-WebView and a per-preferences setting for whether to use the page cache. 1964 1965- (BOOL)usesPageCache 1966{ 1967 return _private->usesPageCache && [[self preferences] usesPageCache]; 1968} 1969 1970- (void)setUsesPageCache:(BOOL)usesPageCache 1971{ 1972 _private->usesPageCache = usesPageCache; 1973 1974 // Post a notification so the WebCore settings update. 1975 [[self preferences] _postPreferencesChangesNotification]; 1976} 1977 1978- (WebHistoryItem *)_globalHistoryItem 1979{ 1980 if (!_private->page) 1981 return nil; 1982 return kit(_private->page->globalHistoryItem()); 1983} 1984 1985- (WebTextIterator *)textIteratorForRect:(NSRect)rect 1986{ 1987 IntPoint rectStart(rect.origin.x, rect.origin.y); 1988 IntPoint rectEnd(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); 1989 1990 Frame* coreFrame = [self _mainCoreFrame]; 1991 if (!coreFrame) 1992 return nil; 1993 1994 VisibleSelection selectionInsideRect(coreFrame->visiblePositionForPoint(rectStart), coreFrame->visiblePositionForPoint(rectEnd)); 1995 1996 return [[[WebTextIterator alloc] initWithRange:kit(selectionInsideRect.toNormalizedRange().get())] autorelease]; 1997} 1998 1999- (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource 2000{ 2001 NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window]; 2002 [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window]; 2003} 2004 2005- (void)_clearUndoRedoOperations 2006{ 2007 if (!_private->page) 2008 return; 2009 _private->page->clearUndoRedoOperations(); 2010} 2011 2012- (void)_setCatchesDelegateExceptions:(BOOL)f 2013{ 2014 _private->catchesDelegateExceptions = f; 2015} 2016 2017- (BOOL)_catchesDelegateExceptions 2018{ 2019 return _private->catchesDelegateExceptions; 2020} 2021 2022- (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value 2023{ 2024 Frame* coreFrame = [self _mainCoreFrame]; 2025 if (!coreFrame) 2026 return; 2027 coreFrame->editor()->command(name).execute(value); 2028} 2029 2030- (void)_setCustomHTMLTokenizerTimeDelay:(double)timeDelay 2031{ 2032 if (!_private->page) 2033 return; 2034 return _private->page->setCustomHTMLTokenizerTimeDelay(timeDelay); 2035} 2036 2037- (void)_setCustomHTMLTokenizerChunkSize:(int)chunkSize 2038{ 2039 if (!_private->page) 2040 return; 2041 return _private->page->setCustomHTMLTokenizerChunkSize(chunkSize); 2042} 2043 2044- (void)_clearMainFrameName 2045{ 2046 _private->page->mainFrame()->tree()->clearName(); 2047} 2048 2049- (void)setSelectTrailingWhitespaceEnabled:(BOOL)flag 2050{ 2051 _private->selectTrailingWhitespaceEnabled = flag; 2052 if (flag) 2053 [self setSmartInsertDeleteEnabled:false]; 2054} 2055 2056- (BOOL)isSelectTrailingWhitespaceEnabled 2057{ 2058 return _private->selectTrailingWhitespaceEnabled; 2059} 2060 2061- (void)setMemoryCacheDelegateCallsEnabled:(BOOL)enabled 2062{ 2063 _private->page->setMemoryCacheClientCallsEnabled(enabled); 2064} 2065 2066- (BOOL)areMemoryCacheDelegateCallsEnabled 2067{ 2068 return _private->page->areMemoryCacheClientCallsEnabled(); 2069} 2070 2071- (void)_setJavaScriptURLsAreAllowed:(BOOL)areAllowed 2072{ 2073 _private->page->setJavaScriptURLsAreAllowed(areAllowed); 2074} 2075 2076+ (NSCursor *)_pointingHandCursor 2077{ 2078 return handCursor().impl(); 2079} 2080 2081- (BOOL)_isUsingAcceleratedCompositing 2082{ 2083#if USE(ACCELERATED_COMPOSITING) 2084 return _private->acceleratedFramesCount > 0; 2085#else 2086 return NO; 2087#endif 2088} 2089 2090- (NSPasteboard *)_insertionPasteboard 2091{ 2092 return _private ? _private->insertionPasteboard : nil; 2093} 2094 2095 2096- (void)_updateActiveState 2097{ 2098 if (_private && _private->page) 2099 _private->page->focusController()->setActive([[self window] isKeyWindow]); 2100} 2101 2102@end 2103 2104@implementation _WebSafeForwarder 2105 2106// Used to send messages to delegates that implement informal protocols. 2107 2108- (id)initWithTarget:(id)t defaultTarget:(id)dt catchExceptions:(BOOL)c 2109{ 2110 self = [super init]; 2111 if (!self) 2112 return nil; 2113 target = t; // Non retained. 2114 defaultTarget = dt; 2115 catchExceptions = c; 2116 return self; 2117} 2118 2119- (void)forwardInvocation:(NSInvocation *)invocation 2120{ 2121 if ([target respondsToSelector:[invocation selector]]) { 2122 if (catchExceptions) { 2123 @try { 2124 [invocation invokeWithTarget:target]; 2125 } @catch(id exception) { 2126 ReportDiscardedDelegateException([invocation selector], exception); 2127 } 2128 } else 2129 [invocation invokeWithTarget:target]; 2130 return; 2131 } 2132 2133 if ([defaultTarget respondsToSelector:[invocation selector]]) 2134 [invocation invokeWithTarget:defaultTarget]; 2135 2136 // Do nothing quietly if method not implemented. 2137} 2138 2139- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 2140{ 2141 return [defaultTarget methodSignatureForSelector:aSelector]; 2142} 2143 2144@end 2145 2146@implementation WebView 2147 2148+ (void)initialize 2149{ 2150 static BOOL initialized = NO; 2151 if (initialized) 2152 return; 2153 initialized = YES; 2154 2155 InitWebCoreSystemInterface(); 2156 2157 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp]; 2158 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil]; 2159 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil]; 2160 2161 continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled]; 2162#ifndef BUILDING_ON_TIGER 2163 grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled]; 2164#endif 2165 2166#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2167 automaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled]; 2168 automaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled]; 2169 automaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled]; 2170 automaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled]; 2171 automaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled]; 2172#endif 2173} 2174 2175+ (void)_applicationWillTerminate 2176{ 2177 applicationIsTerminating = YES; 2178 2179 if (fastDocumentTeardownEnabled()) 2180 [self closeAllWebViews]; 2181 2182 if (!pluginDatabaseClientCount) 2183 [WebPluginDatabase closeSharedDatabase]; 2184 2185 PageGroup::closeLocalStorage(); 2186} 2187 2188+ (BOOL)canShowMIMEType:(NSString *)MIMEType 2189{ 2190 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType]; 2191} 2192 2193- (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType 2194{ 2195 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType]; 2196 if (pluginPackage) 2197 return pluginPackage; 2198 2199 if (_private->pluginDatabase) 2200 return [_private->pluginDatabase pluginForMIMEType:MIMEType]; 2201 2202 return nil; 2203} 2204 2205- (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension 2206{ 2207 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension]; 2208 if (pluginPackage) 2209 return pluginPackage; 2210 2211 if (_private->pluginDatabase) 2212 return [_private->pluginDatabase pluginForExtension:extension]; 2213 2214 return nil; 2215} 2216 2217- (void)addPluginInstanceView:(NSView *)view 2218{ 2219 if (!_private->pluginDatabase) 2220 _private->pluginDatabase = [[WebPluginDatabase alloc] init]; 2221 [_private->pluginDatabase addPluginInstanceView:view]; 2222} 2223 2224- (void)removePluginInstanceView:(NSView *)view 2225{ 2226 if (_private->pluginDatabase) 2227 [_private->pluginDatabase removePluginInstanceView:view]; 2228} 2229 2230- (void)removePluginInstanceViewsFor:(WebFrame*)webFrame 2231{ 2232 if (_private->pluginDatabase) 2233 [_private->pluginDatabase removePluginInstanceViewsFor:webFrame]; 2234} 2235 2236- (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType 2237{ 2238 if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType]) 2239 return YES; 2240 2241 if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType]) 2242 return YES; 2243 2244 return NO; 2245} 2246 2247+ (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType 2248{ 2249 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType]; 2250} 2251 2252+ (NSArray *)MIMETypesShownAsHTML 2253{ 2254 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES]; 2255 NSEnumerator *enumerator = [viewTypes keyEnumerator]; 2256 id key; 2257 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease]; 2258 2259 while ((key = [enumerator nextObject])) { 2260 if ([viewTypes objectForKey:key] == [WebHTMLView class]) 2261 [array addObject:key]; 2262 } 2263 2264 return array; 2265} 2266 2267+ (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes 2268{ 2269 NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy]; 2270 NSEnumerator *enumerator = [viewTypes keyEnumerator]; 2271 id key; 2272 while ((key = [enumerator nextObject])) { 2273 if ([viewTypes objectForKey:key] == [WebHTMLView class]) 2274 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key]; 2275 } 2276 2277 int i, count = [MIMETypes count]; 2278 for (i = 0; i < count; i++) { 2279 [WebView registerViewClass:[WebHTMLView class] 2280 representationClass:[WebHTMLRepresentation class] 2281 forMIMEType:[MIMETypes objectAtIndex:i]]; 2282 } 2283 [viewTypes release]; 2284} 2285 2286+ (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard 2287{ 2288 return [pasteboard _web_bestURL]; 2289} 2290 2291+ (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard 2292{ 2293 return [pasteboard stringForType:WebURLNamePboardType]; 2294} 2295 2296+ (void)registerURLSchemeAsLocal:(NSString *)protocol 2297{ 2298 SecurityOrigin::registerURLSchemeAsLocal(protocol); 2299} 2300 2301- (id)_initWithArguments:(NSDictionary *) arguments 2302{ 2303 NSCoder *decoder = [arguments objectForKey:@"decoder"]; 2304 if (decoder) { 2305 self = [self initWithCoder:decoder]; 2306 } else { 2307 ASSERT([arguments objectForKey:@"frame"]); 2308 NSValue *frameValue = [arguments objectForKey:@"frame"]; 2309 NSRect frame = (frameValue ? [frameValue rectValue] : NSZeroRect); 2310 NSString *frameName = [arguments objectForKey:@"frameName"]; 2311 NSString *groupName = [arguments objectForKey:@"groupName"]; 2312 self = [self initWithFrame:frame frameName:frameName groupName:groupName]; 2313 } 2314 2315 return self; 2316} 2317 2318static bool clientNeedsWebViewInitThreadWorkaround() 2319{ 2320 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND)) 2321 return false; 2322 2323 NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; 2324 2325 // Installer. 2326 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.installer"]) 2327 return true; 2328 2329 // Automator. 2330 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Automator"]) 2331 return true; 2332 2333 // Automator Runner. 2334 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.AutomatorRunner"]) 2335 return true; 2336 2337 // Automator workflows. 2338 if ([bundleIdentifier _webkit_hasCaseInsensitivePrefix:@"com.apple.Automator."]) 2339 return true; 2340 2341#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 2342 // Mail. 2343 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Mail"]) 2344 return true; 2345#endif 2346 2347 return false; 2348} 2349 2350static bool needsWebViewInitThreadWorkaround() 2351{ 2352 static bool isOldClient = clientNeedsWebViewInitThreadWorkaround(); 2353 return isOldClient && !pthread_main_np(); 2354} 2355 2356- (id)initWithFrame:(NSRect)f 2357{ 2358 return [self initWithFrame:f frameName:nil groupName:nil]; 2359} 2360 2361- (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName 2362{ 2363 if (needsWebViewInitThreadWorkaround()) 2364 return [[self _webkit_invokeOnMainThread] initWithFrame:f frameName:frameName groupName:groupName]; 2365 2366 WebCoreThreadViolationCheckRoundTwo(); 2367 return [self _initWithFrame:f frameName:frameName groupName:groupName usesDocumentViews:YES]; 2368} 2369 2370- (id)initWithCoder:(NSCoder *)decoder 2371{ 2372 if (needsWebViewInitThreadWorkaround()) 2373 return [[self _webkit_invokeOnMainThread] initWithCoder:decoder]; 2374 2375 WebCoreThreadViolationCheckRoundTwo(); 2376 WebView *result = nil; 2377 2378 @try { 2379 NSString *frameName; 2380 NSString *groupName; 2381 WebPreferences *preferences; 2382 BOOL useBackForwardList = NO; 2383 BOOL allowsUndo = YES; 2384 2385 result = [super initWithCoder:decoder]; 2386 result->_private = [[WebViewPrivate alloc] init]; 2387 2388 // We don't want any of the archived subviews. The subviews will always 2389 // be created in _commonInitializationFrameName:groupName:. 2390 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 2391 2392 if ([decoder allowsKeyedCoding]) { 2393 frameName = [decoder decodeObjectForKey:@"FrameName"]; 2394 groupName = [decoder decodeObjectForKey:@"GroupName"]; 2395 preferences = [decoder decodeObjectForKey:@"Preferences"]; 2396 useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"]; 2397 if ([decoder containsValueForKey:@"AllowsUndo"]) 2398 allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"]; 2399 } else { 2400 int version; 2401 [decoder decodeValueOfObjCType:@encode(int) at:&version]; 2402 frameName = [decoder decodeObject]; 2403 groupName = [decoder decodeObject]; 2404 preferences = [decoder decodeObject]; 2405 if (version > 1) 2406 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList]; 2407 // The allowsUndo field is no longer written out in encodeWithCoder, but since there are 2408 // version 3 NIBs that have this field encoded, we still need to read it in. 2409 if (version == 3) 2410 [decoder decodeValuesOfObjCTypes:"c", &allowsUndo]; 2411 } 2412 2413 if (![frameName isKindOfClass:[NSString class]]) 2414 frameName = nil; 2415 if (![groupName isKindOfClass:[NSString class]]) 2416 groupName = nil; 2417 if (![preferences isKindOfClass:[WebPreferences class]]) 2418 preferences = nil; 2419 2420 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList); 2421 [result _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:YES]; 2422 [result page]->backForwardList()->setEnabled(useBackForwardList); 2423 result->_private->allowsUndo = allowsUndo; 2424 if (preferences) 2425 [result setPreferences:preferences]; 2426 } @catch (NSException *localException) { 2427 result = nil; 2428 [self release]; 2429 } 2430 2431 return result; 2432} 2433 2434- (void)encodeWithCoder:(NSCoder *)encoder 2435{ 2436 // Set asside the subviews before we archive. We don't want to archive any subviews. 2437 // The subviews will always be created in _commonInitializationFrameName:groupName:. 2438 id originalSubviews = _subviews; 2439 _subviews = nil; 2440 2441 [super encodeWithCoder:encoder]; 2442 2443 // Restore the subviews we set aside. 2444 _subviews = originalSubviews; 2445 2446 BOOL useBackForwardList = _private->page && _private->page->backForwardList()->enabled(); 2447 if ([encoder allowsKeyedCoding]) { 2448 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"]; 2449 [encoder encodeObject:[self groupName] forKey:@"GroupName"]; 2450 [encoder encodeObject:[self preferences] forKey:@"Preferences"]; 2451 [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"]; 2452 [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"]; 2453 } else { 2454 int version = WebViewVersion; 2455 [encoder encodeValueOfObjCType:@encode(int) at:&version]; 2456 [encoder encodeObject:[[self mainFrame] name]]; 2457 [encoder encodeObject:[self groupName]]; 2458 [encoder encodeObject:[self preferences]]; 2459 [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList]; 2460 // DO NOT encode any new fields here, doing so will break older WebKit releases. 2461 } 2462 2463 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList); 2464} 2465 2466- (void)dealloc 2467{ 2468 if (WebCoreObjCScheduleDeallocateOnMainThread([WebView class], self)) 2469 return; 2470 2471 // call close to ensure we tear-down completely 2472 // this maintains our old behavior for existing applications 2473 [self close]; 2474 2475 --WebViewCount; 2476 2477 if ([self _needsFrameLoadDelegateRetainQuirk]) 2478 [_private->frameLoadDelegate release]; 2479 2480 [_private release]; 2481 // [super dealloc] can end up dispatching against _private (3466082) 2482 _private = nil; 2483 2484 [super dealloc]; 2485} 2486 2487- (void)finalize 2488{ 2489 ASSERT(_private->closed); 2490 2491 --WebViewCount; 2492 2493 [super finalize]; 2494} 2495 2496- (void)close 2497{ 2498 // _close existed first, and some clients might be calling or overriding it, so call through. 2499 [self _close]; 2500} 2501 2502- (void)setShouldCloseWithWindow:(BOOL)close 2503{ 2504 _private->shouldCloseWithWindow = close; 2505} 2506 2507- (BOOL)shouldCloseWithWindow 2508{ 2509 return _private->shouldCloseWithWindow; 2510} 2511 2512- (void)addWindowObserversForWindow:(NSWindow *)window 2513{ 2514 if (window) { 2515 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) 2516 name:NSWindowDidBecomeKeyNotification object:nil]; 2517 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) 2518 name:NSWindowDidResignKeyNotification object:nil]; 2519 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOnScreen:) 2520 name:WKWindowWillOrderOnScreenNotification() object:window]; 2521 } 2522} 2523 2524- (void)removeWindowObservers 2525{ 2526 NSWindow *window = [self window]; 2527 if (window) { 2528 [[NSNotificationCenter defaultCenter] removeObserver:self 2529 name:NSWindowDidBecomeKeyNotification object:nil]; 2530 [[NSNotificationCenter defaultCenter] removeObserver:self 2531 name:NSWindowDidResignKeyNotification object:nil]; 2532 [[NSNotificationCenter defaultCenter] removeObserver:self 2533 name:WKWindowWillOrderOnScreenNotification() object:window]; 2534 } 2535} 2536 2537- (void)viewWillMoveToWindow:(NSWindow *)window 2538{ 2539 // Don't do anything if the WebView isn't initialized. 2540 // This happens when decoding a WebView in a nib. 2541 // FIXME: What sets up the observer of NSWindowWillCloseNotification in this case? 2542 if (!_private || _private->closed) 2543 return; 2544 2545 if ([self window] && [self window] != [self hostWindow]) 2546 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]]; 2547 2548 if (window) { 2549 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window]; 2550 2551 // Ensure that we will receive the events that WebHTMLView (at least) needs. 2552 // The following are expensive enough that we don't want to call them over 2553 // and over, so do them when we move into a window. 2554 [window setAcceptsMouseMovedEvents:YES]; 2555 WKSetNSWindowShouldPostEventNotifications(window, YES); 2556 } else 2557 _private->page->willMoveOffscreen(); 2558 2559 if (window != [self window]) { 2560 [self removeWindowObservers]; 2561 [self addWindowObserversForWindow:window]; 2562 } 2563} 2564 2565- (void)viewDidMoveToWindow 2566{ 2567 // Don't do anything if we aren't initialized. This happens 2568 // when decoding a WebView. When WebViews are decoded their subviews 2569 // are created by initWithCoder: and so won't be normally 2570 // initialized. The stub views are discarded by WebView. 2571 if (!_private || _private->closed) 2572 return; 2573 2574 if ([self window]) 2575 _private->page->didMoveOnscreen(); 2576 2577 [self _updateActiveState]; 2578} 2579 2580- (void)_windowDidBecomeKey:(NSNotification *)notification 2581{ 2582 NSWindow *keyWindow = [notification object]; 2583 if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) 2584 [self _updateActiveState]; 2585} 2586 2587- (void)_windowDidResignKey:(NSNotification *)notification 2588{ 2589 NSWindow *formerKeyWindow = [notification object]; 2590 if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) 2591 [self _updateActiveState]; 2592} 2593 2594- (void)_windowWillOrderOnScreen:(NSNotification *)notification 2595{ 2596 if (![self shouldUpdateWhileOffscreen]) 2597 [self setNeedsDisplay:YES]; 2598} 2599 2600- (void)_windowWillClose:(NSNotification *)notification 2601{ 2602 if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow]))) 2603 [self close]; 2604} 2605 2606- (void)setPreferences:(WebPreferences *)prefs 2607{ 2608 if (!prefs) 2609 prefs = [WebPreferences standardPreferences]; 2610 2611 if (_private->preferences == prefs) 2612 return; 2613 2614 [prefs willAddToWebView]; 2615 2616 WebPreferences *oldPrefs = _private->preferences; 2617 2618 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]]; 2619 [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]]; 2620 2621 _private->preferences = [prefs retain]; 2622 2623 // After registering for the notification, post it so the WebCore settings update. 2624 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) 2625 name:WebPreferencesChangedNotification object:[self preferences]]; 2626 [[self preferences] _postPreferencesChangesNotification]; 2627 2628 [oldPrefs didRemoveFromWebView]; 2629 [oldPrefs release]; 2630} 2631 2632- (WebPreferences *)preferences 2633{ 2634 return _private->preferences; 2635} 2636 2637- (void)setPreferencesIdentifier:(NSString *)anIdentifier 2638{ 2639 if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) { 2640 WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier]; 2641 [self setPreferences:prefs]; 2642 [prefs release]; 2643 } 2644} 2645 2646- (NSString *)preferencesIdentifier 2647{ 2648 return [[self preferences] identifier]; 2649} 2650 2651 2652- (void)setUIDelegate:delegate 2653{ 2654 _private->UIDelegate = delegate; 2655 [_private->UIDelegateForwarder release]; 2656 _private->UIDelegateForwarder = nil; 2657} 2658 2659- UIDelegate 2660{ 2661 return _private->UIDelegate; 2662} 2663 2664- (void)setResourceLoadDelegate: delegate 2665{ 2666 _private->resourceProgressDelegate = delegate; 2667 [self _cacheResourceLoadDelegateImplementations]; 2668} 2669 2670- resourceLoadDelegate 2671{ 2672 return _private->resourceProgressDelegate; 2673} 2674 2675- (void)setDownloadDelegate: delegate 2676{ 2677 _private->downloadDelegate = delegate; 2678} 2679 2680 2681- downloadDelegate 2682{ 2683 return _private->downloadDelegate; 2684} 2685 2686- (void)setPolicyDelegate:delegate 2687{ 2688 _private->policyDelegate = delegate; 2689 [_private->policyDelegateForwarder release]; 2690 _private->policyDelegateForwarder = nil; 2691} 2692 2693- policyDelegate 2694{ 2695 return _private->policyDelegate; 2696} 2697 2698- (void)setFrameLoadDelegate:delegate 2699{ 2700 // <rdar://problem/6950660> - Due to some subtle WebKit changes - presumably to delegate callback behavior - we've 2701 // unconvered a latent bug in at least one WebKit app where the delegate wasn't properly retained by the app and 2702 // was dealloc'ed before being cleared. 2703 // This is an effort to keep such apps working for now. 2704 if ([self _needsFrameLoadDelegateRetainQuirk]) { 2705 [delegate retain]; 2706 [_private->frameLoadDelegate release]; 2707 } 2708 2709 _private->frameLoadDelegate = delegate; 2710 [self _cacheFrameLoadDelegateImplementations]; 2711 2712#if ENABLE(ICONDATABASE) 2713 // If this delegate wants callbacks for icons, fire up the icon database. 2714 if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc) 2715 [WebIconDatabase sharedIconDatabase]; 2716#endif 2717} 2718 2719- frameLoadDelegate 2720{ 2721 return _private->frameLoadDelegate; 2722} 2723 2724- (WebFrame *)mainFrame 2725{ 2726 // This can be called in initialization, before _private has been set up (3465613) 2727 if (!_private || !_private->page) 2728 return nil; 2729 return kit(_private->page->mainFrame()); 2730} 2731 2732- (WebFrame *)selectedFrame 2733{ 2734 if (_private->usesDocumentViews) { 2735 // If the first responder is a view in our tree, we get the frame containing the first responder. 2736 // This is faster than searching the frame hierarchy, and will give us a result even in the case 2737 // where the focused frame doesn't actually contain a selection. 2738 WebFrame *focusedFrame = [self _focusedFrame]; 2739 if (focusedFrame) 2740 return focusedFrame; 2741 } 2742 2743 // If the first responder is outside of our view tree, we search for a frame containing a selection. 2744 // There should be at most only one of these. 2745 return [[self mainFrame] _findFrameWithSelection]; 2746} 2747 2748- (WebBackForwardList *)backForwardList 2749{ 2750 if (!_private->page) 2751 return nil; 2752 if (!_private->page->backForwardList()->enabled()) 2753 return nil; 2754 return kit(_private->page->backForwardList()); 2755} 2756 2757- (void)setMaintainsBackForwardList:(BOOL)flag 2758{ 2759 if (!_private->page) 2760 return; 2761 _private->page->backForwardList()->setEnabled(flag); 2762} 2763 2764- (BOOL)goBack 2765{ 2766 if (!_private->page) 2767 return NO; 2768 2769 return _private->page->goBack(); 2770} 2771 2772- (BOOL)goForward 2773{ 2774 if (!_private->page) 2775 return NO; 2776 2777 return _private->page->goForward(); 2778} 2779 2780- (BOOL)goToBackForwardItem:(WebHistoryItem *)item 2781{ 2782 if (!_private->page) 2783 return NO; 2784 2785 _private->page->goToItem(core(item), FrameLoadTypeIndexedBackForward); 2786 return YES; 2787} 2788 2789- (void)setTextSizeMultiplier:(float)m 2790{ 2791 [self _setZoomMultiplier:m isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 2792} 2793 2794- (float)textSizeMultiplier 2795{ 2796 return [self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f; 2797} 2798 2799- (void)_setZoomMultiplier:(float)m isTextOnly:(BOOL)isTextOnly 2800{ 2801 // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>) 2802 _private->zoomMultiplier = m; 2803 ASSERT(_private->page); 2804 if (_private->page) 2805 _private->page->settings()->setZoomsTextOnly(isTextOnly); 2806 2807 // FIXME: it would be nice to rework this code so that _private->zoomMultiplier doesn't exist and callers 2808 // all access _private->page->settings(). 2809 Frame* coreFrame = [self _mainCoreFrame]; 2810 if (coreFrame) 2811 coreFrame->setZoomFactor(m, isTextOnly); 2812} 2813 2814- (float)_zoomMultiplier:(BOOL)isTextOnly 2815{ 2816 if (isTextOnly != [self _realZoomMultiplierIsTextOnly]) 2817 return 1.0f; 2818 return _private->zoomMultiplier; 2819} 2820 2821- (float)_realZoomMultiplier 2822{ 2823 return _private->zoomMultiplier; 2824} 2825 2826- (BOOL)_realZoomMultiplierIsTextOnly 2827{ 2828 if (!_private->page) 2829 return NO; 2830 2831 return _private->page->settings()->zoomsTextOnly(); 2832} 2833 2834#define MinimumZoomMultiplier 0.5f 2835#define MaximumZoomMultiplier 3.0f 2836#define ZoomMultiplierRatio 1.2f 2837 2838- (BOOL)_canZoomOut:(BOOL)isTextOnly 2839{ 2840 id docView = [[[self mainFrame] frameView] documentView]; 2841 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 2842 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 2843 return [zoomingDocView _canZoomOut]; 2844 } 2845 return [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio > MinimumZoomMultiplier; 2846} 2847 2848 2849- (BOOL)_canZoomIn:(BOOL)isTextOnly 2850{ 2851 id docView = [[[self mainFrame] frameView] documentView]; 2852 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 2853 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 2854 return [zoomingDocView _canZoomIn]; 2855 } 2856 return [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio < MaximumZoomMultiplier; 2857} 2858 2859- (IBAction)_zoomOut:(id)sender isTextOnly:(BOOL)isTextOnly 2860{ 2861 id docView = [[[self mainFrame] frameView] documentView]; 2862 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 2863 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 2864 return [zoomingDocView _zoomOut:sender]; 2865 } 2866 float newScale = [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio; 2867 if (newScale > MinimumZoomMultiplier) 2868 [self _setZoomMultiplier:newScale isTextOnly:isTextOnly]; 2869} 2870 2871- (IBAction)_zoomIn:(id)sender isTextOnly:(BOOL)isTextOnly 2872{ 2873 id docView = [[[self mainFrame] frameView] documentView]; 2874 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 2875 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 2876 return [zoomingDocView _zoomIn:sender]; 2877 } 2878 float newScale = [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio; 2879 if (newScale < MaximumZoomMultiplier) 2880 [self _setZoomMultiplier:newScale isTextOnly:isTextOnly]; 2881} 2882 2883- (BOOL)_canResetZoom:(BOOL)isTextOnly 2884{ 2885 id docView = [[[self mainFrame] frameView] documentView]; 2886 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 2887 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 2888 return [zoomingDocView _canResetZoom]; 2889 } 2890 return [self _zoomMultiplier:isTextOnly] != 1.0f; 2891} 2892 2893- (IBAction)_resetZoom:(id)sender isTextOnly:(BOOL)isTextOnly 2894{ 2895 id docView = [[[self mainFrame] frameView] documentView]; 2896 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 2897 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 2898 return [zoomingDocView _resetZoom:sender]; 2899 } 2900 if ([self _zoomMultiplier:isTextOnly] != 1.0f) 2901 [self _setZoomMultiplier:1.0f isTextOnly:isTextOnly]; 2902} 2903 2904- (void)setApplicationNameForUserAgent:(NSString *)applicationName 2905{ 2906 NSString *name = [applicationName copy]; 2907 [_private->applicationNameForUserAgent release]; 2908 _private->applicationNameForUserAgent = name; 2909 if (!_private->userAgentOverridden) 2910 _private->userAgent = String(); 2911} 2912 2913- (NSString *)applicationNameForUserAgent 2914{ 2915 return [[_private->applicationNameForUserAgent retain] autorelease]; 2916} 2917 2918- (void)setCustomUserAgent:(NSString *)userAgentString 2919{ 2920 _private->userAgent = userAgentString; 2921 _private->userAgentOverridden = userAgentString != nil; 2922} 2923 2924- (NSString *)customUserAgent 2925{ 2926 if (!_private->userAgentOverridden) 2927 return nil; 2928 return _private->userAgent; 2929} 2930 2931- (void)setMediaStyle:(NSString *)mediaStyle 2932{ 2933 if (_private->mediaStyle != mediaStyle) { 2934 [_private->mediaStyle release]; 2935 _private->mediaStyle = [mediaStyle copy]; 2936 } 2937} 2938 2939- (NSString *)mediaStyle 2940{ 2941 return _private->mediaStyle; 2942} 2943 2944- (BOOL)supportsTextEncoding 2945{ 2946 id documentView = [[[self mainFrame] frameView] documentView]; 2947 return [documentView conformsToProtocol:@protocol(WebDocumentText)] 2948 && [documentView supportsTextEncoding]; 2949} 2950 2951- (void)setCustomTextEncodingName:(NSString *)encoding 2952{ 2953 NSString *oldEncoding = [self customTextEncodingName]; 2954 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) 2955 return; 2956 if (Frame* mainFrame = [self _mainCoreFrame]) 2957 mainFrame->loader()->reloadWithOverrideEncoding(encoding); 2958} 2959 2960- (NSString *)_mainFrameOverrideEncoding 2961{ 2962 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource]; 2963 if (dataSource == nil) 2964 dataSource = [[self mainFrame] _dataSource]; 2965 if (dataSource == nil) 2966 return nil; 2967 return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding()); 2968} 2969 2970- (NSString *)customTextEncodingName 2971{ 2972 return [self _mainFrameOverrideEncoding]; 2973} 2974 2975- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script 2976{ 2977 // Return statements are only valid in a function but some applications pass in scripts 2978 // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions 2979 // silently ignored the return. If the application is linked against an earlier version 2980 // of WebKit we will strip the return so the script wont fail. 2981 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) { 2982 NSRange returnStringRange = [script rangeOfString:@"return "]; 2983 if (returnStringRange.length && !returnStringRange.location) 2984 script = [script substringFromIndex:returnStringRange.location + returnStringRange.length]; 2985 } 2986 2987 NSString *result = [[self mainFrame] _stringByEvaluatingJavaScriptFromString:script]; 2988 // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script 2989 // Since there's no way to get rid of the main frame, result will never ever be nil here. 2990 ASSERT(result); 2991 2992 return result; 2993} 2994 2995- (WebScriptObject *)windowScriptObject 2996{ 2997 Frame* coreFrame = [self _mainCoreFrame]; 2998 if (!coreFrame) 2999 return nil; 3000 return coreFrame->script()->windowScriptObject(); 3001} 3002 3003// Get the appropriate user-agent string for a particular URL. 3004- (NSString *)userAgentForURL:(NSURL *)url 3005{ 3006 return [self _userAgentForURL:KURL([url absoluteURL])]; 3007} 3008 3009- (void)setHostWindow:(NSWindow *)hostWindow 3010{ 3011 if (_private->closed) 3012 return; 3013 if (hostWindow == _private->hostWindow) 3014 return; 3015 3016 Frame* coreFrame = [self _mainCoreFrame]; 3017 if (_private->usesDocumentViews) { 3018 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) 3019 [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow]; 3020 } 3021 if (_private->hostWindow && [self window] != _private->hostWindow) 3022 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow]; 3023 if (hostWindow) 3024 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow]; 3025 [_private->hostWindow release]; 3026 _private->hostWindow = [hostWindow retain]; 3027 if (_private->usesDocumentViews) { 3028 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) 3029 [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow]; 3030 } 3031} 3032 3033- (NSWindow *)hostWindow 3034{ 3035 // -[WebView hostWindow] can sometimes be called from the WebView's [super dealloc] method 3036 // so we check here to make sure it's not null. 3037 if (!_private) 3038 return nil; 3039 3040 return _private->hostWindow; 3041} 3042 3043- (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point 3044{ 3045 return [[self _frameViewAtWindowPoint:point] documentView]; 3046} 3047 3048- (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint 3049{ 3050 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint]; 3051 if (!frameView) 3052 return nil; 3053 NSView <WebDocumentView> *documentView = [frameView documentView]; 3054 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) { 3055 NSPoint point = [documentView convertPoint:windowPoint fromView:nil]; 3056 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point]; 3057 } 3058 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey]; 3059} 3060 3061- (NSDictionary *)elementAtPoint:(NSPoint)point 3062{ 3063 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]]; 3064} 3065 3066// The following 2 internal NSView methods are called on the drag destination to make scrolling while dragging work. 3067// Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. 3068// When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. 3069// Forward these calls to the document subview to make its scroll view scroll. 3070- (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta 3071{ 3072 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3073 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta]; 3074} 3075 3076- (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo 3077{ 3078 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3079 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo]; 3080} 3081 3082- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo 3083{ 3084 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3085 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); 3086 IntPoint client([draggingInfo draggingLocation]); 3087 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3088 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3089 return core(self)->dragController()->dragEntered(&dragData); 3090} 3091 3092- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo 3093{ 3094 Page* page = core(self); 3095 if (!page) 3096 return NSDragOperationNone; 3097 3098 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3099 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); 3100 IntPoint client([draggingInfo draggingLocation]); 3101 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3102 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3103 return page->dragController()->dragUpdated(&dragData); 3104} 3105 3106- (void)draggingExited:(id <NSDraggingInfo>)draggingInfo 3107{ 3108 Page* page = core(self); 3109 if (!page) 3110 return; 3111 3112 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3113 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); 3114 IntPoint client([draggingInfo draggingLocation]); 3115 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3116 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3117 page->dragController()->dragExited(&dragData); 3118} 3119 3120- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo 3121{ 3122 return YES; 3123} 3124 3125- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo 3126{ 3127 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3128 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]]? (WebHTMLView*)view : nil); 3129 IntPoint client([draggingInfo draggingLocation]); 3130 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3131 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3132 return core(self)->dragController()->performDrag(&dragData); 3133} 3134 3135- (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types 3136{ 3137 NSView *hitView = [super _hitTest:point dragTypes:types]; 3138 if (!hitView && [[self superview] mouse:*point inRect:[self frame]]) 3139 return self; 3140 return hitView; 3141} 3142 3143- (BOOL)acceptsFirstResponder 3144{ 3145 if (_private->usesDocumentViews) 3146 return [[[self mainFrame] frameView] acceptsFirstResponder]; 3147 3148 // FIXME (Viewless): Need more code from WebHTMLView here. 3149 return YES; 3150} 3151 3152- (BOOL)becomeFirstResponder 3153{ 3154 if (_private->usesDocumentViews) { 3155 if (_private->becomingFirstResponder) { 3156 // Fix for unrepro infinite recursion reported in Radar 4448181. If we hit this assert on 3157 // a debug build, we should figure out what causes the problem and do a better fix. 3158 ASSERT_NOT_REACHED(); 3159 return NO; 3160 } 3161 3162 // This works together with setNextKeyView to splice the WebView into 3163 // the key loop similar to the way NSScrollView does this. Note that 3164 // WebFrameView has very similar code. 3165 NSWindow *window = [self window]; 3166 WebFrameView *mainFrameView = [[self mainFrame] frameView]; 3167 3168 NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming]; 3169 BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self); 3170 3171 if ([window keyViewSelectionDirection] == NSSelectingPrevious) { 3172 NSView *previousValidKeyView = [self previousValidKeyView]; 3173 if (previousValidKeyView != self && previousValidKeyView != mainFrameView) { 3174 _private->becomingFirstResponder = YES; 3175 _private->becomingFirstResponderFromOutside = fromOutside; 3176 [window makeFirstResponder:previousValidKeyView]; 3177 _private->becomingFirstResponderFromOutside = NO; 3178 _private->becomingFirstResponder = NO; 3179 return YES; 3180 } 3181 return NO; 3182 } 3183 3184 if ([mainFrameView acceptsFirstResponder]) { 3185 _private->becomingFirstResponder = YES; 3186 _private->becomingFirstResponderFromOutside = fromOutside; 3187 [window makeFirstResponder:mainFrameView]; 3188 _private->becomingFirstResponderFromOutside = NO; 3189 _private->becomingFirstResponder = NO; 3190 return YES; 3191 } 3192 3193 return NO; 3194 } 3195 3196 // FIXME (Viewless): Need more code from WebHTMLView here. 3197 return YES; 3198} 3199 3200- (NSView *)_webcore_effectiveFirstResponder 3201{ 3202 if (_private && _private->usesDocumentViews) { 3203 if (WebFrameView *frameView = [[self mainFrame] frameView]) 3204 return [frameView _webcore_effectiveFirstResponder]; 3205 } 3206 return [super _webcore_effectiveFirstResponder]; 3207} 3208 3209- (void)setNextKeyView:(NSView *)view 3210{ 3211 if (_private && _private->usesDocumentViews) { 3212 // This works together with becomeFirstResponder to splice the WebView into 3213 // the key loop similar to the way NSScrollView does this. Note that 3214 // WebFrameView has similar code. 3215 if (WebFrameView *mainFrameView = [[self mainFrame] frameView]) { 3216 [mainFrameView setNextKeyView:view]; 3217 return; 3218 } 3219 } 3220 3221 [super setNextKeyView:view]; 3222} 3223 3224static WebFrame *incrementFrame(WebFrame *frame, BOOL forward, BOOL wrapFlag) 3225{ 3226 Frame* coreFrame = core(frame); 3227 return kit(forward 3228 ? coreFrame->tree()->traverseNextWithWrap(wrapFlag) 3229 : coreFrame->tree()->traversePreviousWithWrap(wrapFlag)); 3230} 3231 3232- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag 3233{ 3234 return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO]; 3235} 3236 3237+ (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType 3238{ 3239 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType]; 3240 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType]; 3241 3242 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) 3243 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner 3244 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness 3245 if ([viewClass class] == [WebHTMLView class]) 3246 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType); 3247} 3248 3249- (void)setGroupName:(NSString *)groupName 3250{ 3251 if (!_private->page) 3252 return; 3253 _private->page->setGroupName(groupName); 3254} 3255 3256- (NSString *)groupName 3257{ 3258 if (!_private->page) 3259 return nil; 3260 return _private->page->groupName(); 3261} 3262 3263- (double)estimatedProgress 3264{ 3265 if (!_private->page) 3266 return 0.0; 3267 return _private->page->progress()->estimatedProgress(); 3268} 3269 3270- (NSArray *)pasteboardTypesForSelection 3271{ 3272 NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView]; 3273 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) { 3274 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection]; 3275 } 3276 return [NSArray array]; 3277} 3278 3279- (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 3280{ 3281 WebFrame *frame = [self _selectedOrMainFrame]; 3282 if (frame && [frame _hasSelection]) { 3283 NSView <WebDocumentView> *documentView = [[frame frameView] documentView]; 3284 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) 3285 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard]; 3286 } 3287} 3288 3289- (NSArray *)pasteboardTypesForElement:(NSDictionary *)element 3290{ 3291 if ([element objectForKey:WebElementImageURLKey] != nil) { 3292 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)]; 3293 } else if ([element objectForKey:WebElementLinkURLKey] != nil) { 3294 return [NSPasteboard _web_writableTypesForURL]; 3295 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) { 3296 return [self pasteboardTypesForSelection]; 3297 } 3298 return [NSArray array]; 3299} 3300 3301- (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 3302{ 3303 if ([element objectForKey:WebElementImageURLKey] != nil) { 3304 [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard]; 3305 } else if ([element objectForKey:WebElementLinkURLKey] != nil) { 3306 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard]; 3307 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) { 3308 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard]; 3309 } 3310} 3311 3312- (void)moveDragCaretToPoint:(NSPoint)point 3313{ 3314 if (Page* page = core(self)) 3315 page->dragController()->placeDragCaret(IntPoint([self convertPoint:point toView:nil])); 3316} 3317 3318- (void)removeDragCaret 3319{ 3320 if (Page* page = core(self)) 3321 page->dragController()->dragEnded(); 3322} 3323 3324- (void)setMainFrameURL:(NSString *)URLString 3325{ 3326 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]]; 3327} 3328 3329- (NSString *)mainFrameURL 3330{ 3331 WebDataSource *ds; 3332 ds = [[self mainFrame] provisionalDataSource]; 3333 if (!ds) 3334 ds = [[self mainFrame] _dataSource]; 3335 return [[[ds request] URL] _web_originalDataAsString]; 3336} 3337 3338- (BOOL)isLoading 3339{ 3340 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]); 3341 return [self _isLoading]; 3342} 3343 3344- (NSString *)mainFrameTitle 3345{ 3346 NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle]; 3347 return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@""; 3348} 3349 3350- (NSImage *)mainFrameIcon 3351{ 3352 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize]; 3353} 3354 3355- (DOMDocument *)mainFrameDocument 3356{ 3357 // only return the actual value if the state we're in gives NSTreeController 3358 // enough time to release its observers on the old model 3359 if (_private->mainFrameDocumentReady) 3360 return [[self mainFrame] DOMDocument]; 3361 return nil; 3362} 3363 3364- (void)setDrawsBackground:(BOOL)drawsBackground 3365{ 3366 if (_private->drawsBackground == drawsBackground) 3367 return; 3368 _private->drawsBackground = drawsBackground; 3369 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; 3370} 3371 3372- (BOOL)drawsBackground 3373{ 3374 // This method can be called beneath -[NSView dealloc] after we have cleared _private, 3375 // indirectly via -[WebFrameView viewDidMoveToWindow]. 3376 return !_private || _private->drawsBackground; 3377} 3378 3379- (void)setShouldUpdateWhileOffscreen:(BOOL)updateWhileOffscreen 3380{ 3381 if (_private->shouldUpdateWhileOffscreen == updateWhileOffscreen) 3382 return; 3383 _private->shouldUpdateWhileOffscreen = updateWhileOffscreen; 3384 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; 3385} 3386 3387- (BOOL)shouldUpdateWhileOffscreen 3388{ 3389 return _private->shouldUpdateWhileOffscreen; 3390} 3391 3392- (void)setCurrentNodeHighlight:(WebNodeHighlight *)nodeHighlight 3393{ 3394 id old = _private->currentNodeHighlight; 3395 _private->currentNodeHighlight = [nodeHighlight retain]; 3396 [old release]; 3397} 3398 3399- (WebNodeHighlight *)currentNodeHighlight 3400{ 3401 return _private->currentNodeHighlight; 3402} 3403 3404- (NSView *)previousValidKeyView 3405{ 3406 NSView *result = [super previousValidKeyView]; 3407 3408 // Work around AppKit bug 6905484. If the result is a view that's inside this one, it's 3409 // possible it is the wrong answer, because the fact that it's a descendant causes the 3410 // code that implements key view redirection to fail; this means we won't redirect to 3411 // the toolbar, for example, when we hit the edge of a window. Since the bug is specific 3412 // to cases where the receiver of previousValidKeyView is an ancestor of the last valid 3413 // key view in the loop, we can sidestep it by walking along previous key views until 3414 // we find one that is not a superview, then using that to call previousValidKeyView. 3415 3416 if (![result isDescendantOf:self]) 3417 return result; 3418 3419 // Use a visited set so we don't loop indefinitely when walking crazy key loops. 3420 // AppKit uses such sets internally and we want our loop to be as robust as its loops. 3421 RetainPtr<CFMutableSetRef> visitedViews = CFSetCreateMutable(0, 0, 0); 3422 CFSetAddValue(visitedViews.get(), result); 3423 3424 NSView *previousView = self; 3425 do { 3426 CFSetAddValue(visitedViews.get(), previousView); 3427 previousView = [previousView previousKeyView]; 3428 if (!previousView || CFSetGetValue(visitedViews.get(), previousView)) 3429 return result; 3430 } while ([result isDescendantOf:previousView]); 3431 return [previousView previousValidKeyView]; 3432} 3433 3434- (void)mouseDown:(NSEvent *)event 3435{ 3436 // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to 3437 // do the same work in the usesDocumentViews case. We don't want to maintain two 3438 // duplicate copies of this method. 3439 3440 if (_private->usesDocumentViews) { 3441 [super mouseDown:event]; 3442 return; 3443 } 3444 3445 // There's a chance that responding to this event will run a nested event loop, and 3446 // fetching a new event might release the old one. Retaining and then autoreleasing 3447 // the current event prevents that from causing a problem inside WebKit or AppKit code. 3448 [[event retain] autorelease]; 3449 3450 RetainPtr<WebView> protector = self; 3451 if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event]) 3452 return; 3453 3454 _private->handlingMouseDownEvent = YES; 3455 3456 // Record the mouse down position so we can determine drag hysteresis. 3457 [self _setMouseDownEvent:event]; 3458 3459 NSInputManager *currentInputManager = [NSInputManager currentInputManager]; 3460 if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) 3461 goto done; 3462 3463 [_private->completionController endRevertingChange:NO moveLeft:NO]; 3464 3465 // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here. 3466 // We don't want to pass them along to KHTML a second time. 3467 if (!([event modifierFlags] & NSControlKeyMask)) { 3468 _private->ignoringMouseDraggedEvents = NO; 3469 3470 // Don't do any mouseover while the mouse is down. 3471 [self _cancelUpdateMouseoverTimer]; 3472 3473 // Let WebCore get a chance to deal with the event. This will call back to us 3474 // to start the autoscroll timer if appropriate. 3475 if (Frame* frame = [self _mainCoreFrame]) 3476 frame->eventHandler()->mouseDown(event); 3477 } 3478 3479done: 3480 _private->handlingMouseDownEvent = NO; 3481} 3482 3483- (void)mouseUp:(NSEvent *)event 3484{ 3485 // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to 3486 // do the same work in the usesDocumentViews case. We don't want to maintain two 3487 // duplicate copies of this method. 3488 3489 if (_private->usesDocumentViews) { 3490 [super mouseUp:event]; 3491 return; 3492 } 3493 3494 // There's a chance that responding to this event will run a nested event loop, and 3495 // fetching a new event might release the old one. Retaining and then autoreleasing 3496 // the current event prevents that from causing a problem inside WebKit or AppKit code. 3497 [[event retain] autorelease]; 3498 3499 [self _setMouseDownEvent:nil]; 3500 3501 NSInputManager *currentInputManager = [NSInputManager currentInputManager]; 3502 if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) 3503 return; 3504 3505 [self retain]; 3506 3507 [self _stopAutoscrollTimer]; 3508 if (Frame* frame = [self _mainCoreFrame]) 3509 frame->eventHandler()->mouseUp(event); 3510 [self _updateMouseoverWithFakeEvent]; 3511 3512 [self release]; 3513} 3514 3515@end 3516 3517@implementation WebView (WebIBActions) 3518 3519- (IBAction)takeStringURLFrom: sender 3520{ 3521 NSString *URLString = [sender stringValue]; 3522 3523 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]]; 3524} 3525 3526- (BOOL)canGoBack 3527{ 3528 if (!_private->page) 3529 return NO; 3530 3531 return !!_private->page->backForwardList()->backItem(); 3532} 3533 3534- (BOOL)canGoForward 3535{ 3536 if (!_private->page) 3537 return NO; 3538 3539 return !!_private->page->backForwardList()->forwardItem(); 3540} 3541 3542- (IBAction)goBack:(id)sender 3543{ 3544 [self goBack]; 3545} 3546 3547- (IBAction)goForward:(id)sender 3548{ 3549 [self goForward]; 3550} 3551 3552- (IBAction)stopLoading:(id)sender 3553{ 3554 [[self mainFrame] stopLoading]; 3555} 3556 3557- (IBAction)reload:(id)sender 3558{ 3559 [[self mainFrame] reload]; 3560} 3561 3562- (IBAction)reloadFromOrigin:(id)sender 3563{ 3564 [[self mainFrame] reloadFromOrigin]; 3565} 3566 3567// FIXME: This code should move into WebCore so that it is not duplicated in each WebKit. 3568// (This includes canMakeTextSmaller/Larger, makeTextSmaller/Larger, and canMakeTextStandardSize/makeTextStandardSize) 3569- (BOOL)canMakeTextSmaller 3570{ 3571 return [self _canZoomOut:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3572} 3573 3574- (IBAction)makeTextSmaller:(id)sender 3575{ 3576 return [self _zoomOut:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3577} 3578 3579- (BOOL)canMakeTextLarger 3580{ 3581 return [self _canZoomIn:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3582} 3583 3584- (IBAction)makeTextLarger:(id)sender 3585{ 3586 return [self _zoomIn:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3587} 3588 3589- (BOOL)canMakeTextStandardSize 3590{ 3591 return [self _canResetZoom:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3592} 3593 3594- (IBAction)makeTextStandardSize:(id)sender 3595{ 3596 return [self _resetZoom:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3597} 3598 3599- (IBAction)toggleSmartInsertDelete:(id)sender 3600{ 3601 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]]; 3602} 3603 3604- (IBAction)toggleContinuousSpellChecking:(id)sender 3605{ 3606 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]]; 3607} 3608 3609- (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 3610{ 3611 id responder = [self _responderForResponderOperations]; 3612 if (responder != self && [responder respondsToSelector:[item action]]) { 3613 if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)]) 3614 return [responder validateUserInterfaceItemWithoutDelegate:item]; 3615 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) 3616 return [responder validateUserInterfaceItem:item]; 3617 return YES; 3618 } 3619 return NO; 3620} 3621 3622#define VALIDATE(name) \ 3623 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; } 3624 3625- (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item 3626{ 3627 SEL action = [item action]; 3628 3629 if (action == @selector(goBack:)) { 3630 return [self canGoBack]; 3631 } else if (action == @selector(goForward:)) { 3632 return [self canGoForward]; 3633 } else if (action == @selector(makeTextLarger:)) { 3634 return [self canMakeTextLarger]; 3635 } else if (action == @selector(makeTextSmaller:)) { 3636 return [self canMakeTextSmaller]; 3637 } else if (action == @selector(makeTextStandardSize:)) { 3638 return [self canMakeTextStandardSize]; 3639 } else if (action == @selector(reload:)) { 3640 return [[self mainFrame] _dataSource] != nil; 3641 } else if (action == @selector(stopLoading:)) { 3642 return [self _isLoading]; 3643 } else if (action == @selector(toggleContinuousSpellChecking:)) { 3644 BOOL checkMark = NO; 3645 BOOL retVal = NO; 3646 if ([self _continuousCheckingAllowed]) { 3647 checkMark = [self isContinuousSpellCheckingEnabled]; 3648 retVal = YES; 3649 } 3650 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3651 NSMenuItem *menuItem = (NSMenuItem *)item; 3652 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3653 } 3654 return retVal; 3655 } else if (action == @selector(toggleSmartInsertDelete:)) { 3656 BOOL checkMark = [self smartInsertDeleteEnabled]; 3657 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3658 NSMenuItem *menuItem = (NSMenuItem *)item; 3659 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3660 } 3661 return YES; 3662#ifndef BUILDING_ON_TIGER 3663 } else if (action == @selector(toggleGrammarChecking:)) { 3664 BOOL checkMark = [self isGrammarCheckingEnabled]; 3665 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3666 NSMenuItem *menuItem = (NSMenuItem *)item; 3667 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3668 } 3669 return YES; 3670#endif 3671#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 3672 } else if (action == @selector(toggleAutomaticQuoteSubstitution:)) { 3673 BOOL checkMark = [self isAutomaticQuoteSubstitutionEnabled]; 3674 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3675 NSMenuItem *menuItem = (NSMenuItem *)item; 3676 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3677 } 3678 return YES; 3679 } else if (action == @selector(toggleAutomaticLinkDetection:)) { 3680 BOOL checkMark = [self isAutomaticLinkDetectionEnabled]; 3681 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3682 NSMenuItem *menuItem = (NSMenuItem *)item; 3683 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3684 } 3685 return YES; 3686 } else if (action == @selector(toggleAutomaticDashSubstitution:)) { 3687 BOOL checkMark = [self isAutomaticDashSubstitutionEnabled]; 3688 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3689 NSMenuItem *menuItem = (NSMenuItem *)item; 3690 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3691 } 3692 return YES; 3693 } else if (action == @selector(toggleAutomaticTextReplacement:)) { 3694 BOOL checkMark = [self isAutomaticTextReplacementEnabled]; 3695 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3696 NSMenuItem *menuItem = (NSMenuItem *)item; 3697 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3698 } 3699 return YES; 3700 } else if (action == @selector(toggleAutomaticSpellingCorrection:)) { 3701 BOOL checkMark = [self isAutomaticSpellingCorrectionEnabled]; 3702 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3703 NSMenuItem *menuItem = (NSMenuItem *)item; 3704 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3705 } 3706 return YES; 3707#endif 3708 } 3709 FOR_EACH_RESPONDER_SELECTOR(VALIDATE) 3710 3711 return YES; 3712} 3713 3714- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 3715{ 3716 BOOL result = [self validateUserInterfaceItemWithoutDelegate:item]; 3717 return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result); 3718} 3719 3720@end 3721 3722@implementation WebView (WebPendingPublic) 3723 3724- (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode 3725{ 3726 if (runLoop && mode) 3727 core(self)->addSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode)); 3728} 3729 3730- (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode 3731{ 3732 if (runLoop && mode) 3733 core(self)->removeSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode)); 3734} 3735 3736- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection 3737{ 3738 if (_private->closed) 3739 return NO; 3740 3741 // Get the frame holding the selection, or start with the main frame 3742 WebFrame *startFrame = [self _selectedOrMainFrame]; 3743 3744 // Search the first frame, then all the other frames, in order 3745 NSView <WebDocumentSearching> *startSearchView = nil; 3746 WebFrame *frame = startFrame; 3747 do { 3748 WebFrame *nextFrame = incrementFrame(frame, forward, wrapFlag); 3749 3750 BOOL onlyOneFrame = (frame == nextFrame); 3751 ASSERT(!onlyOneFrame || frame == startFrame); 3752 3753 id <WebDocumentView> view = [[frame frameView] documentView]; 3754 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) { 3755 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view; 3756 3757 if (frame == startFrame) 3758 startSearchView = searchView; 3759 3760 BOOL foundString; 3761 // In some cases we have to search some content twice; see comment later in this method. 3762 // We can avoid ever doing this in the common one-frame case by passing YES for wrapFlag 3763 // here, and then bailing out before we get to the code that would search again in the 3764 // same content. 3765 BOOL wrapOnThisPass = wrapFlag && onlyOneFrame; 3766 if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)]) 3767 foundString = [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass startInSelection:startInSelection]; 3768 else 3769 foundString = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass]; 3770 3771 if (foundString) { 3772 if (frame != startFrame) 3773 [startFrame _clearSelection]; 3774 [[self window] makeFirstResponder:searchView]; 3775 return YES; 3776 } 3777 3778 if (onlyOneFrame) 3779 return NO; 3780 } 3781 frame = nextFrame; 3782 } while (frame && frame != startFrame); 3783 3784 // If there are multiple frames and wrapFlag is true and we've visited each one without finding a result, we still need to search in the 3785 // first-searched frame up to the selection. However, the API doesn't provide a way to search only up to a particular point. The only 3786 // way to make sure the entire frame is searched is to pass YES for the wrapFlag. When there are no matches, this will search again 3787 // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice. 3788 // To fix this, we'd need to add a mechanism to specify a range in which to search. 3789 if (wrapFlag && startSearchView) { 3790 BOOL foundString; 3791 if ([startSearchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)]) 3792 foundString = [(NSView <WebDocumentIncrementalSearching> *)startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES startInSelection:startInSelection]; 3793 else 3794 foundString = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES]; 3795 if (foundString) { 3796 [[self window] makeFirstResponder:startSearchView]; 3797 return YES; 3798 } 3799 } 3800 return NO; 3801} 3802 3803- (void)setHoverFeedbackSuspended:(BOOL)newValue 3804{ 3805 if (_private->hoverFeedbackSuspended == newValue) 3806 return; 3807 3808 _private->hoverFeedbackSuspended = newValue; 3809 3810 if (_private->usesDocumentViews) { 3811 id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView]; 3812 // FIXME: in a perfect world we'd do this in a general way that worked with any document view, 3813 // such as by calling a protocol method or using respondsToSelector or sending a notification. 3814 // But until there is any need for these more general solutions, we'll just hardwire it to work 3815 // with WebHTMLView. 3816 // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not 3817 // on each subframe separately. 3818 if ([documentView isKindOfClass:[WebHTMLView class]]) 3819 [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged]; 3820 return; 3821 } 3822 3823 [self _updateMouseoverWithFakeEvent]; 3824} 3825 3826- (BOOL)isHoverFeedbackSuspended 3827{ 3828 return _private->hoverFeedbackSuspended; 3829} 3830 3831- (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady 3832{ 3833 // by setting this to NO, calls to mainFrameDocument are forced to return nil 3834 // setting this to YES lets it return the actual DOMDocument value 3835 // we use this to tell NSTreeController to reset its observers and clear its state 3836 if (_private->mainFrameDocumentReady == mainFrameDocumentReady) 3837 return; 3838 [self _willChangeValueForKey:_WebMainFrameDocumentKey]; 3839 _private->mainFrameDocumentReady = mainFrameDocumentReady; 3840 [self _didChangeValueForKey:_WebMainFrameDocumentKey]; 3841 // this will cause observers to call mainFrameDocument where this flag will be checked 3842} 3843 3844// This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it 3845// until the day comes when we're no longer supporting Mail on Tiger. 3846- (WebFrame *)_frameForCurrentSelection 3847{ 3848 return [self _selectedOrMainFrame]; 3849} 3850 3851- (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements 3852{ 3853 _private->tabKeyCyclesThroughElementsChanged = YES; 3854 if (_private->page) 3855 _private->page->setTabKeyCyclesThroughElements(cyclesElements); 3856} 3857 3858- (BOOL)tabKeyCyclesThroughElements 3859{ 3860 return _private->page && _private->page->tabKeyCyclesThroughElements(); 3861} 3862 3863- (void)setScriptDebugDelegate:(id)delegate 3864{ 3865 _private->scriptDebugDelegate = delegate; 3866 [self _cacheScriptDebugDelegateImplementations]; 3867 3868 if (delegate) 3869 [self _attachScriptDebuggerToAllFrames]; 3870 else 3871 [self _detachScriptDebuggerFromAllFrames]; 3872} 3873 3874- (id)scriptDebugDelegate 3875{ 3876 return _private->scriptDebugDelegate; 3877} 3878 3879- (BOOL)shouldClose 3880{ 3881 Frame* coreFrame = [self _mainCoreFrame]; 3882 if (!coreFrame) 3883 return YES; 3884 return coreFrame->shouldClose(); 3885} 3886 3887static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue jsValue) 3888{ 3889 NSAppleEventDescriptor* aeDesc = 0; 3890 if (jsValue.isBoolean()) 3891 return [NSAppleEventDescriptor descriptorWithBoolean:jsValue.getBoolean()]; 3892 if (jsValue.isString()) 3893 return [NSAppleEventDescriptor descriptorWithString:String(jsValue.getString())]; 3894 if (jsValue.isNumber()) { 3895 double value = jsValue.uncheckedGetNumber(); 3896 int intValue = value; 3897 if (value == intValue) 3898 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)]; 3899 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)]; 3900 } 3901 if (jsValue.isObject()) { 3902 JSObject* object = jsValue.getObject(); 3903 if (object->inherits(&DateInstance::info)) { 3904 DateInstance* date = static_cast<DateInstance*>(object); 3905 double ms = 0; 3906 int tzOffset = 0; 3907 if (date->getTime(ms, tzOffset)) { 3908 CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970; 3909 LongDateTime ldt; 3910 if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt)) 3911 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)]; 3912 } 3913 } 3914 else if (object->inherits(&JSArray::info)) { 3915 DEFINE_STATIC_LOCAL(HashSet<JSObject*>, visitedElems, ()); 3916 if (!visitedElems.contains(object)) { 3917 visitedElems.add(object); 3918 3919 JSArray* array = static_cast<JSArray*>(object); 3920 aeDesc = [NSAppleEventDescriptor listDescriptor]; 3921 unsigned numItems = array->length(); 3922 for (unsigned i = 0; i < numItems; ++i) 3923 [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->get(exec, i)) atIndex:0]; 3924 3925 visitedElems.remove(object); 3926 return aeDesc; 3927 } 3928 } 3929 JSValue primitive = object->toPrimitive(exec); 3930 if (exec->hadException()) { 3931 exec->clearException(); 3932 return [NSAppleEventDescriptor nullDescriptor]; 3933 } 3934 return aeDescFromJSValue(exec, primitive); 3935 } 3936 if (jsValue.isUndefined()) 3937 return [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue]; 3938 ASSERT(jsValue.isNull()); 3939 return [NSAppleEventDescriptor nullDescriptor]; 3940} 3941 3942- (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script 3943{ 3944 Frame* coreFrame = [self _mainCoreFrame]; 3945 if (!coreFrame) 3946 return nil; 3947 if (!coreFrame->document()) 3948 return nil; 3949 JSValue result = coreFrame->loader()->executeScript(script, true).jsValue(); 3950 if (!result) // FIXME: pass errors 3951 return 0; 3952 JSLock lock(SilenceAssertionsOnly); 3953 return aeDescFromJSValue(coreFrame->script()->globalObject()->globalExec(), result); 3954} 3955 3956- (BOOL)canMarkAllTextMatches 3957{ 3958 WebFrame *frame = [self mainFrame]; 3959 do { 3960 id <WebDocumentView> view = [[frame frameView] documentView]; 3961 if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)]) 3962 return NO; 3963 3964 frame = incrementFrame(frame, YES, NO); 3965 } while (frame); 3966 3967 return YES; 3968} 3969 3970- (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit 3971{ 3972 WebFrame *frame = [self mainFrame]; 3973 unsigned matchCount = 0; 3974 do { 3975 id <WebDocumentView> view = [[frame frameView] documentView]; 3976 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) { 3977 [(NSView <WebMultipleTextMatches>*)view setMarkedTextMatchesAreHighlighted:highlight]; 3978 3979 ASSERT(limit == 0 || matchCount < limit); 3980 matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount]; 3981 3982 // Stop looking if we've reached the limit. A limit of 0 means no limit. 3983 if (limit > 0 && matchCount >= limit) 3984 break; 3985 } 3986 3987 frame = incrementFrame(frame, YES, NO); 3988 } while (frame); 3989 3990 return matchCount; 3991} 3992 3993- (void)unmarkAllTextMatches 3994{ 3995 WebFrame *frame = [self mainFrame]; 3996 do { 3997 id <WebDocumentView> view = [[frame frameView] documentView]; 3998 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) 3999 [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches]; 4000 4001 frame = incrementFrame(frame, YES, NO); 4002 } while (frame); 4003} 4004 4005- (NSArray *)rectsForTextMatches 4006{ 4007 NSMutableArray *result = [NSMutableArray array]; 4008 WebFrame *frame = [self mainFrame]; 4009 do { 4010 id <WebDocumentView> view = [[frame frameView] documentView]; 4011 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) { 4012 NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view; 4013 NSRect documentViewVisibleRect = [documentView visibleRect]; 4014 NSArray *originalRects = [documentView rectsForTextMatches]; 4015 unsigned rectCount = [originalRects count]; 4016 unsigned rectIndex; 4017 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 4018 for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) { 4019 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue]; 4020 // Clip rect to document view's visible rect so rect is confined to subframe 4021 r = NSIntersectionRect(r, documentViewVisibleRect); 4022 if (NSIsEmptyRect(r)) 4023 continue; 4024 4025 // Convert rect to our coordinate system 4026 r = [documentView convertRect:r toView:self]; 4027 [result addObject:[NSValue valueWithRect:r]]; 4028 if (rectIndex % 10 == 0) { 4029 [pool drain]; 4030 pool = [[NSAutoreleasePool alloc] init]; 4031 } 4032 } 4033 [pool drain]; 4034 } 4035 4036 frame = incrementFrame(frame, YES, NO); 4037 } while (frame); 4038 4039 return result; 4040} 4041 4042- (void)scrollDOMRangeToVisible:(DOMRange *)range 4043{ 4044 [[[[range startContainer] ownerDocument] webFrame] _scrollDOMRangeToVisible:range]; 4045} 4046 4047- (BOOL)allowsUndo 4048{ 4049 return _private->allowsUndo; 4050} 4051 4052- (void)setAllowsUndo:(BOOL)flag 4053{ 4054 _private->allowsUndo = flag; 4055} 4056 4057- (void)setPageSizeMultiplier:(float)m 4058{ 4059 [self _setZoomMultiplier:m isTextOnly:NO]; 4060} 4061 4062- (float)pageSizeMultiplier 4063{ 4064 return ![self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f; 4065} 4066 4067- (BOOL)canZoomPageIn 4068{ 4069 return [self _canZoomIn:NO]; 4070} 4071 4072- (IBAction)zoomPageIn:(id)sender 4073{ 4074 return [self _zoomIn:sender isTextOnly:NO]; 4075} 4076 4077- (BOOL)canZoomPageOut 4078{ 4079 return [self _canZoomOut:NO]; 4080} 4081 4082- (IBAction)zoomPageOut:(id)sender 4083{ 4084 return [self _zoomOut:sender isTextOnly:NO]; 4085} 4086 4087- (BOOL)canResetPageZoom 4088{ 4089 return [self _canResetZoom:NO]; 4090} 4091 4092- (IBAction)resetPageZoom:(id)sender 4093{ 4094 return [self _resetZoom:sender isTextOnly:NO]; 4095} 4096 4097- (void)setMediaVolume:(float)volume 4098{ 4099 if (_private->page) 4100 _private->page->setMediaVolume(volume); 4101} 4102 4103- (float)mediaVolume 4104{ 4105 if (!_private->page) 4106 return 0; 4107 4108 return _private->page->mediaVolume(); 4109} 4110 4111@end 4112 4113@implementation WebView (WebViewPrintingPrivate) 4114 4115- (float)_headerHeight 4116{ 4117 return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:)); 4118} 4119 4120- (float)_footerHeight 4121{ 4122 return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:)); 4123} 4124 4125- (void)_drawHeaderInRect:(NSRect)rect 4126{ 4127#ifdef DEBUG_HEADER_AND_FOOTER 4128 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4129 [currentContext saveGraphicsState]; 4130 [[NSColor yellowColor] set]; 4131 NSRectFill(rect); 4132 [currentContext restoreGraphicsState]; 4133#endif 4134 4135 SEL selector = @selector(webView:drawHeaderInRect:); 4136 if (![_private->UIDelegate respondsToSelector:selector]) 4137 return; 4138 4139 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4140 [currentContext saveGraphicsState]; 4141 4142 NSRectClip(rect); 4143 CallUIDelegate(self, selector, rect); 4144 4145 [currentContext restoreGraphicsState]; 4146} 4147 4148- (void)_drawFooterInRect:(NSRect)rect 4149{ 4150#ifdef DEBUG_HEADER_AND_FOOTER 4151 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4152 [currentContext saveGraphicsState]; 4153 [[NSColor cyanColor] set]; 4154 NSRectFill(rect); 4155 [currentContext restoreGraphicsState]; 4156#endif 4157 4158 SEL selector = @selector(webView:drawFooterInRect:); 4159 if (![_private->UIDelegate respondsToSelector:selector]) 4160 return; 4161 4162 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4163 [currentContext saveGraphicsState]; 4164 4165 NSRectClip(rect); 4166 CallUIDelegate(self, selector, rect); 4167 4168 [currentContext restoreGraphicsState]; 4169} 4170 4171- (void)_adjustPrintingMarginsForHeaderAndFooter 4172{ 4173 NSPrintOperation *op = [NSPrintOperation currentOperation]; 4174 NSPrintInfo *info = [op printInfo]; 4175 NSMutableDictionary *infoDictionary = [info dictionary]; 4176 4177 // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the 4178 // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087), 4179 // we stash away the unmodified top and bottom margins the first time this method is called, and we read from 4180 // those stashed-away values on subsequent calls. 4181 float originalTopMargin; 4182 float originalBottomMargin; 4183 NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey]; 4184 if (!originalTopMarginNumber) { 4185 ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]); 4186 originalTopMargin = [info topMargin]; 4187 originalBottomMargin = [info bottomMargin]; 4188 [infoDictionary setObject:[NSNumber numberWithFloat:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey]; 4189 [infoDictionary setObject:[NSNumber numberWithFloat:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey]; 4190 } else { 4191 ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]); 4192 ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]); 4193 originalTopMargin = [originalTopMarginNumber floatValue]; 4194 originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] floatValue]; 4195 } 4196 4197 float scale = [op _web_pageSetupScaleFactor]; 4198 [info setTopMargin:originalTopMargin + [self _headerHeight] * scale]; 4199 [info setBottomMargin:originalBottomMargin + [self _footerHeight] * scale]; 4200} 4201 4202- (void)_drawHeaderAndFooter 4203{ 4204 // The header and footer rect height scales with the page, but the width is always 4205 // all the way across the printed page (inset by printing margins). 4206 NSPrintOperation *op = [NSPrintOperation currentOperation]; 4207 float scale = [op _web_pageSetupScaleFactor]; 4208 NSPrintInfo *printInfo = [op printInfo]; 4209 NSSize paperSize = [printInfo paperSize]; 4210 float headerFooterLeft = [printInfo leftMargin]/scale; 4211 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale; 4212 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] , 4213 headerFooterWidth, [self _footerHeight]); 4214 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale, 4215 headerFooterWidth, [self _headerHeight]); 4216 4217 [self _drawHeaderInRect:headerRect]; 4218 [self _drawFooterInRect:footerRect]; 4219} 4220@end 4221 4222@implementation WebView (WebDebugBinding) 4223 4224- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context 4225{ 4226 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context); 4227 [super addObserver:anObserver forKeyPath:keyPath options:options context:context]; 4228} 4229 4230- (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath 4231{ 4232 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath); 4233 [super removeObserver:anObserver forKeyPath:keyPath]; 4234} 4235 4236@end 4237 4238//========================================================================================== 4239// Editing 4240 4241@implementation WebView (WebViewCSS) 4242 4243- (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement 4244{ 4245 // FIXME: is this the best level for this conversion? 4246 if (pseudoElement == nil) 4247 pseudoElement = @""; 4248 4249 return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement]; 4250} 4251 4252@end 4253 4254@implementation WebView (WebViewEditing) 4255 4256- (DOMRange *)editableDOMRangeForPoint:(NSPoint)point 4257{ 4258 Page* page = core(self); 4259 if (!page) 4260 return nil; 4261 return kit(page->mainFrame()->editor()->rangeForPoint(IntPoint([self convertPoint:point toView:nil])).get()); 4262} 4263 4264- (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag 4265{ 4266 // FIXME: This quirk is needed due to <rdar://problem/4985321> - We can phase it out once Aperture can adopt the new behavior on their end 4267 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"]) 4268 return YES; 4269 return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag]; 4270} 4271 4272- (BOOL)maintainsInactiveSelection 4273{ 4274 return NO; 4275} 4276 4277- (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity 4278{ 4279 Frame* coreFrame = core([self _selectedOrMainFrame]); 4280 if (!coreFrame) 4281 return; 4282 4283 if (range == nil) 4284 coreFrame->selection()->clear(); 4285 else { 4286 // Derive the frame to use from the range passed in. 4287 // Using _selectedOrMainFrame could give us a different document than 4288 // the one the range uses. 4289 coreFrame = core([range startContainer])->document()->frame(); 4290 if (!coreFrame) 4291 return; 4292 4293 coreFrame->selection()->setSelectedRange(core(range), core(selectionAffinity), true); 4294 } 4295} 4296 4297- (DOMRange *)selectedDOMRange 4298{ 4299 Frame* coreFrame = core([self _selectedOrMainFrame]); 4300 if (!coreFrame) 4301 return nil; 4302 return kit(coreFrame->selection()->toNormalizedRange().get()); 4303} 4304 4305- (NSSelectionAffinity)selectionAffinity 4306{ 4307 Frame* coreFrame = core([self _selectedOrMainFrame]); 4308 if (!coreFrame) 4309 return NSSelectionAffinityDownstream; 4310 return kit(coreFrame->selection()->affinity()); 4311} 4312 4313- (void)setEditable:(BOOL)flag 4314{ 4315 if (_private->editable != flag) { 4316 _private->editable = flag; 4317 if (!_private->tabKeyCyclesThroughElementsChanged && _private->page) 4318 _private->page->setTabKeyCyclesThroughElements(!flag); 4319 Frame* mainFrame = [self _mainCoreFrame]; 4320 if (mainFrame) { 4321 if (flag) { 4322 mainFrame->applyEditingStyleToBodyElement(); 4323 // If the WebView is made editable and the selection is empty, set it to something. 4324 if (![self selectedDOMRange]) 4325 mainFrame->setSelectionFromNone(); 4326 } else 4327 mainFrame->removeEditingStyleFromBodyElement(); 4328 } 4329 } 4330} 4331 4332- (BOOL)isEditable 4333{ 4334 return _private->editable; 4335} 4336 4337- (void)setTypingStyle:(DOMCSSStyleDeclaration *)style 4338{ 4339 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to 4340 // change the API to allow this. 4341 [[self _selectedOrMainFrame] _setTypingStyle:style withUndoAction:EditActionUnspecified]; 4342} 4343 4344- (DOMCSSStyleDeclaration *)typingStyle 4345{ 4346 return [[self _selectedOrMainFrame] _typingStyle]; 4347} 4348 4349- (void)setSmartInsertDeleteEnabled:(BOOL)flag 4350{ 4351 if (_private->smartInsertDeleteEnabled != flag) { 4352 _private->smartInsertDeleteEnabled = flag; 4353 [[NSUserDefaults standardUserDefaults] setBool:_private->smartInsertDeleteEnabled forKey:WebSmartInsertDeleteEnabled]; 4354 } 4355 if (flag) 4356 [self setSelectTrailingWhitespaceEnabled:false]; 4357} 4358 4359- (BOOL)smartInsertDeleteEnabled 4360{ 4361 return _private->smartInsertDeleteEnabled; 4362} 4363 4364- (void)setContinuousSpellCheckingEnabled:(BOOL)flag 4365{ 4366 if (continuousSpellCheckingEnabled != flag) { 4367 continuousSpellCheckingEnabled = flag; 4368 [[NSUserDefaults standardUserDefaults] setBool:continuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled]; 4369 } 4370 4371 if ([self isContinuousSpellCheckingEnabled]) { 4372 [[self class] _preflightSpellChecker]; 4373 } else { 4374 [[self mainFrame] _unmarkAllMisspellings]; 4375 } 4376} 4377 4378- (BOOL)isContinuousSpellCheckingEnabled 4379{ 4380 return (continuousSpellCheckingEnabled && [self _continuousCheckingAllowed]); 4381} 4382 4383- (NSInteger)spellCheckerDocumentTag 4384{ 4385 if (!_private->hasSpellCheckerDocumentTag) { 4386 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag]; 4387 _private->hasSpellCheckerDocumentTag = YES; 4388 } 4389 return _private->spellCheckerDocumentTag; 4390} 4391 4392- (NSUndoManager *)undoManager 4393{ 4394 if (!_private->allowsUndo) 4395 return nil; 4396 4397 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self]; 4398 if (undoManager) 4399 return undoManager; 4400 4401 return [super undoManager]; 4402} 4403 4404- (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector 4405{ 4406 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; 4407 if ([_private->editingDelegate respondsToSelector:selector]) 4408 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self]; 4409} 4410 4411- (void)setEditingDelegate:(id)delegate 4412{ 4413 if (_private->editingDelegate == delegate) 4414 return; 4415 4416 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; 4417 4418 // remove notifications from current delegate 4419 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self]; 4420 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self]; 4421 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self]; 4422 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self]; 4423 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self]; 4424 4425 _private->editingDelegate = delegate; 4426 [_private->editingDelegateForwarder release]; 4427 _private->editingDelegateForwarder = nil; 4428 4429 // add notifications for new delegate 4430 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)]; 4431 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)]; 4432 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)]; 4433 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)]; 4434 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)]; 4435} 4436 4437- (id)editingDelegate 4438{ 4439 return _private->editingDelegate; 4440} 4441 4442- (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text 4443{ 4444 // FIXME: Should this really be attached to the document with the current selection? 4445 DOMCSSStyleDeclaration *decl = [[[self _selectedOrMainFrame] DOMDocument] createCSSStyleDeclaration]; 4446 [decl setCssText:text]; 4447 return decl; 4448} 4449 4450@end 4451 4452@implementation WebView (WebViewGrammarChecking) 4453 4454// FIXME: This method should be merged into WebViewEditing when we're not in API freeze 4455- (BOOL)isGrammarCheckingEnabled 4456{ 4457#ifdef BUILDING_ON_TIGER 4458 return NO; 4459#else 4460 return grammarCheckingEnabled; 4461#endif 4462} 4463 4464#ifndef BUILDING_ON_TIGER 4465// FIXME: This method should be merged into WebViewEditing when we're not in API freeze 4466- (void)setGrammarCheckingEnabled:(BOOL)flag 4467{ 4468 if (grammarCheckingEnabled == flag) 4469 return; 4470 4471 grammarCheckingEnabled = flag; 4472 [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled]; 4473 4474#ifndef BUILDING_ON_LEOPARD 4475 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4476#else 4477 NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker]; 4478 if ([spellChecker respondsToSelector:@selector(_updateGrammar)]) 4479 [spellChecker performSelector:@selector(_updateGrammar)]; 4480#endif 4481 4482 // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here 4483 // because grammar checking only occurs on code paths that already preflight spell checking appropriately. 4484 4485 if (![self isGrammarCheckingEnabled]) 4486 [[self mainFrame] _unmarkAllBadGrammar]; 4487} 4488 4489// FIXME: This method should be merged into WebIBActions when we're not in API freeze 4490- (void)toggleGrammarChecking:(id)sender 4491{ 4492 [self setGrammarCheckingEnabled:![self isGrammarCheckingEnabled]]; 4493} 4494#endif 4495 4496@end 4497 4498@implementation WebView (WebViewTextChecking) 4499 4500- (BOOL)isAutomaticQuoteSubstitutionEnabled 4501{ 4502#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4503 return NO; 4504#else 4505 return automaticQuoteSubstitutionEnabled; 4506#endif 4507} 4508 4509- (BOOL)isAutomaticLinkDetectionEnabled 4510{ 4511#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4512 return NO; 4513#else 4514 return automaticLinkDetectionEnabled; 4515#endif 4516} 4517 4518- (BOOL)isAutomaticDashSubstitutionEnabled 4519{ 4520#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4521 return NO; 4522#else 4523 return automaticDashSubstitutionEnabled; 4524#endif 4525} 4526 4527- (BOOL)isAutomaticTextReplacementEnabled 4528{ 4529#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4530 return NO; 4531#else 4532 return automaticTextReplacementEnabled; 4533#endif 4534} 4535 4536- (BOOL)isAutomaticSpellingCorrectionEnabled 4537{ 4538#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4539 return NO; 4540#else 4541 return automaticSpellingCorrectionEnabled; 4542#endif 4543} 4544 4545#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 4546 4547- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag 4548{ 4549 if (automaticQuoteSubstitutionEnabled == flag) 4550 return; 4551 automaticQuoteSubstitutionEnabled = flag; 4552 [[NSUserDefaults standardUserDefaults] setBool:automaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled]; 4553 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4554} 4555 4556- (void)toggleAutomaticQuoteSubstitution:(id)sender 4557{ 4558 [self setAutomaticQuoteSubstitutionEnabled:![self isAutomaticQuoteSubstitutionEnabled]]; 4559} 4560 4561- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag 4562{ 4563 if (automaticLinkDetectionEnabled == flag) 4564 return; 4565 automaticLinkDetectionEnabled = flag; 4566 [[NSUserDefaults standardUserDefaults] setBool:automaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled]; 4567 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4568} 4569 4570- (void)toggleAutomaticLinkDetection:(id)sender 4571{ 4572 [self setAutomaticLinkDetectionEnabled:![self isAutomaticLinkDetectionEnabled]]; 4573} 4574 4575- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag 4576{ 4577 if (automaticDashSubstitutionEnabled == flag) 4578 return; 4579 automaticDashSubstitutionEnabled = flag; 4580 [[NSUserDefaults standardUserDefaults] setBool:automaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled]; 4581 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4582} 4583 4584- (void)toggleAutomaticDashSubstitution:(id)sender 4585{ 4586 [self setAutomaticDashSubstitutionEnabled:![self isAutomaticDashSubstitutionEnabled]]; 4587} 4588 4589- (void)setAutomaticTextReplacementEnabled:(BOOL)flag 4590{ 4591 if (automaticTextReplacementEnabled == flag) 4592 return; 4593 automaticTextReplacementEnabled = flag; 4594 [[NSUserDefaults standardUserDefaults] setBool:automaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled]; 4595 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4596} 4597 4598- (void)toggleAutomaticTextReplacement:(id)sender 4599{ 4600 [self setAutomaticTextReplacementEnabled:![self isAutomaticTextReplacementEnabled]]; 4601} 4602 4603- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag 4604{ 4605 if (automaticSpellingCorrectionEnabled == flag) 4606 return; 4607 automaticSpellingCorrectionEnabled = flag; 4608 [[NSUserDefaults standardUserDefaults] setBool:automaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled]; 4609 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4610} 4611 4612- (void)toggleAutomaticSpellingCorrection:(id)sender 4613{ 4614 [self setAutomaticSpellingCorrectionEnabled:![self isAutomaticSpellingCorrectionEnabled]]; 4615} 4616 4617#endif 4618 4619@end 4620 4621@implementation WebView (WebViewUndoableEditing) 4622 4623- (void)replaceSelectionWithNode:(DOMNode *)node 4624{ 4625 [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO]; 4626} 4627 4628- (void)replaceSelectionWithText:(NSString *)text 4629{ 4630 [[self _selectedOrMainFrame] _replaceSelectionWithText:text selectReplacement:YES smartReplace:NO]; 4631} 4632 4633- (void)replaceSelectionWithMarkupString:(NSString *)markupString 4634{ 4635 [[self _selectedOrMainFrame] _replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO]; 4636} 4637 4638- (void)replaceSelectionWithArchive:(WebArchive *)archive 4639{ 4640 [[[self _selectedOrMainFrame] _dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES]; 4641} 4642 4643- (void)deleteSelection 4644{ 4645 WebFrame *webFrame = [self _selectedOrMainFrame]; 4646 Frame* coreFrame = core(webFrame); 4647 if (coreFrame) 4648 coreFrame->editor()->deleteSelectionWithSmartDelete([(WebHTMLView *)[[webFrame frameView] documentView] _canSmartCopyOrDelete]); 4649} 4650 4651- (void)applyStyle:(DOMCSSStyleDeclaration *)style 4652{ 4653 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to 4654 // change the API to allow this. 4655 WebFrame *webFrame = [self _selectedOrMainFrame]; 4656 Frame* coreFrame = core(webFrame); 4657 if (coreFrame) 4658 coreFrame->editor()->applyStyle(core(style)); 4659} 4660 4661@end 4662 4663@implementation WebView (WebViewEditingActions) 4664 4665- (void)_performResponderOperation:(SEL)selector with:(id)parameter 4666{ 4667 static BOOL reentered = NO; 4668 if (reentered) { 4669 [[self nextResponder] tryToPerform:selector with:parameter]; 4670 return; 4671 } 4672 4673 // There are two possibilities here. 4674 // 4675 // One is that WebView has been called in its role as part of the responder chain. 4676 // In that case, it's fine to call the first responder and end up calling down the 4677 // responder chain again. Later we will return here with reentered = YES and continue 4678 // past the WebView. 4679 // 4680 // The other is that we are being called directly, in which case we want to pass the 4681 // selector down to the view inside us that can handle it, and continue down the 4682 // responder chain as usual. 4683 4684 // Pass this selector down to the first responder. 4685 NSResponder *responder = [self _responderForResponderOperations]; 4686 reentered = YES; 4687 [responder tryToPerform:selector with:parameter]; 4688 reentered = NO; 4689} 4690 4691#define FORWARD(name) \ 4692 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; } 4693 4694FOR_EACH_RESPONDER_SELECTOR(FORWARD) 4695 4696- (void)insertText:(NSString *)text 4697{ 4698 [self _performResponderOperation:_cmd with:text]; 4699} 4700 4701@end 4702 4703@implementation WebView (WebViewEditingInMail) 4704 4705- (void)_insertNewlineInQuotedContent 4706{ 4707 [[self _selectedOrMainFrame] _insertParagraphSeparatorInQuotedContent]; 4708} 4709 4710- (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle 4711{ 4712 [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle]; 4713} 4714 4715- (BOOL)_selectionIsCaret 4716{ 4717 Frame* coreFrame = core([self _selectedOrMainFrame]); 4718 if (!coreFrame) 4719 return NO; 4720 return coreFrame->selection()->isCaret(); 4721} 4722 4723- (BOOL)_selectionIsAll 4724{ 4725 Frame* coreFrame = core([self _selectedOrMainFrame]); 4726 if (!coreFrame) 4727 return NO; 4728 return coreFrame->selection()->isAll(MayLeaveEditableContent); 4729} 4730 4731@end 4732 4733static WebFrameView *containingFrameView(NSView *view) 4734{ 4735 while (view && ![view isKindOfClass:[WebFrameView class]]) 4736 view = [view superview]; 4737 return (WebFrameView *)view; 4738} 4739 4740@implementation WebView (WebFileInternal) 4741 4742+ (void)_setCacheModel:(WebCacheModel)cacheModel 4743{ 4744 if (s_didSetCacheModel && cacheModel == s_cacheModel) 4745 return; 4746 4747 NSString *nsurlCacheDirectory = (NSString *)WebCFAutorelease(WKCopyFoundationCacheDirectory()); 4748 if (!nsurlCacheDirectory) 4749 nsurlCacheDirectory = NSHomeDirectory(); 4750 4751 // As a fudge factor, use 1000 instead of 1024, in case the reported byte 4752 // count doesn't align exactly to a megabyte boundary. 4753 uint64_t memSize = WebMemorySize() / 1024 / 1000; 4754 unsigned long long diskFreeSize = WebVolumeFreeSize(nsurlCacheDirectory) / 1024 / 1000; 4755 NSURLCache *nsurlCache = [NSURLCache sharedURLCache]; 4756 4757 unsigned cacheTotalCapacity = 0; 4758 unsigned cacheMinDeadCapacity = 0; 4759 unsigned cacheMaxDeadCapacity = 0; 4760 double deadDecodedDataDeletionInterval = 0; 4761 4762 unsigned pageCacheCapacity = 0; 4763 4764 NSUInteger nsurlCacheMemoryCapacity = 0; 4765 NSUInteger nsurlCacheDiskCapacity = 0; 4766 4767 switch (cacheModel) { 4768 case WebCacheModelDocumentViewer: { 4769 // Page cache capacity (in pages) 4770 pageCacheCapacity = 0; 4771 4772 // Object cache capacities (in bytes) 4773 if (memSize >= 2048) 4774 cacheTotalCapacity = 96 * 1024 * 1024; 4775 else if (memSize >= 1536) 4776 cacheTotalCapacity = 64 * 1024 * 1024; 4777 else if (memSize >= 1024) 4778 cacheTotalCapacity = 32 * 1024 * 1024; 4779 else if (memSize >= 512) 4780 cacheTotalCapacity = 16 * 1024 * 1024; 4781 4782 cacheMinDeadCapacity = 0; 4783 cacheMaxDeadCapacity = 0; 4784 4785 // Foundation memory cache capacity (in bytes) 4786 nsurlCacheMemoryCapacity = 0; 4787 4788 // Foundation disk cache capacity (in bytes) 4789 nsurlCacheDiskCapacity = [nsurlCache diskCapacity]; 4790 4791 break; 4792 } 4793 case WebCacheModelDocumentBrowser: { 4794 // Page cache capacity (in pages) 4795 if (memSize >= 1024) 4796 pageCacheCapacity = 3; 4797 else if (memSize >= 512) 4798 pageCacheCapacity = 2; 4799 else if (memSize >= 256) 4800 pageCacheCapacity = 1; 4801 else 4802 pageCacheCapacity = 0; 4803 4804 // Object cache capacities (in bytes) 4805 if (memSize >= 2048) 4806 cacheTotalCapacity = 96 * 1024 * 1024; 4807 else if (memSize >= 1536) 4808 cacheTotalCapacity = 64 * 1024 * 1024; 4809 else if (memSize >= 1024) 4810 cacheTotalCapacity = 32 * 1024 * 1024; 4811 else if (memSize >= 512) 4812 cacheTotalCapacity = 16 * 1024 * 1024; 4813 4814 cacheMinDeadCapacity = cacheTotalCapacity / 8; 4815 cacheMaxDeadCapacity = cacheTotalCapacity / 4; 4816 4817 // Foundation memory cache capacity (in bytes) 4818 if (memSize >= 2048) 4819 nsurlCacheMemoryCapacity = 4 * 1024 * 1024; 4820 else if (memSize >= 1024) 4821 nsurlCacheMemoryCapacity = 2 * 1024 * 1024; 4822 else if (memSize >= 512) 4823 nsurlCacheMemoryCapacity = 1 * 1024 * 1024; 4824 else 4825 nsurlCacheMemoryCapacity = 512 * 1024; 4826 4827 // Foundation disk cache capacity (in bytes) 4828 if (diskFreeSize >= 16384) 4829 nsurlCacheDiskCapacity = 50 * 1024 * 1024; 4830 else if (diskFreeSize >= 8192) 4831 nsurlCacheDiskCapacity = 40 * 1024 * 1024; 4832 else if (diskFreeSize >= 4096) 4833 nsurlCacheDiskCapacity = 30 * 1024 * 1024; 4834 else 4835 nsurlCacheDiskCapacity = 20 * 1024 * 1024; 4836 4837 break; 4838 } 4839 case WebCacheModelPrimaryWebBrowser: { 4840 // Page cache capacity (in pages) 4841 // (Research indicates that value / page drops substantially after 3 pages.) 4842 if (memSize >= 2048) 4843 pageCacheCapacity = 5; 4844 else if (memSize >= 1024) 4845 pageCacheCapacity = 4; 4846 else if (memSize >= 512) 4847 pageCacheCapacity = 3; 4848 else if (memSize >= 256) 4849 pageCacheCapacity = 2; 4850 else 4851 pageCacheCapacity = 1; 4852 4853 // Object cache capacities (in bytes) 4854 // (Testing indicates that value / MB depends heavily on content and 4855 // browsing pattern. Even growth above 128MB can have substantial 4856 // value / MB for some content / browsing patterns.) 4857 if (memSize >= 2048) 4858 cacheTotalCapacity = 128 * 1024 * 1024; 4859 else if (memSize >= 1536) 4860 cacheTotalCapacity = 96 * 1024 * 1024; 4861 else if (memSize >= 1024) 4862 cacheTotalCapacity = 64 * 1024 * 1024; 4863 else if (memSize >= 512) 4864 cacheTotalCapacity = 32 * 1024 * 1024; 4865 4866 cacheMinDeadCapacity = cacheTotalCapacity / 4; 4867 cacheMaxDeadCapacity = cacheTotalCapacity / 2; 4868 4869 // This code is here to avoid a PLT regression. We can remove it if we 4870 // can prove that the overall system gain would justify the regression. 4871 cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity); 4872 4873 deadDecodedDataDeletionInterval = 60; 4874 4875 // Foundation memory cache capacity (in bytes) 4876 // (These values are small because WebCore does most caching itself.) 4877 if (memSize >= 1024) 4878 nsurlCacheMemoryCapacity = 4 * 1024 * 1024; 4879 else if (memSize >= 512) 4880 nsurlCacheMemoryCapacity = 2 * 1024 * 1024; 4881 else if (memSize >= 256) 4882 nsurlCacheMemoryCapacity = 1 * 1024 * 1024; 4883 else 4884 nsurlCacheMemoryCapacity = 512 * 1024; 4885 4886 // Foundation disk cache capacity (in bytes) 4887 if (diskFreeSize >= 16384) 4888 nsurlCacheDiskCapacity = 175 * 1024 * 1024; 4889 else if (diskFreeSize >= 8192) 4890 nsurlCacheDiskCapacity = 150 * 1024 * 1024; 4891 else if (diskFreeSize >= 4096) 4892 nsurlCacheDiskCapacity = 125 * 1024 * 1024; 4893 else if (diskFreeSize >= 2048) 4894 nsurlCacheDiskCapacity = 100 * 1024 * 1024; 4895 else if (diskFreeSize >= 1024) 4896 nsurlCacheDiskCapacity = 75 * 1024 * 1024; 4897 else 4898 nsurlCacheDiskCapacity = 50 * 1024 * 1024; 4899 4900 break; 4901 } 4902 default: 4903 ASSERT_NOT_REACHED(); 4904 }; 4905 4906#ifdef BUILDING_ON_TIGER 4907 // Don't use a big Foundation disk cache on Tiger because, according to the 4908 // PLT, the Foundation disk cache on Tiger is slower than the network. 4909 nsurlCacheDiskCapacity = [nsurlCache diskCapacity]; 4910#endif 4911 4912 // Don't shrink a big disk cache, since that would cause churn. 4913 nsurlCacheDiskCapacity = max(nsurlCacheDiskCapacity, [nsurlCache diskCapacity]); 4914 4915 cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity); 4916 cache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval); 4917 pageCache()->setCapacity(pageCacheCapacity); 4918 [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity]; 4919 [nsurlCache setDiskCapacity:nsurlCacheDiskCapacity]; 4920 4921 s_cacheModel = cacheModel; 4922 s_didSetCacheModel = YES; 4923} 4924 4925+ (WebCacheModel)_cacheModel 4926{ 4927 return s_cacheModel; 4928} 4929 4930+ (WebCacheModel)_didSetCacheModel 4931{ 4932 return s_didSetCacheModel; 4933} 4934 4935+ (WebCacheModel)_maxCacheModelInAnyInstance 4936{ 4937 WebCacheModel cacheModel = WebCacheModelDocumentViewer; 4938 NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator]; 4939 while (WebPreferences *preferences = [[enumerator nextObject] preferences]) 4940 cacheModel = max(cacheModel, [preferences cacheModel]); 4941 return cacheModel; 4942} 4943 4944+ (void)_preferencesChangedNotification:(NSNotification *)notification 4945{ 4946 WebPreferences *preferences = (WebPreferences *)[notification object]; 4947 ASSERT([preferences isKindOfClass:[WebPreferences class]]); 4948 4949 WebCacheModel cacheModel = [preferences cacheModel]; 4950 if (![self _didSetCacheModel] || cacheModel > [self _cacheModel]) 4951 [self _setCacheModel:cacheModel]; 4952 else if (cacheModel < [self _cacheModel]) 4953 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])]; 4954} 4955 4956+ (void)_preferencesRemovedNotification:(NSNotification *)notification 4957{ 4958 WebPreferences *preferences = (WebPreferences *)[notification object]; 4959 ASSERT([preferences isKindOfClass:[WebPreferences class]]); 4960 4961 if ([preferences cacheModel] == [self _cacheModel]) 4962 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])]; 4963} 4964 4965- (WebFrame *)_focusedFrame 4966{ 4967 NSResponder *resp = [[self window] firstResponder]; 4968 if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) { 4969 WebFrameView *frameView = containingFrameView((NSView *)resp); 4970 ASSERT(frameView != nil); 4971 return [frameView webFrame]; 4972 } 4973 4974 return nil; 4975} 4976 4977- (WebFrame *)_selectedOrMainFrame 4978{ 4979 WebFrame *result = [self selectedFrame]; 4980 if (result == nil) 4981 result = [self mainFrame]; 4982 return result; 4983} 4984 4985- (BOOL)_isLoading 4986{ 4987 WebFrame *mainFrame = [self mainFrame]; 4988 return [[mainFrame _dataSource] isLoading] 4989 || [[mainFrame provisionalDataSource] isLoading]; 4990} 4991 4992- (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point 4993{ 4994 if (_private->closed) 4995 return nil; 4996 ASSERT(_private->usesDocumentViews); 4997 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]]; 4998 if (![view isDescendantOf:[[self mainFrame] frameView]]) 4999 return nil; 5000 WebFrameView *frameView = containingFrameView(view); 5001 ASSERT(frameView); 5002 return frameView; 5003} 5004 5005+ (void)_preflightSpellCheckerNow:(id)sender 5006{ 5007 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer]; 5008} 5009 5010+ (void)_preflightSpellChecker 5011{ 5012 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch. 5013 if ([NSSpellChecker sharedSpellCheckerExists]) { 5014 [self _preflightSpellCheckerNow:self]; 5015 } else { 5016 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0]; 5017 } 5018} 5019 5020- (BOOL)_continuousCheckingAllowed 5021{ 5022 static BOOL allowContinuousSpellChecking = YES; 5023 static BOOL readAllowContinuousSpellCheckingDefault = NO; 5024 if (!readAllowContinuousSpellCheckingDefault) { 5025 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) { 5026 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"]; 5027 } 5028 readAllowContinuousSpellCheckingDefault = YES; 5029 } 5030 return allowContinuousSpellChecking; 5031} 5032 5033- (NSResponder *)_responderForResponderOperations 5034{ 5035 NSResponder *responder = [[self window] firstResponder]; 5036 WebFrameView *mainFrameView = [[self mainFrame] frameView]; 5037 5038 // If the current responder is outside of the webview, use our main frameView or its 5039 // document view. We also do this for subviews of self that are siblings of the main 5040 // frameView since clients might insert non-webview-related views there (see 4552713). 5041 if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) { 5042 responder = [mainFrameView documentView]; 5043 if (!responder) 5044 responder = mainFrameView; 5045 } 5046 return responder; 5047} 5048 5049- (void)_openFrameInNewWindowFromMenu:(NSMenuItem *)sender 5050{ 5051 ASSERT_ARG(sender, [sender isKindOfClass:[NSMenuItem class]]); 5052 5053 NSDictionary *element = [sender representedObject]; 5054 ASSERT([element isKindOfClass:[NSDictionary class]]); 5055 5056 WebDataSource *dataSource = [[element objectForKey:WebElementFrameKey] dataSource]; 5057 NSURLRequest *request = [[dataSource request] copy]; 5058 ASSERT(request); 5059 5060 [self _openNewWindowWithRequest:request]; 5061 [request release]; 5062} 5063 5064- (void)_searchWithGoogleFromMenu:(id)sender 5065{ 5066 id documentView = [[[self selectedFrame] frameView] documentView]; 5067 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) { 5068 return; 5069 } 5070 5071 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString]; 5072 if ([selectedString length] == 0) { 5073 return; 5074 } 5075 5076 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; 5077 [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; 5078 NSMutableString *s = [selectedString mutableCopy]; 5079 const unichar nonBreakingSpaceCharacter = 0xA0; 5080 NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1]; 5081 [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])]; 5082 [pasteboard setString:s forType:NSStringPboardType]; 5083 [s release]; 5084 5085 // FIXME: seems fragile to use the service by name, but this is what AppKit does 5086 NSPerformService(@"Search With Google", pasteboard); 5087} 5088 5089- (void)_searchWithSpotlightFromMenu:(id)sender 5090{ 5091 id documentView = [[[self selectedFrame] frameView] documentView]; 5092 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) 5093 return; 5094 5095 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString]; 5096 if ([selectedString length] == 0) { 5097 return; 5098 } 5099 5100 (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions); 5101} 5102 5103#if USE(ACCELERATED_COMPOSITING) 5104- (void)_clearLayerSyncLoopObserver 5105{ 5106 if (!_private->layerSyncRunLoopObserver) 5107 return; 5108 5109 CFRunLoopObserverInvalidate(_private->layerSyncRunLoopObserver); 5110 CFRelease(_private->layerSyncRunLoopObserver); 5111 _private->layerSyncRunLoopObserver = 0; 5112} 5113#endif 5114@end 5115 5116@implementation WebView (WebViewInternal) 5117 5118- (BOOL)_becomingFirstResponderFromOutside 5119{ 5120 return _private->becomingFirstResponderFromOutside; 5121} 5122 5123#if ENABLE(ICONDATABASE) 5124- (void)_receivedIconChangedNotification:(NSNotification *)notification 5125{ 5126 // Get the URL for this notification 5127 NSDictionary *userInfo = [notification userInfo]; 5128 ASSERT([userInfo isKindOfClass:[NSDictionary class]]); 5129 NSString *urlString = [userInfo objectForKey:WebIconNotificationUserInfoURLKey]; 5130 ASSERT([urlString isKindOfClass:[NSString class]]); 5131 5132 // If that URL matches the current main frame, dispatch the delegate call, which will also unregister 5133 // us for this notification 5134 if ([[self mainFrameURL] isEqualTo:urlString]) 5135 [self _dispatchDidReceiveIconFromWebFrame:[self mainFrame]]; 5136} 5137 5138- (void)_registerForIconNotification:(BOOL)listen 5139{ 5140 if (listen) 5141 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_receivedIconChangedNotification:) name:WebIconDatabaseDidAddIconNotification object:nil]; 5142 else 5143 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebIconDatabaseDidAddIconNotification object:nil]; 5144} 5145 5146- (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame 5147{ 5148 // FIXME: This willChangeValueForKey call is too late, because the icon has already changed by now. 5149 [self _willChangeValueForKey:_WebMainFrameIconKey]; 5150 5151 // Since we definitely have an icon and are about to send out the delegate call for that, this WebView doesn't need to listen for the general 5152 // notification any longer 5153 [self _registerForIconNotification:NO]; 5154 5155 WebFrameLoadDelegateImplementationCache* cache = &_private->frameLoadDelegateImplementations; 5156 if (cache->didReceiveIconForFrameFunc) { 5157 Image* image = iconDatabase()->iconForPageURL(core(webFrame)->loader()->url().string(), IntSize(16, 16)); 5158 if (NSImage *icon = webGetNSImage(image, NSMakeSize(16, 16))) 5159 CallFrameLoadDelegate(cache->didReceiveIconForFrameFunc, self, @selector(webView:didReceiveIcon:forFrame:), icon, webFrame); 5160 } 5161 5162 [self _didChangeValueForKey:_WebMainFrameIconKey]; 5163} 5164#endif // ENABLE(ICONDATABASE) 5165 5166// Get the appropriate user-agent string for a particular URL. 5167- (WebCore::String)_userAgentForURL:(const WebCore::KURL&)url 5168{ 5169 if (_private->useSiteSpecificSpoofing) { 5170 // No current site-specific spoofs. 5171 } 5172 5173 if (_private->userAgent.isNull()) 5174 _private->userAgent = [[self class] _standardUserAgentWithApplicationName:_private->applicationNameForUserAgent]; 5175 5176 return _private->userAgent; 5177} 5178 5179- (void)_addObject:(id)object forIdentifier:(unsigned long)identifier 5180{ 5181 ASSERT(!_private->identifierMap.contains(identifier)); 5182 5183 // If the identifier map is initially empty it means we're starting a load 5184 // of something. The semantic is that the web view should be around as long 5185 // as something is loading. Because of that we retain the web view. 5186 if (_private->identifierMap.isEmpty()) 5187 CFRetain(self); 5188 5189 _private->identifierMap.set(identifier, object); 5190} 5191 5192- (id)_objectForIdentifier:(unsigned long)identifier 5193{ 5194 return _private->identifierMap.get(identifier).get(); 5195} 5196 5197- (void)_removeObjectForIdentifier:(unsigned long)identifier 5198{ 5199 ASSERT(_private->identifierMap.contains(identifier)); 5200 _private->identifierMap.remove(identifier); 5201 5202 // If the identifier map is now empty it means we're no longer loading anything 5203 // and we should release the web view. 5204 if (_private->identifierMap.isEmpty()) 5205 CFRelease(self); 5206} 5207 5208- (void)_retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification 5209{ 5210 CFPreferencesAppSynchronize(UniversalAccessDomain); 5211 5212 Boolean keyExistsAndHasValidFormat; 5213 int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, UniversalAccessDomain, &keyExistsAndHasValidFormat); 5214 5215 // The keyboard access mode is reported by two bits: 5216 // Bit 0 is set if feature is on 5217 // Bit 1 is set if full keyboard access works for any control, not just text boxes and lists 5218 // We require both bits to be on. 5219 // I do not know that we would ever get one bit on and the other off since 5220 // checking the checkbox in system preferences which is marked as "Turn on full keyboard access" 5221 // turns on both bits. 5222 _private->_keyboardUIMode = (mode & 0x2) ? KeyboardAccessFull : KeyboardAccessDefault; 5223 5224 // check for tabbing to links 5225 if ([_private->preferences tabsToLinks]) 5226 _private->_keyboardUIMode = (KeyboardUIMode)(_private->_keyboardUIMode | KeyboardAccessTabsToLinks); 5227} 5228 5229- (KeyboardUIMode)_keyboardUIMode 5230{ 5231 if (!_private->_keyboardUIModeAccessed) { 5232 _private->_keyboardUIModeAccessed = YES; 5233 5234 [self _retrieveKeyboardUIModeFromPreferences:nil]; 5235 5236 [[NSDistributedNotificationCenter defaultCenter] 5237 addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 5238 name:KeyboardUIModeDidChangeNotification object:nil]; 5239 5240 [[NSNotificationCenter defaultCenter] 5241 addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 5242 name:WebPreferencesChangedNotification object:nil]; 5243 } 5244 return _private->_keyboardUIMode; 5245} 5246 5247- (void)_setInsertionPasteboard:(NSPasteboard *)pasteboard 5248{ 5249 _private->insertionPasteboard = pasteboard; 5250} 5251 5252- (void)_setMouseDownEvent:(NSEvent *)event 5253{ 5254 ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown); 5255 5256 if (event == _private->mouseDownEvent) 5257 return; 5258 5259 [event retain]; 5260 [_private->mouseDownEvent release]; 5261 _private->mouseDownEvent = event; 5262} 5263 5264- (void)_cancelUpdateMouseoverTimer 5265{ 5266 if (_private->updateMouseoverTimer) { 5267 CFRunLoopTimerInvalidate(_private->updateMouseoverTimer); 5268 CFRelease(_private->updateMouseoverTimer); 5269 _private->updateMouseoverTimer = NULL; 5270 } 5271} 5272 5273- (void)_stopAutoscrollTimer 5274{ 5275 NSTimer *timer = _private->autoscrollTimer; 5276 _private->autoscrollTimer = nil; 5277 [_private->autoscrollTriggerEvent release]; 5278 _private->autoscrollTriggerEvent = nil; 5279 [timer invalidate]; 5280 [timer release]; 5281} 5282 5283+ (void)_updateMouseoverWithEvent:(NSEvent *)event 5284{ 5285 WebView *oldView = lastMouseoverView; 5286 5287 lastMouseoverView = nil; 5288 5289 NSView *contentView = [[event window] contentView]; 5290 NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil]; 5291 for (NSView *hitView = [contentView hitTest:locationForHitTest]; hitView; hitView = [hitView superview]) { 5292 if ([hitView isKindOfClass:[WebView class]]) { 5293 lastMouseoverView = static_cast<WebView *>(hitView); 5294 break; 5295 } 5296 } 5297 5298 if (lastMouseoverView && lastMouseoverView->_private->hoverFeedbackSuspended) 5299 lastMouseoverView = nil; 5300 5301 if (lastMouseoverView != oldView) { 5302 if (Frame* oldCoreFrame = [oldView _mainCoreFrame]) { 5303 NSEvent *oldViewEvent = [NSEvent mouseEventWithType:NSMouseMoved 5304 location:NSMakePoint(-1, -1) 5305 modifierFlags:[[NSApp currentEvent] modifierFlags] 5306 timestamp:[NSDate timeIntervalSinceReferenceDate] 5307 windowNumber:[[oldView window] windowNumber] 5308 context:[[NSApp currentEvent] context] 5309 eventNumber:0 clickCount:0 pressure:0]; 5310 oldCoreFrame->eventHandler()->mouseMoved(oldViewEvent); 5311 } 5312 } 5313 5314 if (!lastMouseoverView) 5315 return; 5316 5317 if (Frame* coreFrame = core([lastMouseoverView mainFrame])) 5318 coreFrame->eventHandler()->mouseMoved(event); 5319} 5320 5321- (void)_updateMouseoverWithFakeEvent 5322{ 5323 [self _cancelUpdateMouseoverTimer]; 5324 5325 NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved 5326 location:[[self window] convertScreenToBase:[NSEvent mouseLocation]] 5327 modifierFlags:[[NSApp currentEvent] modifierFlags] 5328 timestamp:[NSDate timeIntervalSinceReferenceDate] 5329 windowNumber:[[self window] windowNumber] 5330 context:[[NSApp currentEvent] context] 5331 eventNumber:0 clickCount:0 pressure:0]; 5332 5333 [[self class] _updateMouseoverWithEvent:fakeEvent]; 5334} 5335 5336- (void)_setToolTip:(NSString *)toolTip 5337{ 5338 if (_private->usesDocumentViews) { 5339 id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; 5340 if ([documentView isKindOfClass:[WebHTMLView class]]) 5341 [documentView _setToolTip:toolTip]; 5342 return; 5343 } 5344 5345 // FIXME (Viewless): Code to handle tooltips needs to move into WebView. 5346} 5347 5348- (void)_selectionChanged 5349{ 5350 if (_private->usesDocumentViews) { 5351 id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; 5352 if ([documentView isKindOfClass:[WebHTMLView class]]) 5353 [documentView _selectionChanged]; 5354 return; 5355 } 5356 5357 // FIXME (Viewless): We'll need code here. 5358} 5359 5360- (Frame*)_mainCoreFrame 5361{ 5362 return (_private && _private->page) ? _private->page->mainFrame() : 0; 5363} 5364 5365#if USE(ACCELERATED_COMPOSITING) 5366 5367- (BOOL)_needsOneShotDrawingSynchronization 5368{ 5369 return _private->needsOneShotDrawingSynchronization; 5370} 5371 5372- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization 5373{ 5374 _private->needsOneShotDrawingSynchronization = needsSynchronization; 5375} 5376 5377- (void)_startedAcceleratedCompositingForFrame:(WebFrame*)webFrame 5378{ 5379 BOOL entering = _private->acceleratedFramesCount == 0; 5380 if (entering) 5381 [self willChangeValueForKey:UsingAcceleratedCompositingProperty]; 5382 ++_private->acceleratedFramesCount; 5383 if (entering) 5384 [self didChangeValueForKey:UsingAcceleratedCompositingProperty]; 5385} 5386 5387- (void)_stoppedAcceleratedCompositingForFrame:(WebFrame*)webFrame 5388{ 5389 BOOL leaving = _private->acceleratedFramesCount == 1; 5390 ASSERT(_private->acceleratedFramesCount > 0); 5391 5392 if (leaving) 5393 [self willChangeValueForKey:UsingAcceleratedCompositingProperty]; 5394 --_private->acceleratedFramesCount; 5395 if (leaving) 5396 [self didChangeValueForKey:UsingAcceleratedCompositingProperty]; 5397} 5398 5399- (BOOL)_syncCompositingChanges 5400{ 5401 Frame* frame = [self _mainCoreFrame]; 5402 if (frame && frame->view()) 5403 return frame->view()->syncCompositingStateRecursive(); 5404 5405 return YES; 5406} 5407 5408/* 5409 The order of events with compositing updates is this: 5410 5411 Start of runloop End of runloop 5412 | | 5413 --|-------------------------------------------------------|-- 5414 ^ ^ ^ 5415 | | | 5416 NSWindow update, | CA commit 5417 NSView drawing | 5418 flush | 5419 layerSyncRunLoopObserverCallBack 5420 5421 To avoid flashing, we have to ensure that compositing changes (rendered via 5422 the CoreAnimation rendering display link) appear on screen at the same time 5423 as content painted into the window via the normal WebCore rendering path. 5424 5425 CoreAnimation will commit any layer changes at the end of the runloop via 5426 its "CA commit" observer. Those changes can then appear onscreen at any time 5427 when the display link fires, which can result in unsynchronized rendering. 5428 5429 To fix this, the GraphicsLayerCA code in WebCore does not change the CA 5430 layer tree during style changes and layout; it stores up all changes and 5431 commits them via syncCompositingState(). There are then two situations in 5432 which we can call syncCompositingState(): 5433 5434 1. When painting. FrameView::paintContents() makes a call to syncCompositingState(). 5435 5436 2. When style changes/layout have made changes to the layer tree which do not 5437 result in painting. In this case we need a run loop observer to do a 5438 syncCompositingState() at an appropriate time. The observer will keep firing 5439 until the time is right (essentially when there are no more pending layouts). 5440 5441*/ 5442 5443static void layerSyncRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info) 5444{ 5445 WebView* webView = reinterpret_cast<WebView*>(info); 5446 if ([webView _syncCompositingChanges]) 5447 [webView _clearLayerSyncLoopObserver]; 5448} 5449 5450- (void)_scheduleCompositingLayerSync 5451{ 5452 if (_private->layerSyncRunLoopObserver) 5453 return; 5454 5455 // Run after AppKit does its window update. If we do any painting, we'll commit 5456 // layer changes from FrameView::paintContents(), otherwise we'll commit via 5457 // _syncCompositingChanges when this observer fires. 5458 const CFIndex runLoopOrder = NSDisplayWindowRunLoopOrdering + 1; 5459 5460 // The WebView always outlives the observer, so no need to retain/release. 5461 CFRunLoopObserverContext context = { 0, self, 0, 0, 0 }; 5462 5463 _private->layerSyncRunLoopObserver = CFRunLoopObserverCreate(NULL, 5464 kCFRunLoopBeforeWaiting | kCFRunLoopExit, true /* repeats */, 5465 runLoopOrder, layerSyncRunLoopObserverCallBack, &context); 5466 5467 CFRunLoopAddObserver(CFRunLoopGetCurrent(), _private->layerSyncRunLoopObserver, kCFRunLoopCommonModes); 5468} 5469 5470#endif 5471 5472@end 5473 5474#ifdef BUILDING_ON_LEOPARD 5475 5476static IMP originalRecursivelyRemoveMailAttributesImp; 5477 5478static id objectElementDataAttribute(DOMHTMLObjectElement *self, SEL) 5479{ 5480 return [self getAttribute:@"data"]; 5481} 5482 5483static void recursivelyRemoveMailAttributes(DOMNode *self, SEL selector, BOOL a, BOOL b, BOOL c) 5484{ 5485 // While inside this Mail function, change the behavior of -[DOMHTMLObjectElement data] back to what it used to be 5486 // before we fixed a bug in it (see http://trac.webkit.org/changeset/30044 for that change). 5487 5488 // It's a little bit strange to patch a method defined by WebKit, but it helps keep this workaround self-contained. 5489 5490 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("DOMHTMLObjectElement"), @selector(data)); 5491 IMP originalDataImp = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(objectElementDataAttribute)); 5492 originalRecursivelyRemoveMailAttributesImp(self, selector, a, b, c); 5493 method_setImplementation(methodToPatch, originalDataImp); 5494} 5495 5496#endif 5497 5498static void patchMailRemoveAttributesMethod() 5499{ 5500#ifdef BUILDING_ON_LEOPARD 5501 if (!WKAppVersionCheckLessThan(@"com.apple.mail", -1, 4.0)) 5502 return; 5503 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("DOMNode"), @selector(recursivelyRemoveMailAttributes:convertObjectsToImages:convertEditableElements:)); 5504 if (!methodToPatch) 5505 return; 5506 originalRecursivelyRemoveMailAttributesImp = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(recursivelyRemoveMailAttributes)); 5507#endif 5508} 5509