• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 David Smith (catfish.man@gmail.com)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 *     its contributors may be used to endorse or promote products derived
16 *     from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#import "WebViewInternal.h"
31#import "WebViewData.h"
32
33#import "DOMCSSStyleDeclarationInternal.h"
34#import "DOMNodeInternal.h"
35#import "DOMRangeInternal.h"
36#import "WebBackForwardListInternal.h"
37#import "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
187using namespace WebCore;
188using 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) \
199macro(alignCenter) \
200macro(alignJustified) \
201macro(alignLeft) \
202macro(alignRight) \
203macro(capitalizeWord) \
204macro(centerSelectionInVisibleArea) \
205macro(changeAttributes) \
206macro(changeBaseWritingDirection) \
207macro(changeBaseWritingDirectionToLTR) \
208macro(changeBaseWritingDirectionToRTL) \
209macro(changeColor) \
210macro(changeDocumentBackgroundColor) \
211macro(changeFont) \
212macro(changeSpelling) \
213macro(checkSpelling) \
214macro(complete) \
215macro(copy) \
216macro(copyFont) \
217macro(cut) \
218macro(delete) \
219macro(deleteBackward) \
220macro(deleteBackwardByDecomposingPreviousCharacter) \
221macro(deleteForward) \
222macro(deleteToBeginningOfLine) \
223macro(deleteToBeginningOfParagraph) \
224macro(deleteToEndOfLine) \
225macro(deleteToEndOfParagraph) \
226macro(deleteToMark) \
227macro(deleteWordBackward) \
228macro(deleteWordForward) \
229macro(ignoreSpelling) \
230macro(indent) \
231macro(insertBacktab) \
232macro(insertLineBreak) \
233macro(insertNewline) \
234macro(insertNewlineIgnoringFieldEditor) \
235macro(insertParagraphSeparator) \
236macro(insertTab) \
237macro(insertTabIgnoringFieldEditor) \
238macro(lowercaseWord) \
239macro(makeBaseWritingDirectionLeftToRight) \
240macro(makeBaseWritingDirectionRightToLeft) \
241macro(makeTextWritingDirectionLeftToRight) \
242macro(makeTextWritingDirectionNatural) \
243macro(makeTextWritingDirectionRightToLeft) \
244macro(moveBackward) \
245macro(moveBackwardAndModifySelection) \
246macro(moveDown) \
247macro(moveDownAndModifySelection) \
248macro(moveForward) \
249macro(moveForwardAndModifySelection) \
250macro(moveLeft) \
251macro(moveLeftAndModifySelection) \
252macro(moveParagraphBackwardAndModifySelection) \
253macro(moveParagraphForwardAndModifySelection) \
254macro(moveRight) \
255macro(moveRightAndModifySelection) \
256macro(moveToBeginningOfDocument) \
257macro(moveToBeginningOfDocumentAndModifySelection) \
258macro(moveToBeginningOfLine) \
259macro(moveToBeginningOfLineAndModifySelection) \
260macro(moveToBeginningOfParagraph) \
261macro(moveToBeginningOfParagraphAndModifySelection) \
262macro(moveToBeginningOfSentence) \
263macro(moveToBeginningOfSentenceAndModifySelection) \
264macro(moveToEndOfDocument) \
265macro(moveToEndOfDocumentAndModifySelection) \
266macro(moveToEndOfLine) \
267macro(moveToEndOfLineAndModifySelection) \
268macro(moveToEndOfParagraph) \
269macro(moveToEndOfParagraphAndModifySelection) \
270macro(moveToEndOfSentence) \
271macro(moveToEndOfSentenceAndModifySelection) \
272macro(moveToLeftEndOfLine) \
273macro(moveToLeftEndOfLineAndModifySelection) \
274macro(moveToRightEndOfLine) \
275macro(moveToRightEndOfLineAndModifySelection) \
276macro(moveUp) \
277macro(moveUpAndModifySelection) \
278macro(moveWordBackward) \
279macro(moveWordBackwardAndModifySelection) \
280macro(moveWordForward) \
281macro(moveWordForwardAndModifySelection) \
282macro(moveWordLeft) \
283macro(moveWordLeftAndModifySelection) \
284macro(moveWordRight) \
285macro(moveWordRightAndModifySelection) \
286macro(outdent) \
287macro(orderFrontSubstitutionsPanel) \
288macro(pageDown) \
289macro(pageDownAndModifySelection) \
290macro(pageUp) \
291macro(pageUpAndModifySelection) \
292macro(paste) \
293macro(pasteAsPlainText) \
294macro(pasteAsRichText) \
295macro(pasteFont) \
296macro(performFindPanelAction) \
297macro(scrollLineDown) \
298macro(scrollLineUp) \
299macro(scrollPageDown) \
300macro(scrollPageUp) \
301macro(scrollToBeginningOfDocument) \
302macro(scrollToEndOfDocument) \
303macro(selectAll) \
304macro(selectLine) \
305macro(selectParagraph) \
306macro(selectSentence) \
307macro(selectToMark) \
308macro(selectWord) \
309macro(setMark) \
310macro(showGuessPanel) \
311macro(startSpeaking) \
312macro(stopSpeaking) \
313macro(subscript) \
314macro(superscript) \
315macro(swapWithMark) \
316macro(takeFindStringFromSelection) \
317macro(toggleBaseWritingDirection) \
318macro(transpose) \
319macro(underline) \
320macro(unscript) \
321macro(uppercaseWord) \
322macro(yank) \
323macro(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
332static BOOL s_didSetCacheModel;
333static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
334
335#ifndef NDEBUG
336static 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
364static void patchMailRemoveAttributesMethod();
365
366NSString *WebElementDOMNodeKey =            @"WebElementDOMNode";
367NSString *WebElementFrameKey =              @"WebElementFrame";
368NSString *WebElementImageKey =              @"WebElementImage";
369NSString *WebElementImageAltStringKey =     @"WebElementImageAltString";
370NSString *WebElementImageRectKey =          @"WebElementImageRect";
371NSString *WebElementImageURLKey =           @"WebElementImageURL";
372NSString *WebElementIsSelectedKey =         @"WebElementIsSelected";
373NSString *WebElementLinkLabelKey =          @"WebElementLinkLabel";
374NSString *WebElementLinkTargetFrameKey =    @"WebElementTargetFrame";
375NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
376NSString *WebElementLinkURLKey =            @"WebElementLinkURL";
377NSString *WebElementSpellingToolTipKey =    @"WebElementSpellingToolTip";
378NSString *WebElementTitleKey =              @"WebElementTitle";
379NSString *WebElementLinkIsLiveKey =         @"WebElementLinkIsLive";
380NSString *WebElementIsInScrollBarKey =      @"WebElementIsInScrollBar";
381NSString *WebElementIsContentEditableKey =  @"WebElementIsContentEditableKey";
382
383NSString *WebViewProgressStartedNotification =          @"WebProgressStartedNotification";
384NSString *WebViewProgressEstimateChangedNotification =  @"WebProgressEstimateChangedNotification";
385NSString *WebViewProgressFinishedNotification =         @"WebProgressFinishedNotification";
386
387NSString * const WebViewDidBeginEditingNotification =         @"WebViewDidBeginEditingNotification";
388NSString * const WebViewDidChangeNotification =               @"WebViewDidChangeNotification";
389NSString * const WebViewDidEndEditingNotification =           @"WebViewDidEndEditingNotification";
390NSString * const WebViewDidChangeTypingStyleNotification =    @"WebViewDidChangeTypingStyleNotification";
391NSString * const WebViewDidChangeSelectionNotification =      @"WebViewDidChangeSelectionNotification";
392
393enum { WebViewVersion = 4 };
394
395#define timedLayoutSize 4096
396
397static NSMutableSet *schemesWithRepresentationsSet;
398
399NSString *_WebCanGoBackKey =            @"canGoBack";
400NSString *_WebCanGoForwardKey =         @"canGoForward";
401NSString *_WebEstimatedProgressKey =    @"estimatedProgress";
402NSString *_WebIsLoadingKey =            @"isLoading";
403NSString *_WebMainFrameIconKey =        @"mainFrameIcon";
404NSString *_WebMainFrameTitleKey =       @"mainFrameTitle";
405NSString *_WebMainFrameURLKey =         @"mainFrameURL";
406NSString *_WebMainFrameDocumentKey =    @"mainFrameDocument";
407
408NSString *_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
421static BOOL continuousSpellCheckingEnabled;
422#ifndef BUILDING_ON_TIGER
423static BOOL grammarCheckingEnabled;
424#endif
425#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
426static BOOL automaticQuoteSubstitutionEnabled;
427static BOOL automaticLinkDetectionEnabled;
428static BOOL automaticDashSubstitutionEnabled;
429static BOOL automaticTextReplacementEnabled;
430static BOOL automaticSpellingCorrectionEnabled;
431#endif
432
433@implementation WebView (AllWebViews)
434
435static CFSetCallBacks NonRetainingSetCallbacks = {
436    0,
437    NULL,
438    NULL,
439    CFCopyDescription,
440    CFEqual,
441    CFHash
442};
443
444static 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
472static 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.
480static 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
495static 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
525static 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
545static bool runningLeopardMail()
546{
547#ifdef BUILDING_ON_LEOPARD
548    return applicationIsAppleMail();
549#endif
550    return NO;
551}
552
553static bool runningTigerMail()
554{
555#ifdef BUILDING_ON_TIGER
556    return applicationIsAppleMail();
557#endif
558    return NO;
559}
560
561static 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
972static 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
1340static 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
2159static 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
2221static 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
2589static 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
2621static 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
3502static 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
4095static 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
4919FOR_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
4958static 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
5540static 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
5649static IMP originalRecursivelyRemoveMailAttributesImp;
5650
5651static id objectElementDataAttribute(DOMHTMLObjectElement *self, SEL)
5652{
5653    return [self getAttribute:@"data"];
5654}
5655
5656static 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
5671static 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