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