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