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