1/*
2 * Copyright (C) 2005-2013 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 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 "WebDOMOperationsPrivate.h"
45#import "WebDataSourceInternal.h"
46#import "WebDatabaseManagerPrivate.h"
47#import "WebDefaultEditingDelegate.h"
48#import "WebDefaultPolicyDelegate.h"
49#import "WebDefaultUIDelegate.h"
50#import "WebDelegateImplementationCaching.h"
51#import "WebDeviceOrientationClient.h"
52#import "WebDeviceOrientationProvider.h"
53#import "WebDocument.h"
54#import "WebDocumentInternal.h"
55#import "WebDownload.h"
56#import "WebDownloadInternal.h"
57#import "WebDragClient.h"
58#import "WebDynamicScrollBarsViewInternal.h"
59#import "WebEditingDelegate.h"
60#import "WebEditorClient.h"
61#import "WebFormDelegatePrivate.h"
62#import "WebFrameInternal.h"
63#import "WebFrameLoaderClient.h"
64#import "WebFrameNetworkingContext.h"
65#import "WebFrameViewInternal.h"
66#import "WebGeolocationClient.h"
67#import "WebGeolocationPositionInternal.h"
68#import "WebHTMLRepresentation.h"
69#import "WebHTMLViewInternal.h"
70#import "WebHistoryItemInternal.h"
71#import "WebIconDatabaseInternal.h"
72#import "WebInspector.h"
73#import "WebInspectorClient.h"
74#import "WebKitErrors.h"
75#import "WebKitFullScreenListener.h"
76#import "WebKitLogging.h"
77#import "WebKitNSStringExtras.h"
78#import "WebKitStatisticsPrivate.h"
79#import "WebKitSystemBits.h"
80#import "WebKitVersionChecks.h"
81#import "WebLocalizableStrings.h"
82#import "WebNSDataExtras.h"
83#import "WebNSDataExtrasPrivate.h"
84#import "WebNSDictionaryExtras.h"
85#import "WebNSURLExtras.h"
86#import "WebNSURLRequestExtras.h"
87#import "WebNSViewExtras.h"
88#import "WebNodeHighlight.h"
89#import "WebNotificationClient.h"
90#import "WebPDFView.h"
91#import "WebPanelAuthenticationHandler.h"
92#import "WebPlatformStrategies.h"
93#import "WebPluginDatabase.h"
94#import "WebPolicyDelegate.h"
95#import "WebPreferenceKeysPrivate.h"
96#import "WebPreferencesPrivate.h"
97#import "WebProgressTrackerClient.h"
98#import "WebScriptDebugDelegate.h"
99#import "WebScriptWorldInternal.h"
100#import "WebStorageManagerInternal.h"
101#import "WebSystemInterface.h"
102#import "WebTextCompletionController.h"
103#import "WebTextIterator.h"
104#import "WebUIDelegate.h"
105#import "WebUIDelegatePrivate.h"
106#import "WebUserMediaClient.h"
107#import "WebViewGroup.h"
108#import <CoreFoundation/CFSet.h>
109#import <Foundation/NSURLConnection.h>
110#import <JavaScriptCore/APICast.h>
111#import <JavaScriptCore/JSValueRef.h>
112#import <WebCore/AlternativeTextUIController.h>
113#import <WebCore/AnimationController.h>
114#import <WebCore/ApplicationCacheStorage.h>
115#import <WebCore/BackForwardController.h>
116#import <WebCore/BackForwardList.h>
117#import <WebCore/MemoryCache.h>
118#import <WebCore/Chrome.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/Editor.h>
127#import <WebCore/EventHandler.h>
128#import <WebCore/ExceptionHandlers.h>
129#import <WebCore/FocusController.h>
130#import <WebCore/FrameLoader.h>
131#import <WebCore/FrameSelection.h>
132#import <WebCore/FrameTree.h>
133#import <WebCore/FrameView.h>
134#import <WebCore/GCController.h>
135#import <WebCore/GeolocationController.h>
136#import <WebCore/GeolocationError.h>
137#import <WebCore/HTMLMediaElement.h>
138#import <WebCore/HTMLNames.h>
139#import <WebCore/HistoryController.h>
140#import <WebCore/HistoryItem.h>
141#import <WebCore/IconDatabase.h>
142#import <WebCore/JSCSSStyleDeclaration.h>
143#import <WebCore/JSDocument.h>
144#import <WebCore/JSElement.h>
145#import <WebCore/JSNodeList.h>
146#import <WebCore/JSNotification.h>
147#import <WebCore/Logging.h>
148#import <WebCore/MIMETypeRegistry.h>
149#import <WebCore/MainFrame.h>
150#import <WebCore/MemoryPressureHandler.h>
151#import <WebCore/NodeList.h>
152#import <WebCore/Notification.h>
153#import <WebCore/NotificationController.h>
154#import <WebCore/Page.h>
155#import <WebCore/PageCache.h>
156#import <WebCore/PageGroup.h>
157#import <WebCore/PlatformEventFactoryMac.h>
158#import <WebCore/ProgressTracker.h>
159#import <WebCore/RenderView.h>
160#import <WebCore/RenderWidget.h>
161#import <WebCore/ResourceHandle.h>
162#import <WebCore/ResourceLoadScheduler.h>
163#import <WebCore/ResourceRequest.h>
164#import <WebCore/RuntimeApplicationChecks.h>
165#import <WebCore/RuntimeEnabledFeatures.h>
166#import <WebCore/SchemeRegistry.h>
167#import <WebCore/ScriptController.h>
168#import <WebCore/SecurityOrigin.h>
169#import <WebCore/SecurityPolicy.h>
170#import <WebCore/Settings.h>
171#import <WebCore/StyleProperties.h>
172#import <WebCore/TextResourceDecoder.h>
173#import <WebCore/ThreadCheck.h>
174#import <WebCore/UserAgent.h>
175#import <WebCore/WebCoreObjCExtras.h>
176#import <WebCore/WebCoreView.h>
177#import <WebCore/Widget.h>
178#import <WebKitLegacy/DOM.h>
179#import <WebKitLegacy/DOMExtensions.h>
180#import <WebKitLegacy/DOMPrivate.h>
181#import <WebKitSystemInterface.h>
182#import <bindings/ScriptValue.h>
183#import <mach-o/dyld.h>
184#import <objc/objc-auto.h>
185#import <objc/runtime.h>
186#import <runtime/ArrayPrototype.h>
187#import <runtime/DateInstance.h>
188#import <runtime/InitializeThreading.h>
189#import <runtime/JSLock.h>
190#import <runtime/JSCJSValue.h>
191#import <wtf/Assertions.h>
192#import <wtf/HashTraits.h>
193#import <wtf/MainThread.h>
194#import <wtf/ObjcRuntimeExtras.h>
195#import <wtf/RefCountedLeakCounter.h>
196#import <wtf/RefPtr.h>
197#import <wtf/RunLoop.h>
198#import <wtf/StdLibExtras.h>
199
200#if !PLATFORM(IOS)
201#import "WebContextMenuClient.h"
202#import "WebFullScreenController.h"
203#import "WebNSEventExtras.h"
204#import "WebNSObjectExtras.h"
205#import "WebNSPasteboardExtras.h"
206#import "WebNSPrintOperationExtras.h"
207#import "WebPDFView.h"
208#import <WebCore/WebVideoFullscreenController.h>
209#else
210#import "MemoryMeasure.h"
211#import "WebCaretChangeListener.h"
212#import "WebChromeClientIOS.h"
213#import "WebDefaultFormDelegate.h"
214#import "WebDefaultFrameLoadDelegate.h"
215#import "WebDefaultResourceLoadDelegate.h"
216#import "WebDefaultUIKitDelegate.h"
217#import "WebFixedPositionContent.h"
218#import "WebMailDelegate.h"
219#import "WebNSUserDefaultsExtras.h"
220#import "WebPDFViewIOS.h"
221#import "WebPlainWhiteView.h"
222#import "WebPluginController.h"
223#import "WebPolicyDelegatePrivate.h"
224#import "WebSQLiteDatabaseTrackerClient.h"
225#import "WebStorageManagerPrivate.h"
226#import "WebUIKitSupport.h"
227#import "WebVisiblePosition.h"
228#import <CFNetwork/CFURLCachePriv.h>
229#import <MobileGestalt.h>
230#import <WebCore/EventNames.h>
231#import <WebCore/FontCache.h>
232#import <WebCore/GraphicsLayer.h>
233#import <WebCore/IconController.h>
234#import <WebCore/LegacyTileCache.h>
235#import <WebCore/NetworkStateNotifier.h>
236#import <WebCore/RuntimeApplicationChecksIOS.h>
237#import <WebCore/SQLiteDatabaseTracker.h>
238#import <WebCore/SmartReplace.h>
239#import <WebCore/TextRun.h>
240#import <WebCore/TileControllerMemoryHandlerIOS.h>
241#import <WebCore/WAKWindow.h>
242#import <WebCore/WKView.h>
243#import <WebCore/WebCoreThread.h>
244#import <WebCore/WebCoreThreadMessage.h>
245#import <WebCore/WebCoreThreadRun.h>
246#import <WebCore/WebEvent.h>
247#import <WebCore/WebVideoFullscreenControllerAVKit.h>
248#import <dispatch/private.h>
249#import <wtf/FastMalloc.h>
250#endif // !PLATFORM(IOS)
251
252#if ENABLE(DASHBOARD_SUPPORT)
253#import <WebKitLegacy/WebDashboardRegion.h>
254#endif
255
256#if ENABLE(DISK_IMAGE_CACHE) && PLATFORM(IOS)
257#import "WebDiskImageCacheClientIOS.h"
258#import <WebCore/DiskImageCacheIOS.h>
259#endif
260
261#if ENABLE(REMOTE_INSPECTOR)
262#import <JavaScriptCore/RemoteInspector.h>
263#if PLATFORM(IOS)
264#import "WebIndicateLayer.h"
265#endif
266#endif
267
268#if USE(GLIB)
269#import <glib.h>
270#endif
271
272#if USE(QUICK_LOOK)
273#include <WebCore/QuickLook.h>
274#endif
275
276#if ENABLE(TOUCH_EVENTS)
277#import <WebCore/WebEventRegion.h>
278#endif
279
280#if ENABLE(DISK_IMAGE_CACHE)
281#import "WebDiskImageCacheClientIOS.h"
282#import <WebCore/DiskImageCacheIOS.h>
283#endif
284
285#if ENABLE(GAMEPAD)
286#import <WebCore/HIDGamepadProvider.h>
287#endif
288
289#if !PLATFORM(IOS)
290@interface NSSpellChecker (WebNSSpellCheckerDetails)
291- (void)_preflightChosenSpellServer;
292@end
293
294@interface NSView (WebNSViewDetails)
295- (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
296- (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
297- (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
298- (void)_windowChangedKeyState;
299@end
300
301@interface NSWindow (WebNSWindowDetails)
302- (id)_oldFirstResponderBeforeBecoming;
303- (void)_enableScreenUpdatesIfNeeded;
304- (BOOL)_wrapsCarbonWindow;
305- (BOOL)_hasKeyAppearance;
306@end
307#endif
308
309using namespace JSC;
310using namespace Inspector;
311using namespace WebCore;
312
313#define FOR_EACH_RESPONDER_SELECTOR(macro) \
314macro(alignCenter) \
315macro(alignJustified) \
316macro(alignLeft) \
317macro(alignRight) \
318macro(capitalizeWord) \
319macro(centerSelectionInVisibleArea) \
320macro(changeAttributes) \
321macro(changeBaseWritingDirection) \
322macro(changeBaseWritingDirectionToLTR) \
323macro(changeBaseWritingDirectionToRTL) \
324macro(changeColor) \
325macro(changeDocumentBackgroundColor) \
326macro(changeFont) \
327macro(changeSpelling) \
328macro(checkSpelling) \
329macro(complete) \
330macro(copy) \
331macro(copyFont) \
332macro(cut) \
333macro(delete) \
334macro(deleteBackward) \
335macro(deleteBackwardByDecomposingPreviousCharacter) \
336macro(deleteForward) \
337macro(deleteToBeginningOfLine) \
338macro(deleteToBeginningOfParagraph) \
339macro(deleteToEndOfLine) \
340macro(deleteToEndOfParagraph) \
341macro(deleteToMark) \
342macro(deleteWordBackward) \
343macro(deleteWordForward) \
344macro(ignoreSpelling) \
345macro(indent) \
346macro(insertBacktab) \
347macro(insertLineBreak) \
348macro(insertNewline) \
349macro(insertNewlineIgnoringFieldEditor) \
350macro(insertParagraphSeparator) \
351macro(insertTab) \
352macro(insertTabIgnoringFieldEditor) \
353macro(lowercaseWord) \
354macro(makeBaseWritingDirectionLeftToRight) \
355macro(makeBaseWritingDirectionRightToLeft) \
356macro(makeTextWritingDirectionLeftToRight) \
357macro(makeTextWritingDirectionNatural) \
358macro(makeTextWritingDirectionRightToLeft) \
359macro(moveBackward) \
360macro(moveBackwardAndModifySelection) \
361macro(moveDown) \
362macro(moveDownAndModifySelection) \
363macro(moveForward) \
364macro(moveForwardAndModifySelection) \
365macro(moveLeft) \
366macro(moveLeftAndModifySelection) \
367macro(moveParagraphBackwardAndModifySelection) \
368macro(moveParagraphForwardAndModifySelection) \
369macro(moveRight) \
370macro(moveRightAndModifySelection) \
371macro(moveToBeginningOfDocument) \
372macro(moveToBeginningOfDocumentAndModifySelection) \
373macro(moveToBeginningOfLine) \
374macro(moveToBeginningOfLineAndModifySelection) \
375macro(moveToBeginningOfParagraph) \
376macro(moveToBeginningOfParagraphAndModifySelection) \
377macro(moveToBeginningOfSentence) \
378macro(moveToBeginningOfSentenceAndModifySelection) \
379macro(moveToEndOfDocument) \
380macro(moveToEndOfDocumentAndModifySelection) \
381macro(moveToEndOfLine) \
382macro(moveToEndOfLineAndModifySelection) \
383macro(moveToEndOfParagraph) \
384macro(moveToEndOfParagraphAndModifySelection) \
385macro(moveToEndOfSentence) \
386macro(moveToEndOfSentenceAndModifySelection) \
387macro(moveToLeftEndOfLine) \
388macro(moveToLeftEndOfLineAndModifySelection) \
389macro(moveToRightEndOfLine) \
390macro(moveToRightEndOfLineAndModifySelection) \
391macro(moveUp) \
392macro(moveUpAndModifySelection) \
393macro(moveWordBackward) \
394macro(moveWordBackwardAndModifySelection) \
395macro(moveWordForward) \
396macro(moveWordForwardAndModifySelection) \
397macro(moveWordLeft) \
398macro(moveWordLeftAndModifySelection) \
399macro(moveWordRight) \
400macro(moveWordRightAndModifySelection) \
401macro(orderFrontSubstitutionsPanel) \
402macro(outdent) \
403macro(overWrite) \
404macro(pageDown) \
405macro(pageDownAndModifySelection) \
406macro(pageUp) \
407macro(pageUpAndModifySelection) \
408macro(paste) \
409macro(pasteAsPlainText) \
410macro(pasteAsRichText) \
411macro(pasteFont) \
412macro(performFindPanelAction) \
413macro(scrollLineDown) \
414macro(scrollLineUp) \
415macro(scrollPageDown) \
416macro(scrollPageUp) \
417macro(scrollToBeginningOfDocument) \
418macro(scrollToEndOfDocument) \
419macro(selectAll) \
420macro(selectLine) \
421macro(selectParagraph) \
422macro(selectSentence) \
423macro(selectToMark) \
424macro(selectWord) \
425macro(setMark) \
426macro(showGuessPanel) \
427macro(startSpeaking) \
428macro(stopSpeaking) \
429macro(subscript) \
430macro(superscript) \
431macro(swapWithMark) \
432macro(takeFindStringFromSelection) \
433macro(toggleBaseWritingDirection) \
434macro(transpose) \
435macro(underline) \
436macro(unscript) \
437macro(uppercaseWord) \
438macro(yank) \
439macro(yankAndSelect) \
440
441#define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin"
442#define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin"
443
444#define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange"
445#define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode")
446
447static BOOL s_didSetCacheModel;
448static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
449
450#if PLATFORM(IOS)
451static Class s_pdfRepresentationClass;
452static Class s_pdfViewClass;
453#endif
454
455#ifndef NDEBUG
456static const char webViewIsOpen[] = "At least one WebView is still open.";
457#endif
458
459#if PLATFORM(IOS)
460@interface WebView(WebViewPrivate)
461- (void)_preferencesChanged:(WebPreferences *)preferences;
462- (void)_updateScreenScaleFromWindow;
463@end
464
465@interface NSURLCache (WebPrivate)
466- (CFURLCacheRef)_CFURLCache;
467@end
468#endif
469
470#if !PLATFORM(IOS)
471@interface NSObject (WebValidateWithoutDelegate)
472- (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item;
473@end
474#endif
475
476#if PLATFORM(IOS)
477@class _WebSafeForwarder;
478
479@interface _WebSafeAsyncForwarder : NSObject {
480    _WebSafeForwarder *_forwarder;
481}
482- (id)initWithForwarder:(_WebSafeForwarder *)forwarder;
483@end
484#endif
485
486@interface _WebSafeForwarder : NSObject
487{
488    id target; // Non-retained. Don't retain delegates.
489    id defaultTarget;
490#if PLATFORM(IOS)
491    _WebSafeAsyncForwarder *asyncForwarder;
492    dispatch_once_t asyncForwarderPred;
493#endif
494}
495- (instancetype)initWithTarget:(id)target defaultTarget:(id)defaultTarget;
496#if PLATFORM(IOS)
497- (void)clearTarget;
498- (id)asyncForwarder;
499#endif
500@end
501
502FindOptions coreOptions(WebFindOptions options)
503{
504    return (options & WebFindOptionsCaseInsensitive ? CaseInsensitive : 0)
505        | (options & WebFindOptionsAtWordStarts ? AtWordStarts : 0)
506        | (options & WebFindOptionsTreatMedialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0)
507        | (options & WebFindOptionsBackwards ? Backwards : 0)
508        | (options & WebFindOptionsWrapAround ? WrapAround : 0)
509        | (options & WebFindOptionsStartInSelection ? StartInSelection : 0);
510}
511
512LayoutMilestones coreLayoutMilestones(WebLayoutMilestones milestones)
513{
514    return (milestones & WebDidFirstLayout ? DidFirstLayout : 0)
515        | (milestones & WebDidFirstVisuallyNonEmptyLayout ? DidFirstVisuallyNonEmptyLayout : 0)
516        | (milestones & WebDidHitRelevantRepaintedObjectsAreaThreshold ? DidHitRelevantRepaintedObjectsAreaThreshold : 0);
517}
518
519WebLayoutMilestones kitLayoutMilestones(LayoutMilestones milestones)
520{
521    return (milestones & DidFirstLayout ? WebDidFirstLayout : 0)
522        | (milestones & DidFirstVisuallyNonEmptyLayout ? WebDidFirstVisuallyNonEmptyLayout : 0)
523        | (milestones & DidHitRelevantRepaintedObjectsAreaThreshold ? WebDidHitRelevantRepaintedObjectsAreaThreshold : 0);
524}
525
526static WebPageVisibilityState kit(PageVisibilityState visibilityState)
527{
528    switch (visibilityState) {
529    case PageVisibilityStateVisible:
530        return WebPageVisibilityStateVisible;
531    case PageVisibilityStateHidden:
532        return WebPageVisibilityStateHidden;
533    case PageVisibilityStatePrerender:
534        return WebPageVisibilityStatePrerender;
535    }
536
537    ASSERT_NOT_REACHED();
538    return WebPageVisibilityStateVisible;
539}
540
541@interface WebView (WebFileInternal)
542#if !PLATFORM(IOS)
543- (float)_deviceScaleFactor;
544#endif
545- (BOOL)_isLoading;
546- (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point;
547- (WebFrame *)_focusedFrame;
548+ (void)_preflightSpellChecker;
549- (BOOL)_continuousCheckingAllowed;
550- (NSResponder *)_responderForResponderOperations;
551#if USE(GLIB)
552- (void)_clearGlibLoopObserver;
553#endif
554@end
555
556NSString *WebElementDOMNodeKey =            @"WebElementDOMNode";
557NSString *WebElementFrameKey =              @"WebElementFrame";
558NSString *WebElementImageKey =              @"WebElementImage";
559NSString *WebElementImageAltStringKey =     @"WebElementImageAltString";
560NSString *WebElementImageRectKey =          @"WebElementImageRect";
561NSString *WebElementImageURLKey =           @"WebElementImageURL";
562NSString *WebElementIsSelectedKey =         @"WebElementIsSelected";
563NSString *WebElementLinkLabelKey =          @"WebElementLinkLabel";
564NSString *WebElementLinkTargetFrameKey =    @"WebElementTargetFrame";
565NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
566NSString *WebElementLinkURLKey =            @"WebElementLinkURL";
567NSString *WebElementMediaURLKey =           @"WebElementMediaURL";
568NSString *WebElementSpellingToolTipKey =    @"WebElementSpellingToolTip";
569NSString *WebElementTitleKey =              @"WebElementTitle";
570NSString *WebElementLinkIsLiveKey =         @"WebElementLinkIsLive";
571NSString *WebElementIsInScrollBarKey =      @"WebElementIsInScrollBar";
572NSString *WebElementIsContentEditableKey =  @"WebElementIsContentEditableKey";
573
574NSString *WebViewProgressStartedNotification =          @"WebProgressStartedNotification";
575NSString *WebViewProgressEstimateChangedNotification =  @"WebProgressEstimateChangedNotification";
576#if !PLATFORM(IOS)
577NSString *WebViewProgressFinishedNotification =         @"WebProgressFinishedNotification";
578#else
579NSString * const WebViewProgressEstimatedProgressKey = @"WebProgressEstimatedProgressKey";
580NSString * const WebViewProgressBackgroundColorKey =   @"WebProgressBackgroundColorKey";
581#endif
582
583NSString * const WebViewDidBeginEditingNotification =         @"WebViewDidBeginEditingNotification";
584NSString * const WebViewDidChangeNotification =               @"WebViewDidChangeNotification";
585NSString * const WebViewDidEndEditingNotification =           @"WebViewDidEndEditingNotification";
586NSString * const WebViewDidChangeTypingStyleNotification =    @"WebViewDidChangeTypingStyleNotification";
587NSString * const WebViewDidChangeSelectionNotification =      @"WebViewDidChangeSelectionNotification";
588
589enum { WebViewVersion = 4 };
590
591#define timedLayoutSize 4096
592
593static NSMutableSet *schemesWithRepresentationsSet;
594
595#if !PLATFORM(IOS)
596NSString *_WebCanGoBackKey =            @"canGoBack";
597NSString *_WebCanGoForwardKey =         @"canGoForward";
598NSString *_WebEstimatedProgressKey =    @"estimatedProgress";
599NSString *_WebIsLoadingKey =            @"isLoading";
600NSString *_WebMainFrameIconKey =        @"mainFrameIcon";
601NSString *_WebMainFrameTitleKey =       @"mainFrameTitle";
602NSString *_WebMainFrameURLKey =         @"mainFrameURL";
603NSString *_WebMainFrameDocumentKey =    @"mainFrameDocument";
604#endif
605
606#if USE(QUICK_LOOK)
607NSString *WebQuickLookFileNameKey = @"WebQuickLookFileNameKey";
608NSString *WebQuickLookUTIKey      = @"WebQuickLookUTIKey";
609#endif
610
611NSString *_WebViewDidStartAcceleratedCompositingNotification = @"_WebViewDidStartAcceleratedCompositing";
612NSString * const WebViewWillCloseNotification = @"WebViewWillCloseNotification";
613
614#if ENABLE(REMOTE_INSPECTOR)
615// FIXME: Legacy, remove this, switch to something from JavaScriptCore Inspector::RemoteInspectorServer.
616NSString *_WebViewRemoteInspectorHasSessionChangedNotification = @"_WebViewRemoteInspectorHasSessionChangedNotification";
617#endif
618
619NSString *WebKitKerningAndLigaturesEnabledByDefaultDefaultsKey = @"WebKitKerningAndLigaturesEnabledByDefault";
620
621@interface WebProgressItem : NSObject
622{
623@public
624    long long bytesReceived;
625    long long estimatedLength;
626}
627@end
628
629@implementation WebProgressItem
630@end
631
632static BOOL continuousSpellCheckingEnabled;
633#if !PLATFORM(IOS)
634static BOOL grammarCheckingEnabled;
635static BOOL automaticQuoteSubstitutionEnabled;
636static BOOL automaticLinkDetectionEnabled;
637static BOOL automaticDashSubstitutionEnabled;
638static BOOL automaticTextReplacementEnabled;
639static BOOL automaticSpellingCorrectionEnabled;
640#endif
641
642@implementation WebView (AllWebViews)
643
644static CFSetCallBacks NonRetainingSetCallbacks = {
645    0,
646    NULL,
647    NULL,
648    CFCopyDescription,
649    CFEqual,
650    CFHash
651};
652
653static CFMutableSetRef allWebViewsSet;
654
655+ (void)_makeAllWebViewsPerformSelector:(SEL)selector
656{
657    if (!allWebViewsSet)
658        return;
659
660    [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector];
661}
662
663- (void)_removeFromAllWebViewsSet
664{
665    if (allWebViewsSet)
666        CFSetRemoveValue(allWebViewsSet, self);
667}
668
669- (void)_addToAllWebViewsSet
670{
671    if (!allWebViewsSet)
672        allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks);
673
674    CFSetSetValue(allWebViewsSet, self);
675}
676
677@end
678
679@implementation WebView (WebPrivate)
680
681static String webKitBundleVersionString()
682{
683    return [[NSBundle bundleForClass:[WebView class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
684}
685
686+ (NSString *)_standardUserAgentWithApplicationName:(NSString *)applicationName
687{
688    return standardUserAgentWithApplicationName(applicationName, webKitBundleVersionString());
689}
690
691#if PLATFORM(IOS)
692- (void)_setBrowserUserAgentProductVersion:(NSString *)productVersion buildVersion:(NSString *)buildVersion bundleVersion:(NSString *)bundleVersion
693{
694    [self setApplicationNameForUserAgent:[NSString stringWithFormat:@"Version/%@ Mobile/%@ Safari/%@", productVersion, buildVersion, bundleVersion]];
695}
696
697- (void)_setUIWebViewUserAgentWithBuildVersion:(NSString *)buildVersion
698{
699    [self setApplicationNameForUserAgent:[@"Mobile/" stringByAppendingString:buildVersion]];
700}
701#endif // PLATFORM(IOS)
702
703+ (void)_reportException:(JSValueRef)exception inContext:(JSContextRef)context
704{
705    if (!exception || !context)
706        return;
707
708    JSC::ExecState* execState = toJS(context);
709    JSLockHolder lock(execState);
710
711    // Make sure the context has a DOMWindow global object, otherwise this context didn't originate from a WebView.
712    if (!toJSDOMWindow(execState->lexicalGlobalObject()))
713        return;
714
715    reportException(execState, toJS(execState, exception));
716}
717
718static void WebKitInitializeApplicationCachePathIfNecessary()
719{
720    static BOOL initialized = NO;
721    if (initialized)
722        return;
723
724    NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
725    if (!appName)
726        appName = [[NSProcessInfo processInfo] processName];
727#if PLATFORM(IOS)
728    if (WebCore::applicationIsMobileSafari() || WebCore::applicationIsWebApp())
729        appName = @"com.apple.WebAppCache";
730#endif
731
732    ASSERT(appName);
733
734    NSString* cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:appName];
735
736    cacheStorage().setCacheDirectory(cacheDir);
737    initialized = YES;
738}
739
740static bool shouldEnableLoadDeferring()
741{
742    return !applicationIsAdobeInstaller();
743}
744
745static bool shouldRestrictWindowFocus()
746{
747#if PLATFORM(IOS)
748    return true;
749#else
750    return !applicationIsHRBlock();
751#endif
752}
753
754- (void)_dispatchPendingLoadRequests
755{
756    resourceLoadScheduler()->servePendingRequests();
757}
758
759#if !PLATFORM(IOS)
760- (void)_registerDraggedTypes
761{
762    NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
763    NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
764    NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
765    [types addObjectsFromArray:URLTypes];
766    [self registerForDraggedTypes:[types allObjects]];
767    [types release];
768}
769
770static bool needsOutlookQuirksScript()
771{
772    static bool isOutlookNeedingQuirksScript = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_HTML5_PARSER)
773        && applicationIsMicrosoftOutlook();
774    return isOutlookNeedingQuirksScript;
775}
776
777static NSString *leakOutlookQuirksUserScriptContents()
778{
779    NSString *scriptPath = [[NSBundle bundleForClass:[WebView class]] pathForResource:@"OutlookQuirksUserScript" ofType:@"js"];
780    NSStringEncoding encoding;
781    return [[NSString alloc] initWithContentsOfFile:scriptPath usedEncoding:&encoding error:0];
782}
783
784-(void)_injectOutlookQuirksScript
785{
786    static NSString *outlookQuirksScriptContents = leakOutlookQuirksUserScriptContents();
787    core(self)->group().addUserScriptToWorld(*core([WebScriptWorld world]),
788        outlookQuirksScriptContents, URL(), Vector<String>(), Vector<String>(), InjectAtDocumentEnd, InjectInAllFrames);
789}
790#endif
791
792static bool shouldRespectPriorityInCSSAttributeSetters()
793{
794#if PLATFORM(IOS)
795    static bool isStanzaNeedingAttributeSetterQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_CSS_ATTRIBUTE_SETTERS_IGNORING_PRIORITY)
796        && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.lexcycle.stanza"];
797    return isStanzaNeedingAttributeSetterQuirk;
798#else
799    static bool isIAdProducerNeedingAttributeSetterQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_CSS_ATTRIBUTE_SETTERS_IGNORING_PRIORITY)
800        && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.iAdProducer"];
801    return isIAdProducerNeedingAttributeSetterQuirk;
802#endif
803}
804
805#if PLATFORM(IOS)
806static bool shouldTransformsAffectOverflow()
807{
808    static bool shouldTransformsAffectOverflow = !applicationIsOkCupid() || WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_CSS_TRANSFORMS_AFFECTING_OVERFLOW);
809    return shouldTransformsAffectOverflow;
810}
811
812static bool shouldDispatchJavaScriptWindowOnErrorEvents()
813{
814    static bool shouldDispatchJavaScriptWindowOnErrorEvents = !applicationIsFacebook() || WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_WINDOW_ON_ERROR);
815    return shouldDispatchJavaScriptWindowOnErrorEvents;
816}
817
818static bool isInternalInstall()
819{
820    static bool isInternal = MGGetBoolAnswer(kMGQAppleInternalInstallCapability);
821    return isInternal;
822}
823
824static bool didOneTimeInitialization = false;
825#endif
826
827static bool shouldUseLegacyBackgroundSizeShorthandBehavior()
828{
829#if PLATFORM(IOS)
830    static bool shouldUseLegacyBackgroundSizeShorthandBehavior = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LEGACY_BACKGROUNDSIZE_SHORTHAND_BEHAVIOR);
831#else
832    static bool shouldUseLegacyBackgroundSizeShorthandBehavior = applicationIsVersions()
833        && !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LEGACY_BACKGROUNDSIZE_SHORTHAND_BEHAVIOR);
834#endif
835    return shouldUseLegacyBackgroundSizeShorthandBehavior;
836}
837
838#if ENABLE(GAMEPAD)
839static void WebKitInitializeGamepadProviderIfNecessary()
840{
841    static bool initialized = false;
842    if (initialized)
843        return;
844
845    GamepadProvider::shared().setSharedProvider(HIDGamepadProvider::shared());
846    initialized = true;
847}
848#endif
849
850- (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
851{
852    WebCoreThreadViolationCheckRoundTwo();
853
854#ifndef NDEBUG
855    WTF::RefCountedLeakCounter::suppressMessages(webViewIsOpen);
856#endif
857
858    WebPreferences *standardPreferences = [WebPreferences standardPreferences];
859    [standardPreferences willAddToWebView];
860
861    _private->preferences = [standardPreferences retain];
862    _private->mainFrameDocumentReady = NO;
863    _private->drawsBackground = YES;
864#if !PLATFORM(IOS)
865    _private->backgroundColor = [[NSColor colorWithDeviceWhite:1 alpha:1] retain];
866#else
867    _private->backgroundColor = CGColorRetain(cachedCGColor(Color::white, ColorSpaceDeviceRGB));
868#endif
869    _private->includesFlattenedCompositingLayersWhenDrawingToBitmap = YES;
870
871    NSRect f = [self frame];
872    WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
873    [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
874    [self addSubview:frameView];
875    [frameView release];
876
877#if !PLATFORM(IOS)
878    static bool didOneTimeInitialization = false;
879#endif
880    if (!didOneTimeInitialization) {
881#if !LOG_DISABLED
882        WebKitInitializeLoggingChannelsIfNecessary();
883        WebCore::initializeLoggingChannelsIfNecessary();
884#endif // !LOG_DISABLED
885
886        // Initialize our platform strategies first before invoking the rest
887        // of the initialization code which may depend on the strategies.
888        WebPlatformStrategies::initializeIfNecessary();
889
890#if ENABLE(SQL_DATABASE)
891#if PLATFORM(IOS)
892        // Set the WebSQLiteDatabaseTrackerClient.
893        SQLiteDatabaseTracker::setClient(WebSQLiteDatabaseTrackerClient::sharedWebSQLiteDatabaseTrackerClient());
894
895        if ([standardPreferences databasesEnabled])
896#endif
897        [WebDatabaseManager sharedWebDatabaseManager];
898#endif
899
900#if PLATFORM(IOS)
901        if ([standardPreferences storageTrackerEnabled])
902#endif
903        WebKitInitializeStorageIfNecessary();
904        WebKitInitializeApplicationCachePathIfNecessary();
905#if ENABLE(DISK_IMAGE_CACHE) && PLATFORM(IOS)
906        WebKitInitializeWebDiskImageCache();
907#endif
908#if ENABLE(GAMEPAD)
909        WebKitInitializeGamepadProviderIfNecessary();
910#endif
911
912        Settings::setDefaultMinDOMTimerInterval(0.004);
913
914        Settings::setShouldRespectPriorityInCSSAttributeSetters(shouldRespectPriorityInCSSAttributeSetters());
915
916#if PLATFORM(IOS)
917        if (applicationIsMobileSafari())
918            Settings::setShouldManageAudioSessionCategory(true);
919#endif
920
921        didOneTimeInitialization = true;
922    }
923
924    Page::PageClients pageClients;
925#if !PLATFORM(IOS)
926    pageClients.chromeClient = new WebChromeClient(self);
927    pageClients.contextMenuClient = new WebContextMenuClient(self);
928#if ENABLE(DRAG_SUPPORT)
929    pageClients.dragClient = new WebDragClient(self);
930#endif
931    pageClients.inspectorClient = new WebInspectorClient(self);
932#else
933    pageClients.chromeClient = new WebChromeClientIOS(self);
934    pageClients.inspectorClient = new WebInspectorClient(self);
935#endif
936    pageClients.editorClient = new WebEditorClient(self);
937    pageClients.alternativeTextClient = new WebAlternativeTextClient(self);
938    pageClients.loaderClientForMainFrame = new WebFrameLoaderClient;
939    pageClients.progressTrackerClient = new WebProgressTrackerClient(self);
940    _private->page = new Page(pageClients);
941#if ENABLE(GEOLOCATION)
942    WebCore::provideGeolocationTo(_private->page, new WebGeolocationClient(self));
943#endif
944#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
945    WebCore::provideNotification(_private->page, new WebNotificationClient(self));
946#endif
947#if ENABLE(DEVICE_ORIENTATION)
948#if !PLATFORM(IOS)
949    WebCore::provideDeviceOrientationTo(_private->page, new WebDeviceOrientationClient(self));
950#endif
951#endif
952#if ENABLE(MEDIA_STREAM)
953    WebCore::provideUserMediaTo(_private->page, new WebUserMediaClient(self));
954#endif
955
956#if ENABLE(REMOTE_INSPECTOR)
957    _private->page->setRemoteInspectionAllowed(true);
958#endif
959
960    _private->page->setCanStartMedia([self window]);
961    _private->page->settings().setLocalStorageDatabasePath([[self preferences] _localStorageDatabasePath]);
962    _private->page->settings().setUseLegacyBackgroundSizeShorthandBehavior(shouldUseLegacyBackgroundSizeShorthandBehavior());
963
964#if !PLATFORM(IOS)
965    if (needsOutlookQuirksScript()) {
966        _private->page->settings().setShouldInjectUserScriptsInInitialEmptyDocument(true);
967        [self _injectOutlookQuirksScript];
968    }
969#endif
970
971#if PLATFORM(IOS)
972    // Preserve the behavior we had before <rdar://problem/7580867>
973    // by enforcing a 5MB limit for session storage.
974    _private->page->settings().setSessionStorageQuota(5 * 1024 * 1024);
975
976    [self _updateScreenScaleFromWindow];
977    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_wakWindowScreenScaleChanged:) name:WAKWindowScreenScaleDidChangeNotification object:nil];
978    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_wakWindowVisibilityChanged:) name:WAKWindowVisibilityDidChangeNotification object:nil];
979    _private->_fixedPositionContent = [[WebFixedPositionContent alloc] initWithWebView:self];
980#endif
981
982    if ([[NSUserDefaults standardUserDefaults] objectForKey:WebSmartInsertDeleteEnabled])
983        [self setSmartInsertDeleteEnabled:[[NSUserDefaults standardUserDefaults] boolForKey:WebSmartInsertDeleteEnabled]];
984
985    [WebFrame _createMainFrameWithPage:_private->page frameName:frameName frameView:frameView];
986
987#if !PLATFORM(IOS)
988    NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
989
990    if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOADING_DURING_COMMON_RUNLOOP_MODES))
991        [self scheduleInRunLoop:runLoop forMode:(NSString *)kCFRunLoopCommonModes];
992    else
993        [self scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode];
994#endif
995
996    [self _addToAllWebViewsSet];
997    [self setGroupName:groupName];
998
999    // If there's already a next key view (e.g., from a nib), wire it up to our
1000    // contained frame view. In any case, wire our next key view up to the our
1001    // contained frame view. This works together with our becomeFirstResponder
1002    // and setNextKeyView overrides.
1003    NSView *nextKeyView = [self nextKeyView];
1004    if (nextKeyView && nextKeyView != frameView)
1005        [frameView setNextKeyView:nextKeyView];
1006    [super setNextKeyView:frameView];
1007
1008    if ([[self class] shouldIncludeInWebKitStatistics])
1009        ++WebViewCount;
1010
1011#if !PLATFORM(IOS)
1012    [self _registerDraggedTypes];
1013#endif
1014
1015    [self _setIsVisible:[self _isViewVisible]];
1016
1017    WebPreferences *prefs = [self preferences];
1018    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1019                                                 name:WebPreferencesChangedInternalNotification object:prefs];
1020
1021#if !PLATFORM(IOS)
1022    [self _preferencesChanged:[self preferences]];
1023    [[self preferences] _postPreferencesChangedAPINotification];
1024#else
1025    // do this on the current thread on iOS, since the web thread could be blocked on the main thread,
1026    // and prefs need to be changed synchronously <rdar://problem/5841558>
1027    [self _preferencesChanged:prefs];
1028    _private->page->settings().setFontFallbackPrefersPictographs(true);
1029#endif
1030
1031    memoryPressureHandler().install();
1032
1033    if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION)) {
1034        // Originally, we allowed all local loads.
1035        SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForAll);
1036    } else if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MORE_STRICT_LOCAL_RESOURCE_SECURITY_RESTRICTION)) {
1037        // Later, we allowed local loads for local URLs and documents loaded
1038        // with substitute data.
1039        SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalAndSubstituteData);
1040    }
1041
1042#if !PLATFORM(IOS)
1043    if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_CONTENT_SNIFFING_FOR_FILE_URLS))
1044        ResourceHandle::forceContentSniffing();
1045#endif
1046
1047#if USE(GLIB)
1048    [self _scheduleGlibContextIterations];
1049#endif
1050}
1051
1052- (id)_initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName
1053{
1054    self = [super initWithFrame:f];
1055    if (!self)
1056        return nil;
1057
1058#ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
1059    // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
1060    // may not work with other WebKit applications.  Unsetting DYLD_FRAMEWORK_PATH removes the
1061    // need for Safari to unset it to prevent it from being passed to applications it launches.
1062    // Unsetting it when a WebView is first created is as good a place as any.
1063    // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details.
1064    if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
1065        unsetenv("DYLD_FRAMEWORK_PATH");
1066        unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
1067    }
1068#endif
1069
1070    _private = [[WebViewPrivate alloc] init];
1071    [self _commonInitializationWithFrameName:frameName groupName:groupName];
1072    [self setMaintainsBackForwardList: YES];
1073#if !PLATFORM(IOS)
1074    _private->page->setDeviceScaleFactor([self _deviceScaleFactor]);
1075#endif
1076    return self;
1077}
1078
1079- (void)_viewWillDrawInternal
1080{
1081    Frame* frame = [self _mainCoreFrame];
1082    if (frame && frame->view())
1083        frame->view()->updateLayoutAndStyleIfNeededRecursive();
1084}
1085
1086+ (NSArray *)_supportedMIMETypes
1087{
1088    // Load the plug-in DB allowing plug-ins to install types.
1089    [WebPluginDatabase sharedDatabase];
1090    return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
1091}
1092
1093#if !PLATFORM(IOS)
1094+ (NSArray *)_supportedFileExtensions
1095{
1096    NSMutableSet *extensions = [[NSMutableSet alloc] init];
1097    NSArray *MIMETypes = [self _supportedMIMETypes];
1098    NSEnumerator *enumerator = [MIMETypes objectEnumerator];
1099    NSString *MIMEType;
1100    while ((MIMEType = [enumerator nextObject]) != nil) {
1101        NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType);
1102        if (extensionsForType) {
1103            [extensions addObjectsFromArray:extensionsForType];
1104        }
1105    }
1106    NSArray *uniqueExtensions = [extensions allObjects];
1107    [extensions release];
1108    return uniqueExtensions;
1109}
1110#endif
1111
1112#if PLATFORM(IOS)
1113+ (void)enableWebThread
1114{
1115    static BOOL isWebThreadEnabled = NO;
1116    if (!isWebThreadEnabled) {
1117        WebCoreObjCDeallocOnWebThread([WebBasePluginPackage class]);
1118        WebCoreObjCDeallocOnWebThread([WebDataSource class]);
1119        WebCoreObjCDeallocOnWebThread([WebFrame class]);
1120        WebCoreObjCDeallocOnWebThread([WebHTMLView class]);
1121        WebCoreObjCDeallocOnWebThread([WebHistoryItem class]);
1122        WebCoreObjCDeallocOnWebThread([WebPlainWhiteView class]);
1123        WebCoreObjCDeallocOnWebThread([WebPolicyDecisionListener class]);
1124        WebCoreObjCDeallocOnWebThread([WebView class]);
1125        WebCoreObjCDeallocOnWebThread([WebVisiblePosition class]);
1126        if (applicationIsTheEconomistOnIPhone() && !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_DELEGATE_CALLS_IN_COMMON_RUNLOOP_MODES))
1127            WebThreadSetDelegateSourceRunLoopMode(kCFRunLoopDefaultMode);
1128        WebThreadEnable();
1129        isWebThreadEnabled = YES;
1130    }
1131}
1132
1133- (id)initSimpleHTMLDocumentWithStyle:(NSString *)style frame:(CGRect)frame preferences:(WebPreferences *)preferences groupName:(NSString *)groupName
1134{
1135    self = [super initWithFrame:frame];
1136    if (!self)
1137        return nil;
1138
1139    _private = [[WebViewPrivate alloc] init];
1140
1141#ifndef NDEBUG
1142    WTF::RefCountedLeakCounter::suppressMessages(webViewIsOpen);
1143#endif
1144
1145    if (!preferences)
1146        preferences = [WebPreferences standardPreferences];
1147    [preferences willAddToWebView];
1148
1149    _private->preferences = [preferences retain];
1150    _private->mainFrameDocumentReady = NO;
1151    _private->drawsBackground = YES;
1152    _private->backgroundColor = CGColorRetain(cachedCGColor(Color::white, ColorSpaceDeviceRGB));
1153
1154    WebFrameView *frameView = nil;
1155    frameView = [[WebFrameView alloc] initWithFrame: CGRectMake(0,0,frame.size.width,frame.size.height)];
1156    [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
1157    [self addSubview:frameView];
1158    [frameView release];
1159
1160
1161    Page::PageClients pageClients;
1162    pageClients.chromeClient = new WebChromeClientIOS(self);
1163#if ENABLE(DRAG_SUPPORT)
1164    pageClients.dragClient = new WebDragClient(self);
1165#endif
1166    pageClients.editorClient = new WebEditorClient(self);
1167    pageClients.inspectorClient = new WebInspectorClient(self);
1168    pageClients.loaderClientForMainFrame = new WebFrameLoaderClient;
1169    pageClients.progressTrackerClient = new WebProgressTrackerClient(self);
1170    _private->page = new Page(pageClients);
1171
1172    [self setSmartInsertDeleteEnabled:YES];
1173
1174    // FIXME: <rdar://problem/6851451> Should respect preferences in fast path WebView initialization
1175    // We are ignoring the preferences object on fast path and just using Settings defaults (everything fancy off).
1176    // This matches how UIKit sets up the preferences. We need to set  default values for fonts though, <rdar://problem/6850611>.
1177    // This should be revisited later. There is some risk involved, _preferencesChanged used to show up badly in Shark.
1178    _private->page->settings().setMinimumLogicalFontSize(9);
1179    _private->page->settings().setDefaultFontSize([_private->preferences defaultFontSize]);
1180    _private->page->settings().setDefaultFixedFontSize(13);
1181    _private->page->settings().setDownloadableBinaryFontsEnabled(false);
1182    _private->page->settings().setAcceleratedDrawingEnabled([preferences acceleratedDrawingEnabled]);
1183    _private->page->settings().setScreenFontSubstitutionEnabled(false);
1184
1185    // FIXME: <rdar://problem/7394370> Always use primary font baseline in text field base line calculation, ignore fallback fonts.
1186    _private->page->settings().setAlwaysUseBaselineOfPrimaryFont([preferences _alwaysUseBaselineOfPrimaryFont]);
1187
1188    _private->page->settings().setFontFallbackPrefersPictographs(true);
1189    _private->page->settings().setPictographFontFamily("AppleColorEmoji");
1190
1191    // FIXME: this is a workaround for <rdar://problem/11518688> REGRESSION: Quoted text font changes when replying to certain email
1192    _private->page->settings().setStandardFontFamily([_private->preferences standardFontFamily]);
1193
1194    // FIXME: this is a workaround for <rdar://problem/11820090> Quoted text changes in size when replying to certain email
1195    _private->page->settings().setMinimumFontSize([_private->preferences minimumFontSize]);
1196
1197    [self setGroupName:groupName];
1198
1199#if ENABLE(REMOTE_INSPECTOR)
1200    _private->page->setRemoteInspectionAllowed(isInternalInstall());
1201#endif
1202
1203    [self _updateScreenScaleFromWindow];
1204    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_wakWindowScreenScaleChanged:) name:WAKWindowScreenScaleDidChangeNotification object:nil];
1205    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_wakWindowVisibilityChanged:) name:WAKWindowVisibilityDidChangeNotification object:nil];
1206
1207    [WebFrame _createMainFrameWithSimpleHTMLDocumentWithPage:_private->page frameView:frameView style:style];
1208
1209    [self _addToAllWebViewsSet];
1210
1211    ++WebViewCount;
1212
1213    SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalAndSubstituteData);
1214
1215    return self;
1216}
1217
1218+ (void)_handleMemoryWarning
1219{
1220    ASSERT(WebThreadIsCurrent());
1221    WebKit::MemoryMeasure totalMemory("Memory warning: Overall memory change from [WebView _handleMemoryWarning].");
1222
1223    // Always peform the following.
1224    [WebView purgeInactiveFontData];
1225
1226    // Only perform the remaining if a non-simple document was created.
1227    if (!didOneTimeInitialization)
1228        return;
1229
1230    tileControllerMemoryHandler().trimUnparentedTilesToTarget(0);
1231
1232#if ENABLE(DISK_IMAGE_CACHE)
1233    {
1234        WebKit::MemoryMeasure measurer("Memory warning: flushing images to disk.");
1235        WebCore::memoryCache()->flushCachedImagesToDisk();
1236    }
1237#endif
1238
1239    [WebStorageManager closeIdleLocalStorageDatabases];
1240
1241    [WebView _releaseMemoryNow];
1242}
1243
1244+ (void)registerForMemoryNotifications
1245{
1246    BOOL shouldAutoClearPressureOnMemoryRelease = !WebCore::applicationIsMobileSafari();
1247
1248    memoryPressureHandler().installMemoryReleaseBlock(^{
1249        [WebView _handleMemoryWarning];
1250    }, shouldAutoClearPressureOnMemoryRelease);
1251
1252#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
1253    static dispatch_source_t memoryNotificationEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYSTATUS, 0, DISPATCH_MEMORYSTATUS_PRESSURE_WARN, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1254#else
1255    static dispatch_source_t memoryNotificationEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_VM, 0, DISPATCH_VM_PRESSURE, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1256#endif
1257    dispatch_source_set_event_handler(memoryNotificationEventSource, ^{
1258        // Set memory pressure flag and schedule releasing memory in web thread runloop exit.
1259        memoryPressureHandler().setReceivedMemoryPressure(WebCore::MemoryPressureReasonVMPressure);
1260    });
1261
1262    dispatch_resume(memoryNotificationEventSource);
1263
1264    if (!shouldAutoClearPressureOnMemoryRelease) {
1265        // Listen to memory status notification to reset the memory pressure flag.
1266        static dispatch_source_t memoryStatusEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYSTATUS,
1267                                                                                    0,
1268                                                                                    DISPATCH_MEMORYSTATUS_PRESSURE_WARN | DISPATCH_MEMORYSTATUS_PRESSURE_NORMAL,
1269                                                                                    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1270        dispatch_source_set_event_handler(memoryStatusEventSource, ^{
1271            unsigned long currentStatus = dispatch_source_get_data(memoryStatusEventSource);
1272            if (currentStatus == DISPATCH_MEMORYSTATUS_PRESSURE_NORMAL)
1273                memoryPressureHandler().clearMemoryPressure();
1274            else if (currentStatus == DISPATCH_MEMORYSTATUS_PRESSURE_WARN)
1275                memoryPressureHandler().setReceivedMemoryPressure(WebCore::MemoryPressureReasonVMStatus);
1276        });
1277
1278        dispatch_resume(memoryStatusEventSource);
1279    }
1280}
1281
1282+ (void)_releaseMemoryNow
1283{
1284    ASSERT(WebThreadIsCurrent());
1285    [WebView discardAllCompiledCode];
1286    [WebView garbageCollectNow];
1287    [WebView purgeInactiveFontData];
1288    [WebView drainLayerPool];
1289    [WebCache emptyInMemoryResources];
1290    [WebView releaseFastMallocMemoryOnCurrentThread];
1291
1292    dispatch_async(dispatch_get_main_queue(), ^{
1293        // Clear the main thread's TCMalloc thread cache.
1294        [WebView releaseFastMallocMemoryOnCurrentThread];
1295    });
1296}
1297
1298+ (void)_clearPrivateBrowsingSessionCookieStorage
1299{
1300    WebFrameNetworkingContext::clearPrivateBrowsingSessionCookieStorage();
1301}
1302
1303- (void)_replaceCurrentHistoryItem:(WebHistoryItem *)item
1304{
1305    Frame* frame = [self _mainCoreFrame];
1306    if (frame)
1307        frame->loader().history().replaceCurrentItem(core(item));
1308}
1309
1310+ (void)willEnterBackgroundWithCompletionHandler:(void(^)(void))handler
1311{
1312    WebThreadRun(^{
1313        [WebView _releaseMemoryNow];
1314        dispatch_async(dispatch_get_main_queue(), handler);
1315    });
1316}
1317
1318+ (void)releaseFastMallocMemoryOnCurrentThread
1319{
1320    WebKit::MemoryMeasure measurer("Memory warning: Releasing fast malloc memory to system.");
1321    WTF::releaseFastMallocFreeMemory();
1322}
1323
1324+ (void)garbageCollectNow
1325{
1326    ASSERT(WebThreadIsCurrent());
1327    WebKit::MemoryMeasure measurer("Memory warning: Calling JavaScript GC.");
1328    gcController().garbageCollectNow();
1329}
1330
1331+ (void)purgeInactiveFontData
1332{
1333    ASSERT(WebThreadIsCurrent());
1334    WebKit::MemoryMeasure measurer("Memory warning: Purging inactive font data.");
1335    fontCache().purgeInactiveFontData();
1336}
1337
1338+ (void)drainLayerPool
1339{
1340    ASSERT(WebThreadIsCurrent());
1341    WebKit::MemoryMeasure measurer("Memory warning: Draining layer pool.");
1342    WebCore::LegacyTileCache::drainLayerPool();
1343}
1344
1345+ (void)discardAllCompiledCode
1346{
1347    ASSERT(WebThreadIsCurrent());
1348    WebKit::MemoryMeasure measurer("Memory warning: Discarding JIT'ed code.");
1349    gcController().discardAllCompiledCode();
1350}
1351
1352+ (BOOL)isCharacterSmartReplaceExempt:(unichar)character isPreviousCharacter:(BOOL)b
1353{
1354    return WebCore::isCharacterSmartReplaceExempt(character, b);
1355}
1356
1357- (void)updateLayoutIgnorePendingStyleSheets
1358{
1359    WebThreadRun(^{
1360        for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree().traverseNext()) {
1361            Document *document = frame->document();
1362            if (document)
1363                document->updateLayoutIgnorePendingStylesheets();
1364        }
1365    });
1366}
1367#endif // PLATFORM(IOS)
1368
1369static NSMutableSet *knownPluginMIMETypes()
1370{
1371    static NSMutableSet *mimeTypes = [[NSMutableSet alloc] init];
1372
1373    return mimeTypes;
1374}
1375
1376+ (void)_registerPluginMIMEType:(NSString *)MIMEType
1377{
1378    [WebView registerViewClass:[WebHTMLView class] representationClass:[WebHTMLRepresentation class] forMIMEType:MIMEType];
1379    [knownPluginMIMETypes() addObject:MIMEType];
1380}
1381
1382+ (void)_unregisterPluginMIMEType:(NSString *)MIMEType
1383{
1384    [self _unregisterViewClassAndRepresentationClassForMIMEType:MIMEType];
1385    [knownPluginMIMETypes() removeObject:MIMEType];
1386}
1387
1388+ (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
1389{
1390    MIMEType = [MIMEType lowercaseString];
1391    Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
1392    Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
1393
1394#if PLATFORM(IOS)
1395#define WebPDFView ([WebView _getPDFViewClass])
1396#endif
1397    if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) {
1398#if PLATFORM(IOS)
1399#undef WebPDFView
1400#endif
1401        // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed.
1402
1403        if (allowPlugins) {
1404            // Load the plug-in DB allowing plug-ins to install types.
1405            [WebPluginDatabase sharedDatabase];
1406        }
1407
1408        // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
1409        viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
1410        repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
1411    }
1412
1413    if (viewClass && repClass) {
1414        if (viewClass == [WebHTMLView class] && repClass == [WebHTMLRepresentation class]) {
1415            // Special-case WebHTMLView for text types that shouldn't be shown.
1416            if ([[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType])
1417                return NO;
1418
1419            // If the MIME type is a known plug-in we might not want to load it.
1420            if (!allowPlugins && [knownPluginMIMETypes() containsObject:MIMEType]) {
1421                BOOL isSupportedByWebKit = [[WebHTMLView supportedNonImageMIMETypes] containsObject:MIMEType] ||
1422                    [[WebHTMLView supportedMIMETypes] containsObject:MIMEType];
1423
1424                // If this is a known plug-in MIME type and WebKit can't show it natively, we don't want to show it.
1425                if (!isSupportedByWebKit)
1426                    return NO;
1427            }
1428        }
1429        if (vClass)
1430            *vClass = viewClass;
1431        if (rClass)
1432            *rClass = repClass;
1433        return YES;
1434    }
1435
1436    return NO;
1437}
1438
1439- (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType
1440{
1441    if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType allowingPlugins:[_private->preferences arePlugInsEnabled]])
1442        return YES;
1443#if !PLATFORM(IOS)
1444    if (_private->pluginDatabase) {
1445        WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType];
1446        if (pluginPackage) {
1447            if (vClass)
1448                *vClass = [WebHTMLView class];
1449            if (rClass)
1450                *rClass = [WebHTMLRepresentation class];
1451            return YES;
1452        }
1453    }
1454#endif
1455    return NO;
1456}
1457
1458+ (void)_setAlwaysUsesComplexTextCodePath:(BOOL)f
1459{
1460    Font::setCodePath(f ? Font::Complex : Font::Auto);
1461}
1462
1463+ (void)_setAllowsRoundingHacks:(BOOL)allowsRoundingHacks
1464{
1465    TextRun::setAllowsRoundingHacks(allowsRoundingHacks);
1466}
1467
1468+ (BOOL)_allowsRoundingHacks
1469{
1470    return TextRun::allowsRoundingHacks();
1471}
1472
1473+ (BOOL)canCloseAllWebViews
1474{
1475    return DOMWindow::dispatchAllPendingBeforeUnloadEvents();
1476}
1477
1478+ (void)closeAllWebViews
1479{
1480    DOMWindow::dispatchAllPendingUnloadEvents();
1481
1482    // This will close the WebViews in a random order. Change this if close order is important.
1483    // Make a new set to avoid mutating the set we are enumerating.
1484    NSSet *webViewsToClose = [NSSet setWithSet:(NSSet *)allWebViewsSet];
1485    NSEnumerator *enumerator = [webViewsToClose objectEnumerator];
1486    while (WebView *webView = [enumerator nextObject])
1487        [webView close];
1488}
1489
1490+ (BOOL)canShowFile:(NSString *)path
1491{
1492    return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
1493}
1494
1495#if !PLATFORM(IOS)
1496+ (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
1497{
1498    return WKGetPreferredExtensionForMIMEType(type);
1499}
1500#endif
1501
1502- (BOOL)_isClosed
1503{
1504    return !_private || _private->closed;
1505}
1506
1507#if PLATFORM(IOS)
1508- (void)_dispatchUnloadEvent
1509{
1510    WebThreadRun(^{
1511        WebFrame *mainFrame = [self mainFrame];
1512        Frame *coreMainFrame = core(mainFrame);
1513        if (coreMainFrame) {
1514            Document *document = coreMainFrame->document();
1515            if (document)
1516                document->dispatchWindowEvent(Event::create(eventNames().unloadEvent, false, false));
1517        }
1518    });
1519}
1520
1521- (DOMCSSStyleDeclaration *)styleAtSelectionStart
1522{
1523    WebFrame *mainFrame = [self mainFrame];
1524    Frame *coreMainFrame = core(mainFrame);
1525    if (!coreMainFrame)
1526        return nil;
1527    return coreMainFrame->styleAtSelectionStart();
1528}
1529
1530- (NSUInteger)_renderTreeSize
1531{
1532    if (!_private->page)
1533        return 0;
1534    return _private->page->renderTreeSize();
1535}
1536
1537- (void)_dispatchTileDidDraw:(CALayer*)tile
1538{
1539    id mailDelegate = [self _webMailDelegate];
1540    if ([mailDelegate respondsToSelector:@selector(_webthread_webView:tileDidDraw:)]) {
1541        [mailDelegate _webthread_webView:self tileDidDraw:tile];
1542        return;
1543    }
1544
1545    if (!OSAtomicCompareAndSwap32(0, 1, &_private->didDrawTiles))
1546        return;
1547
1548    WebThreadLock();
1549
1550    [[[self _UIKitDelegateForwarder] asyncForwarder] webViewDidDrawTiles:self];
1551}
1552
1553- (void)_willStartScrollingOrZooming
1554{
1555    // Pause timers during top level interaction
1556    if (_private->mainViewIsScrollingOrZooming)
1557        return;
1558    _private->mainViewIsScrollingOrZooming = YES;
1559
1560    // This suspends active DOM objects like timers, but not media.
1561    [[self mainFrame] setTimeoutsPaused:YES];
1562
1563    // This defers loading callbacks only.
1564    // WARNING: This behavior could change if Bug 49401 lands in open source WebKit again.
1565    [self setDefersCallbacks:YES];
1566}
1567
1568- (void)_didFinishScrollingOrZooming
1569{
1570    if (!_private->mainViewIsScrollingOrZooming)
1571        return;
1572    _private->mainViewIsScrollingOrZooming = NO;
1573    [self setDefersCallbacks:NO];
1574    [[self mainFrame] setTimeoutsPaused:NO];
1575    if (FrameView* view = [self _mainCoreFrame]->view())
1576        view->resumeVisibleImageAnimationsIncludingSubframes();
1577}
1578
1579- (void)_setResourceLoadSchedulerSuspended:(BOOL)suspend
1580{
1581    if (suspend)
1582        resourceLoadScheduler()->suspendPendingRequests();
1583    else
1584        resourceLoadScheduler()->resumePendingRequests();
1585}
1586
1587+ (void)_setAllowCookies:(BOOL)allow
1588{
1589    ResourceRequestBase::setDefaultAllowCookies(allow);
1590}
1591
1592+ (BOOL)_allowCookies
1593{
1594    return ResourceRequestBase::defaultAllowCookies();
1595}
1596
1597+ (BOOL)_isUnderMemoryPressure
1598{
1599    return memoryPressureHandler().isUnderMemoryPressure();
1600}
1601
1602+ (void)_clearMemoryPressure
1603{
1604    memoryPressureHandler().clearMemoryPressure();
1605}
1606
1607+ (BOOL)_shouldWaitForMemoryClearMessage
1608{
1609    return memoryPressureHandler().shouldWaitForMemoryClearMessage();
1610}
1611#endif // PLATFORM(IOS)
1612
1613- (void)_closePluginDatabases
1614{
1615    pluginDatabaseClientCount--;
1616
1617    // Close both sets of plug-in databases because plug-ins need an opportunity to clean up files, etc.
1618
1619#if !PLATFORM(IOS)
1620    // Unload the WebView local plug-in database.
1621    if (_private->pluginDatabase) {
1622        [_private->pluginDatabase destroyAllPluginInstanceViews];
1623        [_private->pluginDatabase close];
1624        [_private->pluginDatabase release];
1625        _private->pluginDatabase = nil;
1626    }
1627#endif
1628
1629    // Keep the global plug-in database active until the app terminates to avoid having to reload plug-in bundles.
1630    if (!pluginDatabaseClientCount && applicationIsTerminating)
1631        [WebPluginDatabase closeSharedDatabase];
1632}
1633
1634- (void)_closeWithFastTeardown
1635{
1636#ifndef NDEBUG
1637    WTF::RefCountedLeakCounter::suppressMessages("At least one WebView was closed with fast teardown.");
1638#endif
1639
1640#if !PLATFORM(IOS)
1641    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
1642#endif
1643    [[NSNotificationCenter defaultCenter] removeObserver:self];
1644
1645    [self _closePluginDatabases];
1646}
1647
1648static bool fastDocumentTeardownEnabled()
1649{
1650#ifdef NDEBUG
1651    static bool enabled = ![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableFullDocumentTeardownPreferenceKey];
1652#else
1653    static bool initialized = false;
1654    static bool enabled = false;
1655    if (!initialized) {
1656        // This allows debug builds to default to not have fast teardown, so leak checking still works.
1657        // But still allow the WebKitEnableFullDocumentTeardown default to override it if present.
1658        NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitEnableFullDocumentTeardownPreferenceKey];
1659        if (setting)
1660            enabled = ![setting boolValue];
1661        initialized = true;
1662    }
1663#endif
1664    return enabled;
1665}
1666
1667// _close is here only for backward compatibility; clients and subclasses should use
1668// public method -close instead.
1669- (void)_close
1670{
1671#if PLATFORM(IOS)
1672    // Always clear delegates on calling thread, becasue caller can deallocate delegates right after calling -close
1673    // (and could in fact already be in delegate's -dealloc method, as seen in <rdar://problem/11540972>).
1674
1675    [self _clearDelegates];
1676
1677    // Fix for problems such as <rdar://problem/5774587> Crash closing tab in WebCore::Frame::page() from -[WebCoreFrameBridge pauseTimeouts]
1678    WebThreadRun(^{
1679#endif
1680
1681    if (!_private || _private->closed)
1682        return;
1683
1684    [[NSNotificationCenter defaultCenter] postNotificationName:WebViewWillCloseNotification object:self];
1685
1686    _private->closed = YES;
1687    [self _removeFromAllWebViewsSet];
1688
1689#ifndef NDEBUG
1690    WTF::RefCountedLeakCounter::cancelMessageSuppression(webViewIsOpen);
1691#endif
1692
1693    // To quit the apps fast we skip document teardown, except plugins
1694    // need to be destroyed and unloaded.
1695    if (applicationIsTerminating && fastDocumentTeardownEnabled()) {
1696        [self _closeWithFastTeardown];
1697        return;
1698    }
1699
1700#if ENABLE(VIDEO) && !PLATFORM(IOS)
1701    [self _exitFullscreen];
1702#endif
1703
1704#if PLATFORM(IOS)
1705    _private->closing = YES;
1706#endif
1707
1708    if (Frame* mainFrame = [self _mainCoreFrame])
1709        mainFrame->loader().detachFromParent();
1710
1711    [self setHostWindow:nil];
1712
1713#if !PLATFORM(IOS)
1714    [self setDownloadDelegate:nil];
1715    [self setEditingDelegate:nil];
1716    [self setFrameLoadDelegate:nil];
1717    [self setPolicyDelegate:nil];
1718    [self setResourceLoadDelegate:nil];
1719    [self setScriptDebugDelegate:nil];
1720    [self setUIDelegate:nil];
1721
1722    [_private->inspector webViewClosed];
1723#endif
1724
1725#if !PLATFORM(IOS)
1726    // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
1727    [self removeDragCaret];
1728#endif
1729
1730    _private->group->removeWebView(self);
1731
1732    // Deleteing the WebCore::Page will clear the page cache so we call destroy on
1733    // all the plug-ins in the page cache to break any retain cycles.
1734    // See comment in HistoryItem::releaseAllPendingPageCaches() for more information.
1735    Page* page = _private->page;
1736    _private->page = 0;
1737    delete page;
1738
1739#if !PLATFORM(IOS)
1740    if (_private->hasSpellCheckerDocumentTag) {
1741        [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
1742        _private->hasSpellCheckerDocumentTag = NO;
1743    }
1744#endif
1745
1746    if (_private->layerFlushController) {
1747        _private->layerFlushController->invalidate();
1748        _private->layerFlushController = nullptr;
1749    }
1750
1751#if USE(GLIB)
1752    [self _clearGlibLoopObserver];
1753#endif
1754
1755    [[self _notificationProvider] unregisterWebView:self];
1756
1757#if !PLATFORM(IOS)
1758    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
1759#endif
1760    [[NSNotificationCenter defaultCenter] removeObserver:self];
1761
1762    [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]];
1763
1764    WebPreferences *preferences = _private->preferences;
1765    _private->preferences = nil;
1766    [preferences didRemoveFromWebView];
1767    [preferences release];
1768
1769    [self _closePluginDatabases];
1770
1771#ifndef NDEBUG
1772    // Need this to make leak messages accurate.
1773    if (applicationIsTerminating) {
1774        gcController().garbageCollectNow();
1775        [WebCache setDisabled:YES];
1776    }
1777#endif
1778#if PLATFORM(IOS)
1779    // Fix for problems such as <rdar://problem/5774587> Crash closing tab in WebCore::Frame::page() from -[WebCoreFrameBridge pauseTimeouts]
1780    });
1781#endif
1782}
1783
1784// Indicates if the WebView is in the midst of a user gesture.
1785- (BOOL)_isProcessingUserGesture
1786{
1787    return ScriptController::processingUserGesture();
1788}
1789
1790+ (NSString *)_MIMETypeForFile:(NSString *)path
1791{
1792#if !PLATFORM(IOS)
1793    NSString *extension = [path pathExtension];
1794#endif
1795    NSString *MIMEType = nil;
1796
1797#if !PLATFORM(IOS)
1798    // Get the MIME type from the extension.
1799    if ([extension length] != 0) {
1800        MIMEType = WKGetMIMETypeForExtension(extension);
1801    }
1802#endif
1803
1804    // If we can't get a known MIME type from the extension, sniff.
1805    if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
1806        NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
1807        NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
1808        [handle closeFile];
1809        if ([data length] != 0) {
1810            MIMEType = [data _webkit_guessedMIMEType];
1811        }
1812        if ([MIMEType length] == 0) {
1813            MIMEType = @"application/octet-stream";
1814        }
1815    }
1816
1817    return MIMEType;
1818}
1819
1820- (WebDownload *)_downloadURL:(NSURL *)URL
1821{
1822    ASSERT(URL);
1823
1824    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
1825    WebDownload *download = [WebDownload _downloadWithRequest:request
1826                                                     delegate:_private->downloadDelegate
1827                                                    directory:nil];
1828    [request release];
1829
1830    return download;
1831}
1832
1833- (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
1834{
1835    NSDictionary *features = [[NSDictionary alloc] init];
1836    WebView *newWindowWebView = [[self _UIDelegateForwarder] webView:self
1837                                            createWebViewWithRequest:nil
1838                                                      windowFeatures:features];
1839    [features release];
1840    if (!newWindowWebView)
1841        return nil;
1842
1843    CallUIDelegate(newWindowWebView, @selector(webViewShow:));
1844    return newWindowWebView;
1845}
1846
1847- (WebInspector *)inspector
1848{
1849    if (!_private->inspector)
1850        _private->inspector = [[WebInspector alloc] initWithWebView:self];
1851    return _private->inspector;
1852}
1853
1854#if ENABLE(REMOTE_INSPECTOR)
1855+ (void)_enableRemoteInspector
1856{
1857    RemoteInspector::shared().start();
1858}
1859
1860+ (void)_disableRemoteInspector
1861{
1862    RemoteInspector::shared().stop();
1863}
1864
1865+ (void)_disableAutoStartRemoteInspector
1866{
1867    RemoteInspector::startDisabled();
1868}
1869
1870+ (BOOL)_isRemoteInspectorEnabled
1871{
1872    return RemoteInspector::shared().enabled();
1873}
1874
1875+ (BOOL)_hasRemoteInspectorSession
1876{
1877    return RemoteInspector::shared().hasActiveDebugSession();
1878}
1879
1880- (BOOL)allowsRemoteInspection
1881{
1882    return _private->page->remoteInspectionAllowed();
1883}
1884
1885- (void)setAllowsRemoteInspection:(BOOL)allow
1886{
1887    _private->page->setRemoteInspectionAllowed(allow);
1888}
1889
1890- (void)setShowingInspectorIndication:(BOOL)showing
1891{
1892#if PLATFORM(IOS)
1893    ASSERT(WebThreadIsLocked());
1894
1895    if (showing) {
1896        if (!_private->indicateLayer) {
1897            _private->indicateLayer = [[WebIndicateLayer alloc] initWithWebView:self];
1898            [_private->indicateLayer setNeedsLayout];
1899            [[[self window] hostLayer] addSublayer:_private->indicateLayer];
1900        }
1901    } else {
1902        [_private->indicateLayer removeFromSuperlayer];
1903        [_private->indicateLayer release];
1904        _private->indicateLayer = nil;
1905    }
1906#else
1907    // Implemented in WebCore::InspectorOverlay.
1908#endif
1909}
1910
1911#if PLATFORM(IOS)
1912- (void)_setHostApplicationProcessIdentifier:(pid_t)pid auditToken:(audit_token_t)auditToken
1913{
1914    RetainPtr<CFDataRef> auditData = adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
1915    RemoteInspector::shared().setParentProcessInformation(pid, auditData);
1916}
1917#endif // PLATFORM(IOS)
1918#endif // ENABLE(REMOTE_INSPECTOR)
1919
1920- (WebCore::Page*)page
1921{
1922    return _private->page;
1923}
1924
1925#if !PLATFORM(IOS)
1926- (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items
1927{
1928    NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate] webView:self contextMenuItemsForElement:element defaultMenuItems:items];
1929    NSArray *menuItems = defaultMenuItems;
1930
1931    // CallUIDelegate returns nil if UIDelegate is nil or doesn't respond to the selector. So we need to check that here
1932    // to distinguish between using defaultMenuItems or the delegate really returning nil to say "no context menu".
1933    SEL selector = @selector(webView:contextMenuItemsForElement:defaultMenuItems:);
1934    if (_private->UIDelegate && [_private->UIDelegate respondsToSelector:selector]) {
1935        menuItems = CallUIDelegate(self, selector, element, defaultMenuItems);
1936        if (!menuItems)
1937            return nil;
1938    }
1939
1940    unsigned count = [menuItems count];
1941    if (!count)
1942        return nil;
1943
1944    NSMenu *menu = [[NSMenu alloc] init];
1945    for (unsigned i = 0; i < count; i++)
1946        [menu addItem:[menuItems objectAtIndex:i]];
1947
1948    return [menu autorelease];
1949}
1950#endif
1951
1952- (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(NSUInteger)modifierFlags
1953{
1954    // We originally intended to call this delegate method sometimes with a nil dictionary, but due to
1955    // a bug dating back to WebKit 1.0 this delegate was never called with nil! Unfortunately we can't
1956    // start calling this with nil since it will break Adobe Help Viewer, and possibly other clients.
1957    if (!dictionary)
1958        return;
1959    CallUIDelegate(self, @selector(webView:mouseDidMoveOverElement:modifierFlags:), dictionary, modifierFlags);
1960}
1961
1962- (void)_loadBackForwardListFromOtherView:(WebView *)otherView
1963{
1964    if (!_private->page)
1965        return;
1966
1967    if (!otherView->_private->page)
1968        return;
1969
1970    // It turns out the right combination of behavior is done with the back/forward load
1971    // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
1972    // in the back forward list, and go to the current one.
1973
1974    BackForwardClient* backForwardClient = _private->page->backForward().client();
1975    ASSERT(!backForwardClient->currentItem()); // destination list should be empty
1976
1977    BackForwardClient* otherBackForwardClient = otherView->_private->page->backForward().client();
1978    if (!otherBackForwardClient->currentItem())
1979        return; // empty back forward list, bail
1980
1981    HistoryItem* newItemToGoTo = 0;
1982
1983    int lastItemIndex = otherBackForwardClient->forwardListCount();
1984    for (int i = -otherBackForwardClient->backListCount(); i <= lastItemIndex; ++i) {
1985        if (i == 0) {
1986            // If this item is showing , save away its current scroll and form state,
1987            // since that might have changed since loading and it is normally not saved
1988            // until we leave that page.
1989            otherView->_private->page->mainFrame().loader().history().saveDocumentAndScrollState();
1990        }
1991        RefPtr<HistoryItem> newItem = otherBackForwardClient->itemAtIndex(i)->copy();
1992        if (i == 0)
1993            newItemToGoTo = newItem.get();
1994        backForwardClient->addItem(newItem.release());
1995    }
1996
1997    ASSERT(newItemToGoTo);
1998    _private->page->goToItem(newItemToGoTo, FrameLoadType::IndexedBackForward);
1999}
2000
2001- (void)_setFormDelegate: (id<WebFormDelegate>)delegate
2002{
2003    _private->formDelegate = delegate;
2004#if PLATFORM(IOS)
2005    [_private->formDelegateForwarder clearTarget];
2006    [_private->formDelegateForwarder release];
2007    _private->formDelegateForwarder = nil;
2008#endif
2009}
2010
2011- (id<WebFormDelegate>)_formDelegate
2012{
2013    return _private->formDelegate;
2014}
2015
2016#if PLATFORM(IOS)
2017- (id)_formDelegateForwarder
2018{
2019    if (_private->closing)
2020        return nil;
2021
2022    if (!_private->formDelegateForwarder)
2023        _private->formDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:[self _formDelegate] defaultTarget:[WebDefaultFormDelegate sharedFormDelegate]];
2024    return _private->formDelegateForwarder;
2025}
2026
2027- (id)_formDelegateForSelector:(SEL)selector
2028{
2029    id delegate = self->_private->formDelegate;
2030    if ([delegate respondsToSelector:selector])
2031        return delegate;
2032
2033    delegate = [WebDefaultFormDelegate sharedFormDelegate];
2034    if ([delegate respondsToSelector:selector])
2035        return delegate;
2036
2037    return nil;
2038}
2039#endif
2040
2041#if !PLATFORM(IOS)
2042- (BOOL)_needsAdobeFrameReloadingQuirk
2043{
2044    static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0)
2045        || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0)
2046        || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0)
2047        || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0)
2048        || WKAppVersionCheckLessThan(@"com.adobe.Contribute", -1, 4.2)
2049        || WKAppVersionCheckLessThan(@"com.adobe.dreamweaver-9.0", -1, 9.1)
2050        || WKAppVersionCheckLessThan(@"com.macromedia.fireworks", -1, 9.1)
2051        || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1)
2052        || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1)
2053        || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2);
2054
2055    return needsQuirk;
2056}
2057
2058- (BOOL)_needsLinkElementTextCSSQuirk
2059{
2060    static BOOL needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LINK_ELEMENT_TEXT_CSS_QUIRK)
2061        && WKAppVersionCheckLessThan(@"com.e-frontier.shade10", -1, 10.6);
2062    return needsQuirk;
2063}
2064
2065- (BOOL)_needsIsLoadingInAPISenseQuirk
2066{
2067    static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.apple.iAdProducer", -1, 2.1);
2068
2069    return needsQuirk;
2070}
2071
2072- (BOOL)_needsKeyboardEventDisambiguationQuirks
2073{
2074    static BOOL needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) && !applicationIsSafari();
2075    return needsQuirks;
2076}
2077
2078- (BOOL)_needsFrameLoadDelegateRetainQuirk
2079{
2080    static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.equinux.iSale5", -1, 5.6);
2081    return needsQuirk;
2082}
2083
2084static bool needsSelfRetainWhileLoadingQuirk()
2085{
2086    static bool needsQuirk = applicationIsAperture();
2087    return needsQuirk;
2088}
2089#endif // !PLATFORM(IOS)
2090
2091- (BOOL)_needsPreHTML5ParserQuirks
2092{
2093#if !PLATFORM(IOS)
2094    // AOL Instant Messenger and Microsoft My Day contain markup incompatible
2095    // with the new HTML5 parser. If these applications were linked against a
2096    // version of WebKit prior to the introduction of the HTML5 parser, enable
2097    // parser quirks to maintain compatibility. For details, see
2098    // <https://bugs.webkit.org/show_bug.cgi?id=46134> and
2099    // <https://bugs.webkit.org/show_bug.cgi?id=46334>.
2100    static bool isApplicationNeedingParserQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_HTML5_PARSER)
2101        && (applicationIsAOLInstantMessenger() || applicationIsMicrosoftMyDay());
2102
2103    // Mail.app must continue to display HTML email that contains quirky markup.
2104    static bool isAppleMail = applicationIsAppleMail();
2105
2106    return isApplicationNeedingParserQuirks
2107        || isAppleMail
2108#if ENABLE(DASHBOARD_SUPPORT)
2109        // Pre-HTML5 parser quirks are required to remain compatible with many
2110        // Dashboard widgets. See <rdar://problem/8175982>.
2111        || (_private->page && _private->page->settings().usesDashboardBackwardCompatibilityMode())
2112#endif
2113        || [[self preferences] usePreHTML5ParserQuirks];
2114#else
2115    static bool isApplicationNeedingParserQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_HTML5_PARSER) && applicationIsDaijisenDictionary();
2116    return isApplicationNeedingParserQuirks || [[self preferences] usePreHTML5ParserQuirks];
2117#endif
2118}
2119
2120- (void)_preferencesChangedNotification:(NSNotification *)notification
2121{
2122#if PLATFORM(IOS)
2123    // For WebViews that load synchronously, preference changes need to be propagated
2124    // down to WebCore synchronously so that loads in that WebView have the correct
2125    // up-to-date settings.
2126    if (!WebThreadIsLocked())
2127        WebThreadLock();
2128    if ([[self mainFrame] _loadsSynchronously]) {
2129#endif
2130
2131    WebPreferences *preferences = (WebPreferences *)[notification object];
2132    [self _preferencesChanged:preferences];
2133
2134#if PLATFORM(IOS)
2135    } else {
2136        WebThreadRun(^{
2137            // It is possible that the prefs object has already changed before the invocation could be called
2138            // on the web thread. This is not possible on TOT which is why they have a simple ASSERT.
2139            WebPreferences *preferences = (WebPreferences *)[notification object];
2140            if (preferences != [self preferences])
2141                return;
2142            [self _preferencesChanged:preferences];
2143        });
2144    }
2145#endif
2146}
2147
2148- (void)_preferencesChanged:(WebPreferences *)preferences
2149{
2150    ASSERT(preferences == [self preferences]);
2151    if (!_private->userAgentOverridden)
2152        _private->userAgent = String();
2153
2154    // Cache this value so we don't have to read NSUserDefaults on each page load
2155    _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing];
2156
2157    // Update corresponding WebCore Settings object.
2158    if (!_private->page)
2159        return;
2160
2161#if PLATFORM(IOS)
2162    // iOS waits to call [WebDatabaseManager sharedWebDatabaseManager] until
2163    // didOneTimeInitialization is true so that we don't initialize databases
2164    // until the first WebView has been created. This is because database
2165    // initialization current requires disk access to populate the origins
2166    // quota map and we want to do this lazily by waiting until WebKit is
2167    // used to display web content in a WebView. The possible cases are:
2168    //   - on one time initialize (the first WebView creation) if databases are enabled (default)
2169    //   - when databases are dynamically enabled later, and they were disabled at startup (this case)
2170    if (didOneTimeInitialization) {
2171        if ([preferences databasesEnabled])
2172            [WebDatabaseManager sharedWebDatabaseManager];
2173
2174        if ([preferences storageTrackerEnabled])
2175            WebKitInitializeStorageIfNecessary();
2176    }
2177#endif
2178
2179    Settings& settings = _private->page->settings();
2180
2181    settings.setCursiveFontFamily([preferences cursiveFontFamily]);
2182    settings.setDefaultFixedFontSize([preferences defaultFixedFontSize]);
2183    settings.setDefaultFontSize([preferences defaultFontSize]);
2184    settings.setDefaultTextEncodingName([preferences defaultTextEncodingName]);
2185    settings.setUsesEncodingDetector([preferences usesEncodingDetector]);
2186    settings.setFantasyFontFamily([preferences fantasyFontFamily]);
2187    settings.setFixedFontFamily([preferences fixedFontFamily]);
2188    settings.setScreenFontSubstitutionEnabled(
2189#if !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
2190        [[NSUserDefaults standardUserDefaults] boolForKey:@"NSFontDefaultScreenFontSubstitutionEnabled"] ||
2191#endif
2192        [preferences screenFontSubstitutionEnabled]
2193    );
2194    settings.setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]);
2195    settings.setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]);
2196    settings.setLocalStorageDatabasePath([preferences _localStorageDatabasePath]);
2197    settings.setJavaEnabled([preferences isJavaEnabled]);
2198    settings.setScriptEnabled([preferences isJavaScriptEnabled]);
2199    settings.setWebSecurityEnabled([preferences isWebSecurityEnabled]);
2200    settings.setAllowUniversalAccessFromFileURLs([preferences allowUniversalAccessFromFileURLs]);
2201    settings.setAllowFileAccessFromFileURLs([preferences allowFileAccessFromFileURLs]);
2202    settings.setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]);
2203    settings.setMinimumFontSize([preferences minimumFontSize]);
2204    settings.setMinimumLogicalFontSize([preferences minimumLogicalFontSize]);
2205    settings.setPictographFontFamily([preferences pictographFontFamily]);
2206    settings.setPluginsEnabled([preferences arePlugInsEnabled]);
2207    settings.setLocalStorageEnabled([preferences localStorageEnabled]);
2208
2209    _private->page->enableLegacyPrivateBrowsing([preferences privateBrowsingEnabled]);
2210    settings.setSansSerifFontFamily([preferences sansSerifFontFamily]);
2211    settings.setSerifFontFamily([preferences serifFontFamily]);
2212    settings.setStandardFontFamily([preferences standardFontFamily]);
2213    settings.setLoadsImagesAutomatically([preferences loadsImagesAutomatically]);
2214    settings.setLoadsSiteIconsIgnoringImageLoadingSetting([preferences loadsSiteIconsIgnoringImageLoadingPreference]);
2215#if PLATFORM(IOS)
2216    settings.setShouldPrintBackgrounds(true);
2217#else
2218    settings.setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]);
2219#endif
2220    settings.setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]);
2221    settings.setEditableLinkBehavior(core([preferences editableLinkBehavior]));
2222    settings.setTextDirectionSubmenuInclusionBehavior(core([preferences textDirectionSubmenuInclusionBehavior]));
2223    settings.setDOMPasteAllowed([preferences isDOMPasteAllowed]);
2224    settings.setUsesPageCache([self usesPageCache]);
2225    settings.setPageCacheSupportsPlugins([preferences pageCacheSupportsPlugins]);
2226    settings.setBackForwardCacheExpirationInterval([preferences _backForwardCacheExpirationInterval]);
2227
2228    settings.setDeveloperExtrasEnabled([preferences developerExtrasEnabled]);
2229    settings.setJavaScriptExperimentsEnabled([preferences javaScriptExperimentsEnabled]);
2230    settings.setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]);
2231    settings.setApplicationChromeMode([preferences applicationChromeModeEnabled]);
2232
2233    settings.setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing);
2234    settings.setWebArchiveDebugModeEnabled([preferences webArchiveDebugModeEnabled]);
2235    settings.setLocalFileContentSniffingEnabled([preferences localFileContentSniffingEnabled]);
2236    settings.setOfflineWebApplicationCacheEnabled([preferences offlineWebApplicationCacheEnabled]);
2237    settings.setJavaScriptCanAccessClipboard([preferences javaScriptCanAccessClipboard]);
2238    settings.setXSSAuditorEnabled([preferences isXSSAuditorEnabled]);
2239    settings.setDNSPrefetchingEnabled([preferences isDNSPrefetchingEnabled]);
2240
2241    // FIXME: Enabling accelerated compositing when WebGL is enabled causes tests to fail on Leopard which expect HW compositing to be disabled.
2242    // Until we fix that, I will comment out the test (CFM)
2243    settings.setAcceleratedCompositingEnabled([preferences acceleratedCompositingEnabled]);
2244    settings.setAcceleratedDrawingEnabled([preferences acceleratedDrawingEnabled]);
2245    settings.setCanvasUsesAcceleratedDrawing([preferences canvasUsesAcceleratedDrawing]);
2246    settings.setShowDebugBorders([preferences showDebugBorders]);
2247    settings.setShowRepaintCounter([preferences showRepaintCounter]);
2248    settings.setWebGLEnabled([preferences webGLEnabled]);
2249    settings.setSubpixelCSSOMElementMetricsEnabled([preferences subpixelCSSOMElementMetricsEnabled]);
2250
2251    settings.setForceSoftwareWebGLRendering([preferences forceSoftwareWebGLRendering]);
2252    settings.setAccelerated2dCanvasEnabled([preferences accelerated2dCanvasEnabled]);
2253    settings.setLoadDeferringEnabled(shouldEnableLoadDeferring());
2254    settings.setWindowFocusRestricted(shouldRestrictWindowFocus());
2255    settings.setFrameFlatteningEnabled([preferences isFrameFlatteningEnabled]);
2256    settings.setSpatialNavigationEnabled([preferences isSpatialNavigationEnabled]);
2257    settings.setPaginateDuringLayoutEnabled([preferences paginateDuringLayoutEnabled]);
2258    RuntimeEnabledFeatures::sharedFeatures().setCSSRegionsEnabled([preferences cssRegionsEnabled]);
2259    RuntimeEnabledFeatures::sharedFeatures().setCSSCompositingEnabled([preferences cssCompositingEnabled]);
2260
2261    settings.setAsynchronousSpellCheckingEnabled([preferences asynchronousSpellCheckingEnabled]);
2262    settings.setHyperlinkAuditingEnabled([preferences hyperlinkAuditingEnabled]);
2263    settings.setUsePreHTML5ParserQuirks([self _needsPreHTML5ParserQuirks]);
2264    settings.setInteractiveFormValidationEnabled([self interactiveFormValidationEnabled]);
2265    settings.setValidationMessageTimerMagnification([self validationMessageTimerMagnification]);
2266
2267    settings.setMediaPlaybackRequiresUserGesture([preferences mediaPlaybackRequiresUserGesture]);
2268    settings.setMediaPlaybackAllowsInline([preferences mediaPlaybackAllowsInline]);
2269    settings.setSuppressesIncrementalRendering([preferences suppressesIncrementalRendering]);
2270    settings.setBackspaceKeyNavigationEnabled([preferences backspaceKeyNavigationEnabled]);
2271    settings.setWantsBalancedSetDefersLoadingBehavior([preferences wantsBalancedSetDefersLoadingBehavior]);
2272    settings.setMockScrollbarsEnabled([preferences mockScrollbarsEnabled]);
2273
2274    settings.setShouldRespectImageOrientation([preferences shouldRespectImageOrientation]);
2275
2276    settings.setRequestAnimationFrameEnabled([preferences requestAnimationFrameEnabled]);
2277    settings.setDiagnosticLoggingEnabled([preferences diagnosticLoggingEnabled]);
2278    settings.setLowPowerVideoAudioBufferSizeEnabled([preferences lowPowerVideoAudioBufferSizeEnabled]);
2279
2280    settings.setUseLegacyTextAlignPositionedElementBehavior([preferences useLegacyTextAlignPositionedElementBehavior]);
2281
2282    settings.setShouldConvertPositionStyleOnCopy([preferences shouldConvertPositionStyleOnCopy]);
2283    settings.setEnableInheritURIQueryComponent([preferences isInheritURIQueryComponentEnabled]);
2284
2285    switch ([preferences storageBlockingPolicy]) {
2286    case WebAllowAllStorage:
2287        settings.setStorageBlockingPolicy(SecurityOrigin::AllowAllStorage);
2288        break;
2289    case WebBlockThirdPartyStorage:
2290        settings.setStorageBlockingPolicy(SecurityOrigin::BlockThirdPartyStorage);
2291        break;
2292    case WebBlockAllStorage:
2293        settings.setStorageBlockingPolicy(SecurityOrigin::BlockAllStorage);
2294        break;
2295    }
2296
2297    settings.setPlugInSnapshottingEnabled([preferences plugInSnapshottingEnabled]);
2298
2299    settings.setFixedPositionCreatesStackingContext(true);
2300#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 10100
2301    settings.setAcceleratedCompositingForFixedPositionEnabled(true);
2302#endif
2303
2304#if PLATFORM(IOS)
2305    settings.setStandalone([preferences _standalone]);
2306    settings.setTelephoneNumberParsingEnabled([preferences _telephoneNumberParsingEnabled]);
2307    settings.setAlwaysUseBaselineOfPrimaryFont([preferences _alwaysUseBaselineOfPrimaryFont]);
2308    settings.setAllowMultiElementImplicitSubmission([preferences _allowMultiElementImplicitFormSubmission]);
2309    settings.setLayoutInterval(std::chrono::milliseconds([preferences _layoutInterval]));
2310    settings.setMaxParseDuration([preferences _maxParseDuration]);
2311    settings.setAlwaysUseAcceleratedOverflowScroll([preferences _alwaysUseAcceleratedOverflowScroll]);
2312    settings.setMediaPlaybackAllowsAirPlay([preferences mediaPlaybackAllowsAirPlay]);
2313    settings.setAudioSessionCategoryOverride([preferences audioSessionCategoryOverride]);
2314    settings.setNetworkDataUsageTrackingEnabled([preferences networkDataUsageTrackingEnabled]);
2315    settings.setNetworkInterfaceName([preferences networkInterfaceName]);
2316    settings.setAVKitEnabled([preferences avKitEnabled]);
2317    settings.setShouldTransformsAffectOverflow(shouldTransformsAffectOverflow());
2318    settings.setShouldDispatchJavaScriptWindowOnErrorEvents(shouldDispatchJavaScriptWindowOnErrorEvents());
2319
2320    settings.setPasswordEchoEnabled([preferences _allowPasswordEcho]);
2321    settings.setPasswordEchoDurationInSeconds([preferences _passwordEchoDuration]);
2322
2323    ASSERT_WITH_MESSAGE(settings.pageCacheSupportsPlugins(), "PageCacheSupportsPlugins should be enabled on iOS.");
2324    settings.setDelegatesPageScaling(true);
2325
2326#if ENABLE(IOS_TEXT_AUTOSIZING)
2327    settings.setMinimumZoomFontSize([preferences _minimumZoomFontSize]);
2328#endif
2329#endif // PLATFORM(IOS)
2330
2331#if PLATFORM(MAC)
2332    if ([preferences userStyleSheetEnabled]) {
2333        NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString];
2334        if ([location isEqualToString:@"apple-dashboard://stylesheet"])
2335            location = @"file:///System/Library/PrivateFrameworks/DashboardClient.framework/Resources/widget.css";
2336        settings.setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]);
2337    } else
2338        settings.setUserStyleSheetLocation([NSURL URLWithString:@""]);
2339
2340    settings.setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]);
2341    settings.setTreatsAnyTextCSSLinkAsStylesheet([self _needsLinkElementTextCSSQuirk]);
2342    settings.setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]);
2343    settings.setEnforceCSSMIMETypeInNoQuirksMode(!WKAppVersionCheckLessThan(@"com.apple.iWeb", -1, 2.1));
2344    settings.setNeedsIsLoadingInAPISenseQuirk([self _needsIsLoadingInAPISenseQuirk]);
2345    settings.setTextAreasAreResizable([preferences textAreasAreResizable]);
2346    settings.setExperimentalNotificationsEnabled([preferences experimentalNotificationsEnabled]);
2347    settings.setShowsURLsInToolTips([preferences showsURLsInToolTips]);
2348    settings.setShowsToolTipOverTruncatedText([preferences showsToolTipOverTruncatedText]);
2349    settings.setQTKitEnabled([preferences isQTKitEnabled]);
2350
2351    // FIXME: Should we enable this following <rdar://problem/15290404>?
2352    settings.setMultithreadedWebGLEnabled([preferences multithreadedWebGLEnabled]);
2353#endif // PLATFORM(MAC)
2354
2355#if ENABLE(SQL_DATABASE)
2356    DatabaseManager::manager().setIsAvailable([preferences databasesEnabled]);
2357#endif
2358
2359#if ENABLE(MEDIA_SOURCE)
2360    settings.setMediaSourceEnabled([preferences mediaSourceEnabled]);
2361#endif
2362
2363#if ENABLE(SERVICE_CONTROLS)
2364    settings.setImageControlsEnabled([preferences imageControlsEnabled]);
2365#endif
2366
2367#if ENABLE(VIDEO_TRACK)
2368    settings.setShouldDisplaySubtitles([preferences shouldDisplaySubtitles]);
2369    settings.setShouldDisplayCaptions([preferences shouldDisplayCaptions]);
2370    settings.setShouldDisplayTextDescriptions([preferences shouldDisplayTextDescriptions]);
2371#endif
2372
2373#if USE(AVFOUNDATION)
2374    settings.setAVFoundationEnabled([preferences isAVFoundationEnabled]);
2375#endif
2376
2377#if ENABLE(WEB_AUDIO)
2378    settings.setWebAudioEnabled([preferences webAudioEnabled]);
2379#endif
2380
2381#if ENABLE(FULLSCREEN_API)
2382    settings.setFullScreenEnabled([preferences fullScreenEnabled]);
2383#endif
2384
2385#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
2386    settings.setHiddenPageDOMTimerThrottlingEnabled([preferences hiddenPageDOMTimerThrottlingEnabled]);
2387#endif
2388
2389    settings.setHiddenPageCSSAnimationSuspensionEnabled([preferences hiddenPageCSSAnimationSuspensionEnabled]);
2390
2391#if ENABLE(GAMEPAD)
2392    RuntimeEnabledFeatures::sharedFeatures().setGamepadsEnabled([preferences gamepadsEnabled]);
2393#endif
2394
2395    NSTimeInterval timeout = [preferences incrementalRenderingSuppressionTimeoutInSeconds];
2396    if (timeout > 0)
2397        settings.setIncrementalRenderingSuppressionTimeoutInSeconds(timeout);
2398
2399    // Application Cache Preferences are stored on the global cache storage manager, not in Settings.
2400    [WebApplicationCache setDefaultOriginQuota:[preferences applicationCacheDefaultOriginQuota]];
2401
2402    BOOL zoomsTextOnly = [preferences zoomsTextOnly];
2403    if (_private->zoomsTextOnly != zoomsTextOnly)
2404        [self _setZoomMultiplier:_private->zoomMultiplier isTextOnly:zoomsTextOnly];
2405
2406#if ENABLE(DISK_IMAGE_CACHE) && PLATFORM(IOS)
2407    DiskImageCache& diskImageCache = WebCore::diskImageCache();
2408    diskImageCache.setEnabled([preferences diskImageCacheEnabled]);
2409    diskImageCache.setMinimumImageSize([preferences diskImageCacheMinimumImageSize]);
2410    diskImageCache.setMaximumCacheSize([preferences diskImageCacheMaximumCacheSize]);
2411#endif
2412
2413#if PLATFORM(IOS)
2414    [[self window] setTileBordersVisible:[preferences showDebugBorders]];
2415    [[self window] setTilePaintCountsVisible:[preferences showRepaintCounter]];
2416    [[self window] setAcceleratedDrawingEnabled:[preferences acceleratedDrawingEnabled]];
2417    [WAKView _setInterpolationQuality:[preferences _interpolationQuality]];
2418#endif
2419}
2420
2421static inline IMP getMethod(id o, SEL s)
2422{
2423    return [o respondsToSelector:s] ? [o methodForSelector:s] : 0;
2424}
2425
2426#if PLATFORM(IOS)
2427- (id)_UIKitDelegateForwarder
2428{
2429    if (_private->closing)
2430        return nil;
2431
2432    if (!_private->UIKitDelegateForwarder)
2433        _private->UIKitDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIKitDelegate defaultTarget:[WebDefaultUIKitDelegate sharedUIKitDelegate]];
2434    return _private->UIKitDelegateForwarder;
2435}
2436#endif
2437
2438- (void)_cacheResourceLoadDelegateImplementations
2439{
2440    WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
2441    id delegate = _private->resourceProgressDelegate;
2442
2443    if (!delegate) {
2444        bzero(cache, sizeof(WebResourceDelegateImplementationCache));
2445        return;
2446    }
2447
2448    cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:));
2449    cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:));
2450    cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:));
2451    cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:));
2452    cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
2453#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
2454    cache->canAuthenticateAgainstProtectionSpaceFunc = getMethod(delegate, @selector(webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource:));
2455#endif
2456
2457#if PLATFORM(IOS)
2458    cache->connectionPropertiesFunc = getMethod(delegate, @selector(webView:connectionPropertiesForResource:dataSource:));
2459    cache->webThreadDidFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webThreadWebView:resource:didFinishLoadingFromDataSource:));
2460    cache->webThreadDidFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webThreadWebView:resource:didFailLoadingWithError:fromDataSource:));
2461    cache->webThreadIdentifierForRequestFunc = getMethod(delegate, @selector(webThreadWebView:identifierForInitialRequest:fromDataSource:));
2462    cache->webThreadDidLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webThreadWebView:didLoadResourceFromMemoryCache:response:length:fromDataSource:));
2463    cache->webThreadWillSendRequestFunc = getMethod(delegate, @selector(webThreadWebView:resource:willSendRequest:redirectResponse:fromDataSource:));
2464    cache->webThreadDidReceiveResponseFunc = getMethod(delegate, @selector(webThreadWebView:resource:didReceiveResponse:fromDataSource:));
2465    cache->webThreadDidReceiveContentLengthFunc = getMethod(delegate, @selector(webThreadWebView:resource:didReceiveContentLength:fromDataSource:));
2466    cache->webThreadWillCacheResponseFunc = getMethod(delegate, @selector(webThreadWebView:resource:willCacheResponse:fromDataSource:));
2467#endif
2468
2469    cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:));
2470    cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:));
2471    cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:));
2472    cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:));
2473    cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:));
2474    cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:));
2475    cache->shouldUseCredentialStorageFunc = getMethod(delegate, @selector(webView:resource:shouldUseCredentialStorageForDataSource:));
2476    cache->shouldPaintBrokenImageForURLFunc = getMethod(delegate, @selector(webView:shouldPaintBrokenImageForURL:));
2477}
2478
2479- (void)_cacheFrameLoadDelegateImplementations
2480{
2481    WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations;
2482    id delegate = _private->frameLoadDelegate;
2483
2484    if (!delegate) {
2485        bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache));
2486        return;
2487    }
2488
2489    cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:));
2490    cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:));
2491    cache->didPushStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPushStateWithinPageForFrame:));
2492    cache->didReplaceStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didReplaceStateWithinPageForFrame:));
2493    cache->didPopStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPopStateWithinPageForFrame:));
2494#if JSC_OBJC_API_ENABLED
2495    cache->didCreateJavaScriptContextForFrameFunc = getMethod(delegate, @selector(webView:didCreateJavaScriptContext:forFrame:));
2496#endif
2497    cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:));
2498    cache->didClearWindowObjectForFrameInScriptWorldFunc = getMethod(delegate, @selector(webView:didClearWindowObjectForFrame:inScriptWorld:));
2499    cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:));
2500    cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:));
2501    cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:));
2502    cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:));
2503    cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:));
2504    cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:));
2505    cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:));
2506    cache->didFirstVisuallyNonEmptyLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:));
2507    cache->didLayoutFunc = getMethod(delegate, @selector(webView:didLayout:));
2508    cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:));
2509#if ENABLE(ICONDATABASE)
2510    cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:));
2511#endif
2512    cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:));
2513    cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:));
2514    cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:));
2515    cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:));
2516    cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:));
2517    cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:));
2518    cache->didDisplayInsecureContentFunc = getMethod(delegate, @selector(webViewDidDisplayInsecureContent:));
2519    cache->didRunInsecureContentFunc = getMethod(delegate, @selector(webView:didRunInsecureContent:));
2520    cache->didDetectXSSFunc = getMethod(delegate, @selector(webView:didDetectXSS:));
2521    cache->didRemoveFrameFromHierarchyFunc = getMethod(delegate, @selector(webView:didRemoveFrameFromHierarchy:));
2522#if PLATFORM(IOS)
2523    cache->webThreadDidLayoutFunc = getMethod(delegate, @selector(webThreadWebView:didLayout:));
2524#endif
2525
2526    // It would be nice to get rid of this code and transition all clients to using didLayout instead of
2527    // didFirstLayoutInFrame and didFirstVisuallyNonEmptyLayoutInFrame. In the meantime, this is required
2528    // for backwards compatibility.
2529    Page* page = core(self);
2530    if (page) {
2531        unsigned milestones = DidFirstLayout;
2532#if PLATFORM(IOS)
2533        milestones |= DidFirstVisuallyNonEmptyLayout;
2534#else
2535        if (cache->didFirstVisuallyNonEmptyLayoutInFrameFunc)
2536            milestones |= DidFirstVisuallyNonEmptyLayout;
2537#endif
2538        page->addLayoutMilestones(static_cast<LayoutMilestones>(milestones));
2539    }
2540}
2541
2542- (void)_cacheScriptDebugDelegateImplementations
2543{
2544    WebScriptDebugDelegateImplementationCache *cache = &_private->scriptDebugDelegateImplementations;
2545    id delegate = _private->scriptDebugDelegate;
2546
2547    if (!delegate) {
2548        bzero(cache, sizeof(WebScriptDebugDelegateImplementationCache));
2549        return;
2550    }
2551
2552    cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:));
2553    if (cache->didParseSourceFunc)
2554        cache->didParseSourceExpectsBaseLineNumber = YES;
2555    else {
2556        cache->didParseSourceExpectsBaseLineNumber = NO;
2557        cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:));
2558    }
2559
2560    cache->failedToParseSourceFunc = getMethod(delegate, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:));
2561
2562    cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:hasHandler:sourceId:line:forWebFrame:));
2563    if (cache->exceptionWasRaisedFunc)
2564        cache->exceptionWasRaisedExpectsHasHandlerFlag = YES;
2565    else {
2566        cache->exceptionWasRaisedExpectsHasHandlerFlag = NO;
2567        cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:));
2568    }
2569}
2570
2571- (void)_cacheHistoryDelegateImplementations
2572{
2573    WebHistoryDelegateImplementationCache *cache = &_private->historyDelegateImplementations;
2574    id delegate = _private->historyDelegate;
2575
2576    if (!delegate) {
2577        bzero(cache, sizeof(WebHistoryDelegateImplementationCache));
2578        return;
2579    }
2580
2581    cache->navigatedFunc = getMethod(delegate, @selector(webView:didNavigateWithNavigationData:inFrame:));
2582    cache->clientRedirectFunc = getMethod(delegate, @selector(webView:didPerformClientRedirectFromURL:toURL:inFrame:));
2583    cache->serverRedirectFunc = getMethod(delegate, @selector(webView:didPerformServerRedirectFromURL:toURL:inFrame:));
2584    cache->deprecatedSetTitleFunc = getMethod(delegate, @selector(webView:updateHistoryTitle:forURL:));
2585    cache->setTitleFunc = getMethod(delegate, @selector(webView:updateHistoryTitle:forURL:inFrame:));
2586    cache->populateVisitedLinksFunc = getMethod(delegate, @selector(populateVisitedLinksForWebView:));
2587}
2588
2589- (id)_policyDelegateForwarder
2590{
2591#if PLATFORM(IOS)
2592    if (_private->closing)
2593        return nil;
2594#endif
2595    if (!_private->policyDelegateForwarder)
2596        _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate]];
2597    return _private->policyDelegateForwarder;
2598}
2599
2600- (id)_UIDelegateForwarder
2601{
2602#if PLATFORM(IOS)
2603    if (_private->closing)
2604        return nil;
2605#endif
2606    if (!_private->UIDelegateForwarder)
2607        _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate]];
2608    return _private->UIDelegateForwarder;
2609}
2610
2611#if PLATFORM(IOS)
2612- (id)_UIDelegateForSelector:(SEL)selector
2613{
2614    id delegate = self->_private->UIDelegate;
2615    if ([delegate respondsToSelector:selector])
2616        return delegate;
2617
2618    delegate = [WebDefaultUIDelegate sharedUIDelegate];
2619    if ([delegate respondsToSelector:selector])
2620        return delegate;
2621
2622    return nil;
2623}
2624#endif
2625
2626- (id)_editingDelegateForwarder
2627{
2628#if PLATFORM(IOS)
2629    if (_private->closing)
2630        return nil;
2631#endif
2632    // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
2633    // Not sure if that is a bug or not.
2634    if (!_private)
2635        return nil;
2636
2637    if (!_private->editingDelegateForwarder)
2638        _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate]];
2639    return _private->editingDelegateForwarder;
2640}
2641
2642- (void)_closeWindow
2643{
2644    [[self _UIDelegateForwarder] webViewClose:self];
2645}
2646
2647+ (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType
2648{
2649    [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
2650    [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
2651
2652    // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
2653    // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
2654    // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
2655    MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType);
2656}
2657
2658+ (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme
2659{
2660    NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
2661    [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
2662
2663    // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
2664    // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
2665    // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
2666    if ([viewClass class] == [WebHTMLView class])
2667        MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
2668
2669    // This is used to make _representationExistsForURLScheme faster.
2670    // Without this set, we'd have to create the MIME type each time.
2671    if (schemesWithRepresentationsSet == nil) {
2672        schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
2673    }
2674    [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
2675}
2676
2677+ (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
2678{
2679    return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
2680}
2681
2682+ (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
2683{
2684    return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
2685}
2686
2687+ (BOOL)_canHandleRequest:(NSURLRequest *)request forMainFrame:(BOOL)forMainFrame
2688{
2689    // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed.
2690    if (!request)
2691        return NO;
2692
2693    if ([NSURLConnection canHandleRequest:request])
2694        return YES;
2695
2696    NSString *scheme = [[request URL] scheme];
2697
2698    // Representations for URL schemes work at the top level.
2699    if (forMainFrame && [self _representationExistsForURLScheme:scheme])
2700        return YES;
2701
2702    if ([scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"])
2703        return YES;
2704
2705    if ([scheme _webkit_isCaseInsensitiveEqualToString:@"blob"])
2706        return YES;
2707
2708    return NO;
2709}
2710
2711+ (BOOL)_canHandleRequest:(NSURLRequest *)request
2712{
2713    return [self _canHandleRequest:request forMainFrame:YES];
2714}
2715
2716+ (NSString *)_decodeData:(NSData *)data
2717{
2718    HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet
2719    return TextResourceDecoder::create("text/html")->decodeAndFlush(static_cast<const char*>([data bytes]), [data length]); // bookmark files are HTML
2720}
2721
2722- (void)_pushPerformingProgrammaticFocus
2723{
2724    _private->programmaticFocusCount++;
2725}
2726
2727- (void)_popPerformingProgrammaticFocus
2728{
2729    _private->programmaticFocusCount--;
2730}
2731
2732- (BOOL)_isPerformingProgrammaticFocus
2733{
2734    return _private->programmaticFocusCount != 0;
2735}
2736
2737#if !PLATFORM(IOS)
2738- (void)_didChangeValueForKey: (NSString *)key
2739{
2740    LOG (Bindings, "calling didChangeValueForKey: %@", key);
2741    [self didChangeValueForKey: key];
2742}
2743
2744- (void)_willChangeValueForKey: (NSString *)key
2745{
2746    LOG (Bindings, "calling willChangeValueForKey: %@", key);
2747    [self willChangeValueForKey: key];
2748}
2749
2750+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
2751    static NSSet *manualNotifyKeys = nil;
2752    if (!manualNotifyKeys)
2753        manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
2754            _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey,
2755            nil];
2756    if ([manualNotifyKeys containsObject:key])
2757        return NO;
2758    return YES;
2759}
2760
2761- (NSArray *)_declaredKeys {
2762    static NSArray *declaredKeys = nil;
2763    if (!declaredKeys)
2764        declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
2765            _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
2766    return declaredKeys;
2767}
2768
2769- (void)setObservationInfo:(void *)info
2770{
2771    _private->observationInfo = info;
2772}
2773
2774- (void *)observationInfo
2775{
2776    return _private->observationInfo;
2777}
2778
2779- (void)_willChangeBackForwardKeys
2780{
2781    [self _willChangeValueForKey: _WebCanGoBackKey];
2782    [self _willChangeValueForKey: _WebCanGoForwardKey];
2783}
2784
2785- (void)_didChangeBackForwardKeys
2786{
2787    [self _didChangeValueForKey: _WebCanGoBackKey];
2788    [self _didChangeValueForKey: _WebCanGoForwardKey];
2789}
2790
2791- (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
2792{
2793    if (needsSelfRetainWhileLoadingQuirk())
2794        [self retain];
2795
2796    [self _willChangeBackForwardKeys];
2797    if (frame == [self mainFrame]){
2798        // Force an observer update by sending a will/did.
2799        [self _willChangeValueForKey: _WebIsLoadingKey];
2800        [self _didChangeValueForKey: _WebIsLoadingKey];
2801
2802        [self _willChangeValueForKey: _WebMainFrameURLKey];
2803    }
2804
2805    [NSApp setWindowsNeedUpdate:YES];
2806
2807#if ENABLE(FULLSCREEN_API)
2808    Document* document = core([frame DOMDocument]);
2809    if (Element* element = document ? document->webkitCurrentFullScreenElement() : 0) {
2810        SEL selector = @selector(webView:closeFullScreenWithListener:);
2811        if (_private->UIDelegate && [_private->UIDelegate respondsToSelector:selector]) {
2812            WebKitFullScreenListener *listener = [[WebKitFullScreenListener alloc] initWithElement:element];
2813            CallUIDelegate(self, selector, listener);
2814            [listener release];
2815        } else if (_private->newFullscreenController && [_private->newFullscreenController isFullScreen]) {
2816            [_private->newFullscreenController close];
2817        }
2818    }
2819#endif
2820}
2821
2822- (void)_checkDidPerformFirstNavigation
2823{
2824    if (_private->_didPerformFirstNavigation)
2825        return;
2826
2827    Page* page = _private->page;
2828    if (!page)
2829        return;
2830
2831    auto& backForwardController = page->backForward();
2832
2833    if (!backForwardController.backItem())
2834        return;
2835
2836    _private->_didPerformFirstNavigation = YES;
2837
2838    if (_private->preferences.automaticallyDetectsCacheModel && _private->preferences.cacheModel < WebCacheModelDocumentBrowser)
2839        _private->preferences.cacheModel = WebCacheModelDocumentBrowser;
2840}
2841
2842- (void)_didCommitLoadForFrame:(WebFrame *)frame
2843{
2844    if (frame == [self mainFrame])
2845        [self _didChangeValueForKey: _WebMainFrameURLKey];
2846
2847    [self _checkDidPerformFirstNavigation];
2848
2849    [NSApp setWindowsNeedUpdate:YES];
2850}
2851
2852- (void)_didFinishLoadForFrame:(WebFrame *)frame
2853{
2854    if (needsSelfRetainWhileLoadingQuirk())
2855        [self performSelector:@selector(release) withObject:nil afterDelay:0];
2856
2857    [self _didChangeBackForwardKeys];
2858    if (frame == [self mainFrame]){
2859        // Force an observer update by sending a will/did.
2860        [self _willChangeValueForKey: _WebIsLoadingKey];
2861        [self _didChangeValueForKey: _WebIsLoadingKey];
2862    }
2863    [NSApp setWindowsNeedUpdate:YES];
2864}
2865
2866- (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
2867{
2868    if (needsSelfRetainWhileLoadingQuirk())
2869        [self performSelector:@selector(release) withObject:nil afterDelay:0];
2870
2871    [self _didChangeBackForwardKeys];
2872    if (frame == [self mainFrame]){
2873        // Force an observer update by sending a will/did.
2874        [self _willChangeValueForKey: _WebIsLoadingKey];
2875        [self _didChangeValueForKey: _WebIsLoadingKey];
2876    }
2877    [NSApp setWindowsNeedUpdate:YES];
2878}
2879
2880- (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
2881{
2882    if (needsSelfRetainWhileLoadingQuirk())
2883        [self performSelector:@selector(release) withObject:nil afterDelay:0];
2884
2885    [self _didChangeBackForwardKeys];
2886    if (frame == [self mainFrame]){
2887        // Force an observer update by sending a will/did.
2888        [self _willChangeValueForKey: _WebIsLoadingKey];
2889        [self _didChangeValueForKey: _WebIsLoadingKey];
2890
2891        [self _didChangeValueForKey: _WebMainFrameURLKey];
2892    }
2893    [NSApp setWindowsNeedUpdate:YES];
2894}
2895
2896- (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
2897{
2898    RetainPtr<NSMutableURLRequest *> request = adoptNS([[NSMutableURLRequest alloc] initWithURL:URL]);
2899    [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
2900    NSCachedURLResponse *cachedResponse;
2901
2902    if (!_private->page)
2903        return nil;
2904
2905    if (CFURLStorageSessionRef storageSession = _private->page->mainFrame().loader().networkingContext()->storageSession().platformSession())
2906        cachedResponse = WKCachedResponseForRequest(storageSession, request.get());
2907    else
2908        cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request.get()];
2909
2910    return cachedResponse;
2911}
2912
2913- (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2914{
2915    NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
2916    DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey];
2917    [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey])
2918                        element:domElement
2919                            URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
2920                          title:[element objectForKey:WebElementImageAltStringKey]
2921                        archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
2922                          types:types
2923                         source:nil];
2924}
2925
2926- (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2927{
2928    [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
2929                     andTitle:[element objectForKey:WebElementLinkLabelKey]
2930                        types:types];
2931}
2932
2933#if ENABLE(DRAG_SUPPORT)
2934- (void)_setInitiatedDrag:(BOOL)initiatedDrag
2935{
2936    if (!_private->page)
2937        return;
2938    _private->page->dragController().setDidInitiateDrag(initiatedDrag);
2939}
2940#endif
2941
2942#else
2943
2944- (void)_didCommitLoadForFrame:(WebFrame *)frame
2945{
2946    if (frame == [self mainFrame])
2947        _private->didDrawTiles = 0;
2948}
2949
2950#endif // PLATFORM(IOS)
2951
2952#if ENABLE(DASHBOARD_SUPPORT)
2953
2954#define DASHBOARD_CONTROL_LABEL @"control"
2955
2956- (void)_addControlRect:(NSRect)bounds clip:(NSRect)clip fromView:(NSView *)view toDashboardRegions:(NSMutableDictionary *)regions
2957{
2958    NSRect adjustedBounds = bounds;
2959    adjustedBounds.origin = [self convertPoint:bounds.origin fromView:view];
2960    adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
2961    adjustedBounds.size = bounds.size;
2962
2963    NSRect adjustedClip;
2964    adjustedClip.origin = [self convertPoint:clip.origin fromView:view];
2965    adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
2966    adjustedClip.size = clip.size;
2967
2968    WebDashboardRegion *region = [[WebDashboardRegion alloc] initWithRect:adjustedBounds
2969        clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle];
2970    NSMutableArray *scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
2971    if (!scrollerRegions) {
2972        scrollerRegions = [[NSMutableArray alloc] init];
2973        [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
2974        [scrollerRegions release];
2975    }
2976    [scrollerRegions addObject:region];
2977    [region release];
2978}
2979
2980- (void)_addScrollerDashboardRegionsForFrameView:(FrameView*)frameView dashboardRegions:(NSMutableDictionary *)regions
2981{
2982    NSView *documentView = [[kit(&frameView->frame()) frameView] documentView];
2983
2984    for (const auto& widget: frameView->children()) {
2985        if (widget->isFrameView()) {
2986            [self _addScrollerDashboardRegionsForFrameView:toFrameView(widget.get()) dashboardRegions:regions];
2987            continue;
2988        }
2989
2990        if (!widget->isScrollbar())
2991            continue;
2992
2993        // FIXME: This should really pass an appropriate clip, but our first try got it wrong, and
2994        // it's not common to need this to be correct in Dashboard widgets.
2995        NSRect bounds = widget->frameRect();
2996        [self _addControlRect:bounds clip:bounds fromView:documentView toDashboardRegions:regions];
2997    }
2998}
2999
3000- (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
3001{
3002    // Add scroller regions for NSScroller and WebCore scrollbars
3003    NSUInteger count = [views count];
3004    for (NSUInteger i = 0; i < count; i++) {
3005        NSView *view = [views objectAtIndex:i];
3006
3007        if ([view isKindOfClass:[WebHTMLView class]]) {
3008            if (Frame* coreFrame = core([(WebHTMLView*)view _frame])) {
3009                if (FrameView* coreView = coreFrame->view())
3010                    [self _addScrollerDashboardRegionsForFrameView:coreView dashboardRegions:regions];
3011            }
3012        } else if ([view isKindOfClass:[NSScroller class]]) {
3013            // AppKit places absent scrollers at -100,-100
3014            if ([view frame].origin.y < 0)
3015                continue;
3016            [self _addControlRect:[view bounds] clip:[view visibleRect] fromView:view toDashboardRegions:regions];
3017        }
3018        [self _addScrollerDashboardRegions:regions from:[view subviews]];
3019    }
3020}
3021
3022- (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
3023{
3024    [self _addScrollerDashboardRegions:regions from:[self subviews]];
3025}
3026
3027- (NSDictionary *)_dashboardRegions
3028{
3029    // Only return regions from main frame.
3030    Frame* mainFrame = [self _mainCoreFrame];
3031    if (!mainFrame)
3032        return nil;
3033
3034    const Vector<AnnotatedRegionValue>& regions = mainFrame->document()->annotatedRegions();
3035    size_t size = regions.size();
3036
3037    NSMutableDictionary *webRegions = [NSMutableDictionary dictionaryWithCapacity:size];
3038    for (size_t i = 0; i < size; i++) {
3039        const AnnotatedRegionValue& region = regions[i];
3040
3041        if (region.type == StyleDashboardRegion::None)
3042            continue;
3043
3044        NSString *label = region.label;
3045        WebDashboardRegionType type = WebDashboardRegionTypeNone;
3046        if (region.type == StyleDashboardRegion::Circle)
3047            type = WebDashboardRegionTypeCircle;
3048        else if (region.type == StyleDashboardRegion::Rectangle)
3049            type = WebDashboardRegionTypeRectangle;
3050        NSMutableArray *regionValues = [webRegions objectForKey:label];
3051        if (!regionValues) {
3052            regionValues = [[NSMutableArray alloc] initWithCapacity:1];
3053            [webRegions setObject:regionValues forKey:label];
3054            [regionValues release];
3055        }
3056
3057        WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:pixelSnappedIntRect(region.bounds) clip:pixelSnappedIntRect(region.clip) type:type];
3058        [regionValues addObject:webRegion];
3059        [webRegion release];
3060    }
3061
3062    [self _addScrollerDashboardRegions:webRegions];
3063
3064    return webRegions;
3065}
3066
3067- (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag
3068{
3069    // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement
3070    // specific support for the backward compatibility mode flag.
3071    if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page)
3072        _private->page->settings().setUsesDashboardBackwardCompatibilityMode(true);
3073
3074    switch (behavior) {
3075        case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
3076            _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
3077            break;
3078        }
3079        case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
3080            _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
3081            break;
3082        }
3083        case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
3084            _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
3085            break;
3086        }
3087        case WebDashboardBehaviorAllowWheelScrolling: {
3088            _private->dashboardBehaviorAllowWheelScrolling = flag;
3089            break;
3090        }
3091        case WebDashboardBehaviorUseBackwardCompatibilityMode: {
3092            if (_private->page)
3093                _private->page->settings().setUsesDashboardBackwardCompatibilityMode(flag);
3094#if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
3095            RuntimeEnabledFeatures::sharedFeatures().setLegacyCSSVendorPrefixesEnabled(flag);
3096#endif
3097            break;
3098        }
3099    }
3100
3101    // Pre-HTML5 parser quirks should be enabled if Dashboard is in backward
3102    // compatibility mode. See <rdar://problem/8175982>.
3103    if (_private->page)
3104        _private->page->settings().setUsePreHTML5ParserQuirks([self _needsPreHTML5ParserQuirks]);
3105}
3106
3107- (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
3108{
3109    switch (behavior) {
3110        case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
3111            return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
3112        }
3113        case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
3114            return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
3115        }
3116        case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
3117            return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
3118        }
3119        case WebDashboardBehaviorAllowWheelScrolling: {
3120            return _private->dashboardBehaviorAllowWheelScrolling;
3121        }
3122        case WebDashboardBehaviorUseBackwardCompatibilityMode: {
3123            return _private->page && _private->page->settings().usesDashboardBackwardCompatibilityMode();
3124        }
3125    }
3126    return NO;
3127}
3128
3129#endif /* ENABLE(DASHBOARD_SUPPORT) */
3130
3131+ (void)_setShouldUseFontSmoothing:(BOOL)f
3132{
3133    Font::setShouldUseSmoothing(f);
3134}
3135
3136+ (BOOL)_shouldUseFontSmoothing
3137{
3138    return Font::shouldUseSmoothing();
3139}
3140
3141#if !PLATFORM(IOS)
3142+ (void)_setUsesTestModeFocusRingColor:(BOOL)f
3143{
3144    setUsesTestModeFocusRingColor(f);
3145}
3146
3147+ (BOOL)_usesTestModeFocusRingColor
3148{
3149    return usesTestModeFocusRingColor();
3150}
3151#endif
3152
3153#if PLATFORM(IOS)
3154- (void)_setUIKitDelegate:(id)delegate
3155{
3156    _private->UIKitDelegate = delegate;
3157    [_private->UIKitDelegateForwarder clearTarget];
3158    [_private->UIKitDelegateForwarder release];
3159    _private->UIKitDelegateForwarder = nil;
3160}
3161
3162- (id)_UIKitDelegate
3163{
3164    return _private->UIKitDelegate;
3165}
3166
3167- (void)setWebMailDelegate:(id)delegate
3168{
3169    _private->WebMailDelegate = delegate;
3170}
3171
3172- (id)_webMailDelegate
3173{
3174    return _private->WebMailDelegate;
3175}
3176
3177- (id <WebCaretChangeListener>)caretChangeListener
3178{
3179    return _private->_caretChangeListener;
3180}
3181
3182- (void)setCaretChangeListener:(id <WebCaretChangeListener>)listener
3183{
3184    _private->_caretChangeListener = listener;
3185}
3186
3187- (NSSet *)caretChangeListeners
3188{
3189    return _private->_caretChangeListeners;
3190}
3191
3192- (void)addCaretChangeListener:(id <WebCaretChangeListener>)listener
3193{
3194    if (_private->_caretChangeListeners == nil) {
3195        _private->_caretChangeListeners = [[NSMutableSet alloc] init];
3196    }
3197
3198    [_private->_caretChangeListeners addObject:listener];
3199}
3200
3201- (void)removeCaretChangeListener:(id <WebCaretChangeListener>)listener
3202{
3203    [_private->_caretChangeListeners removeObject:listener];
3204}
3205
3206- (void)removeAllCaretChangeListeners
3207{
3208    [_private->_caretChangeListeners removeAllObjects];
3209}
3210
3211- (void)caretChanged
3212{
3213    [_private->_caretChangeListener caretChanged];
3214    NSSet *copy = [_private->_caretChangeListeners copy];
3215    for (id <WebCaretChangeListener> listener in copy) {
3216        [listener caretChanged];
3217    }
3218    [copy release];
3219}
3220
3221- (void)_clearDelegates
3222{
3223    ASSERT(WebThreadIsLocked() || !WebThreadIsEnabled());
3224
3225    [self _setFormDelegate:nil];
3226    [self _setUIKitDelegate:nil];
3227    [self setCaretChangeListener:nil];
3228    [self removeAllCaretChangeListeners];
3229    [self setWebMailDelegate:nil];
3230
3231    [self setDownloadDelegate:nil];
3232    [self setEditingDelegate:nil];
3233    [self setFrameLoadDelegate:nil];
3234    [self setPolicyDelegate:nil];
3235    [self setResourceLoadDelegate:nil];
3236    [self setScriptDebugDelegate:nil];
3237    [self setUIDelegate:nil];
3238}
3239
3240- (NSURL *)_displayURL
3241{
3242    WebThreadLock();
3243    WebFrame *frame = [self mainFrame];
3244    // FIXME: <rdar://problem/6362369> We used to get provisionalDataSource here if in provisional state; how do we tell that now? Is this right?
3245    WebDataSource *dataSource = [frame provisionalDataSource];
3246    if (!dataSource)
3247        dataSource = [frame dataSource];
3248    NSURL *unreachableURL = [dataSource unreachableURL];
3249    NSURL *URL = unreachableURL != nil ? unreachableURL : [[dataSource request] URL];
3250    [[URL retain] autorelease];
3251    return URL;
3252}
3253#endif // PLATFORM(IOS)
3254
3255#if !PLATFORM(IOS)
3256- (void)setAlwaysShowVerticalScroller:(BOOL)flag
3257{
3258    WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
3259    if (flag) {
3260        [scrollview setVerticalScrollingMode:ScrollbarAlwaysOn andLock:YES];
3261    } else {
3262        [scrollview setVerticalScrollingModeLocked:NO];
3263        [scrollview setVerticalScrollingMode:ScrollbarAuto andLock:NO];
3264    }
3265}
3266
3267- (BOOL)alwaysShowVerticalScroller
3268{
3269    WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
3270    return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == ScrollbarAlwaysOn;
3271}
3272
3273- (void)setAlwaysShowHorizontalScroller:(BOOL)flag
3274{
3275    WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
3276    if (flag) {
3277        [scrollview setHorizontalScrollingMode:ScrollbarAlwaysOn andLock:YES];
3278    } else {
3279        [scrollview setHorizontalScrollingModeLocked:NO];
3280        [scrollview setHorizontalScrollingMode:ScrollbarAuto andLock:NO];
3281    }
3282}
3283
3284- (void)setProhibitsMainFrameScrolling:(BOOL)prohibits
3285{
3286    if (Frame* mainFrame = [self _mainCoreFrame])
3287        mainFrame->view()->setProhibitsScrolling(prohibits);
3288}
3289
3290- (BOOL)alwaysShowHorizontalScroller
3291{
3292    WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
3293    return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == ScrollbarAlwaysOn;
3294}
3295#endif // !PLATFORM(IOS)
3296
3297- (void)_setUseFastImageScalingMode:(BOOL)flag
3298{
3299    if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) {
3300        _private->page->setInLowQualityImageInterpolationMode(flag);
3301        [self setNeedsDisplay:YES];
3302    }
3303}
3304
3305- (BOOL)_inFastImageScalingMode
3306{
3307    if (_private->page)
3308        return _private->page->inLowQualityImageInterpolationMode();
3309    return NO;
3310}
3311
3312- (BOOL)_cookieEnabled
3313{
3314    if (_private->page)
3315        return _private->page->settings().cookieEnabled();
3316    return YES;
3317}
3318
3319- (void)_setCookieEnabled:(BOOL)enable
3320{
3321    if (_private->page)
3322        _private->page->settings().setCookieEnabled(enable);
3323}
3324
3325#if !PLATFORM(IOS)
3326- (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
3327{
3328    if (!_private->pluginDatabase)
3329        _private->pluginDatabase = [[WebPluginDatabase alloc] init];
3330
3331    [_private->pluginDatabase setPlugInPaths:newPaths];
3332    [_private->pluginDatabase refresh];
3333}
3334#endif
3335
3336#if PLATFORM(IOS)
3337- (BOOL)_locked_plugInsAreRunningInFrame:(WebFrame *)frame
3338{
3339    // Ask plug-ins in this frame
3340    id <WebDocumentView> documentView = [[frame frameView] documentView];
3341    if (documentView && [documentView isKindOfClass:[WebHTMLView class]]) {
3342        if ([[(WebHTMLView *)documentView _pluginController] plugInsAreRunning])
3343            return YES;
3344    }
3345
3346    // Ask plug-ins in child frames
3347    NSArray *childFrames = [frame childFrames];
3348    unsigned childCount = [childFrames count];
3349    unsigned childIndex;
3350    for (childIndex = 0; childIndex < childCount; childIndex++) {
3351        if ([self _locked_plugInsAreRunningInFrame:[childFrames objectAtIndex:childIndex]])
3352            return YES;
3353    }
3354
3355    return NO;
3356}
3357
3358- (BOOL)_pluginsAreRunning
3359{
3360    WebThreadLock();
3361    return [self _locked_plugInsAreRunningInFrame:[self mainFrame]];
3362}
3363
3364- (void)_locked_recursivelyPerformPlugInSelector:(SEL)selector inFrame:(WebFrame *)frame
3365{
3366    // Send the message to plug-ins in this frame
3367    id <WebDocumentView> documentView = [[frame frameView] documentView];
3368    if (documentView && [documentView isKindOfClass:[WebHTMLView class]])
3369        [[(WebHTMLView *)documentView _pluginController] performSelector:selector];
3370
3371    // Send the message to plug-ins in child frames
3372    NSArray *childFrames = [frame childFrames];
3373    unsigned childCount = [childFrames count];
3374    unsigned childIndex;
3375    for (childIndex = 0; childIndex < childCount; childIndex++) {
3376        [self _locked_recursivelyPerformPlugInSelector:selector inFrame:[childFrames objectAtIndex:childIndex]];
3377    }
3378}
3379
3380- (void)_destroyAllPlugIns
3381{
3382    WebThreadLock();
3383    [self _locked_recursivelyPerformPlugInSelector:@selector(destroyAllPlugins) inFrame:[self mainFrame]];
3384}
3385
3386- (void)_clearBackForwardCache
3387{
3388    WebThreadRun(^{
3389        WebKit::MemoryMeasure measurer("[WebView _clearBackForwardCache]");
3390        BackForwardList* bfList = core([self backForwardList]);
3391        if (!bfList)
3392            return;
3393
3394        BOOL didClearBFCache = bfList->clearAllPageCaches();
3395        if (WebKit::MemoryMeasure::isLoggingEnabled())
3396            NSLog(@"[WebView _clearBackForwardCache] %@ empty cache\n", (didClearBFCache ? @"DID" : @"did NOT"));
3397    });
3398}
3399
3400- (void)_startAllPlugIns
3401{
3402    WebThreadLock();
3403    [self _locked_recursivelyPerformPlugInSelector:@selector(startAllPlugins) inFrame:[self mainFrame]];
3404}
3405
3406- (void)_stopAllPlugIns
3407{
3408    WebThreadLock();
3409    [self _locked_recursivelyPerformPlugInSelector:@selector(stopAllPlugins) inFrame:[self mainFrame]];
3410}
3411
3412- (void)_stopAllPlugInsForPageCache
3413{
3414    WebThreadLock();
3415    [self _locked_recursivelyPerformPlugInSelector:@selector(stopPluginsForPageCache) inFrame:[self mainFrame]];
3416}
3417
3418- (void)_restorePlugInsFromCache
3419{
3420    WebThreadLock();
3421    [self _locked_recursivelyPerformPlugInSelector:@selector(restorePluginsFromCache) inFrame:[self mainFrame]];
3422}
3423
3424- (BOOL)_setMediaLayer:(CALayer*)layer forPluginView:(NSView*)pluginView
3425{
3426    WebThreadLock();
3427
3428    Frame* mainCoreFrame = [self _mainCoreFrame];
3429    for (Frame* frame = mainCoreFrame; frame; frame = frame->tree().traverseNext()) {
3430        FrameView* coreView = frame ? frame->view() : 0;
3431        if (!coreView)
3432            continue;
3433
3434        // Get the GraphicsLayer for this widget.
3435        GraphicsLayer* layerForWidget = coreView->graphicsLayerForPlatformWidget(pluginView);
3436        if (!layerForWidget)
3437            continue;
3438
3439        if (layerForWidget->contentsLayerForMedia() != layer) {
3440            layerForWidget->setContentsToMedia(layer);
3441            // We need to make sure the layer hierachy change is applied immediately.
3442            if (mainCoreFrame->view())
3443                mainCoreFrame->view()->flushCompositingStateIncludingSubframes();
3444            return YES;
3445        }
3446    }
3447
3448    return NO;
3449}
3450
3451- (void)_setNeedsUnrestrictedGetMatchedCSSRules:(BOOL)flag
3452{
3453    if (_private->page)
3454        _private->page->settings().setCrossOriginCheckInGetMatchedCSSRulesDisabled(flag);
3455}
3456#endif // PLATFORM(IOS)
3457
3458- (void)_attachScriptDebuggerToAllFrames
3459{
3460    for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree().traverseNext())
3461        [kit(frame) _attachScriptDebugger];
3462}
3463
3464- (void)_detachScriptDebuggerFromAllFrames
3465{
3466    for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree().traverseNext())
3467        [kit(frame) _detachScriptDebugger];
3468}
3469
3470#if !PLATFORM(IOS)
3471- (void)setBackgroundColor:(NSColor *)backgroundColor
3472{
3473    if ([_private->backgroundColor isEqual:backgroundColor])
3474        return;
3475
3476    id old = _private->backgroundColor;
3477    _private->backgroundColor = [backgroundColor retain];
3478    [old release];
3479
3480    [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
3481}
3482
3483- (NSColor *)backgroundColor
3484{
3485    return _private->backgroundColor;
3486}
3487#else
3488- (void)setBackgroundColor:(CGColorRef)backgroundColor
3489{
3490   if (!backgroundColor || CFEqual(_private->backgroundColor, backgroundColor))
3491        return;
3492
3493    CFTypeRef old = _private->backgroundColor;
3494    CFRetain(backgroundColor);
3495    _private->backgroundColor = backgroundColor;
3496    CFRelease(old);
3497
3498    [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
3499}
3500
3501- (CGColorRef)backgroundColor
3502{
3503    return _private->backgroundColor;
3504}
3505#endif
3506
3507- (BOOL)defersCallbacks
3508{
3509    if (!_private->page)
3510        return NO;
3511    return _private->page->defersLoading();
3512}
3513
3514- (void)setDefersCallbacks:(BOOL)defer
3515{
3516    if (!_private->page)
3517        return;
3518    return _private->page->setDefersLoading(defer);
3519}
3520
3521#if TARGET_OS_IPHONE && USE(QUICK_LOOK)
3522- (NSDictionary *)quickLookContentForURL:(NSURL *)url
3523{
3524    NSString *uti = qlPreviewConverterUTIForURL(url);
3525    if (!uti)
3526        return nil;
3527
3528    NSString *fileName = qlPreviewConverterFileNameForURL(url);
3529    if (!fileName)
3530        return nil;
3531
3532    return [NSDictionary dictionaryWithObjectsAndKeys: fileName, WebQuickLookFileNameKey, uti, WebQuickLookUTIKey, nil];
3533}
3534#endif
3535
3536#if PLATFORM(IOS)
3537- (BOOL)_isStopping
3538{
3539    return _private->isStopping;
3540}
3541
3542- (BOOL)_isClosing
3543{
3544    return _private->closing;
3545}
3546
3547+ (NSArray *)_productivityDocumentMIMETypes
3548{
3549#if USE(QUICK_LOOK)
3550    return [QLPreviewGetSupportedMIMETypesSet() allObjects];
3551#else
3552    return nil;
3553#endif
3554}
3555
3556- (void)_setAllowsMessaging:(BOOL)aFlag
3557{
3558    _private->allowsMessaging = aFlag;
3559}
3560
3561- (BOOL)_allowsMessaging
3562{
3563    return _private->allowsMessaging;
3564}
3565
3566- (void)_setFixedLayoutSize:(CGSize)size
3567{
3568    ASSERT(WebThreadIsLocked());
3569    _private->fixedLayoutSize = size;
3570    if (Frame* mainFrame = core([self mainFrame])) {
3571        IntSize newSize(size);
3572        mainFrame->view()->setFixedLayoutSize(newSize);
3573        mainFrame->view()->setUseFixedLayout(!newSize.isEmpty());
3574        [self setNeedsDisplay:YES];
3575    }
3576}
3577
3578- (CGSize)_fixedLayoutSize
3579{
3580    return _private->fixedLayoutSize;
3581}
3582
3583- (void)_synchronizeCustomFixedPositionLayoutRect
3584{
3585    ASSERT(WebThreadIsLocked());
3586
3587    IntRect newRect;
3588    {
3589        MutexLocker locker(_private->pendingFixedPositionLayoutRectMutex);
3590        if (CGRectIsNull(_private->pendingFixedPositionLayoutRect))
3591            return;
3592        newRect = enclosingIntRect(_private->pendingFixedPositionLayoutRect);
3593        _private->pendingFixedPositionLayoutRect = CGRectNull;
3594    }
3595
3596    if (Frame* mainFrame = core([self mainFrame]))
3597        mainFrame->view()->setCustomFixedPositionLayoutRect(newRect);
3598}
3599
3600- (void)_setCustomFixedPositionLayoutRectInWebThread:(CGRect)rect synchronize:(BOOL)synchronize
3601{
3602    {
3603        MutexLocker locker(_private->pendingFixedPositionLayoutRectMutex);
3604        _private->pendingFixedPositionLayoutRect = rect;
3605    }
3606    if (!synchronize)
3607        return;
3608    WebThreadRun(^{
3609        [self _synchronizeCustomFixedPositionLayoutRect];
3610    });
3611}
3612
3613- (void)_setCustomFixedPositionLayoutRect:(CGRect)rect
3614{
3615    ASSERT(WebThreadIsLocked());
3616    {
3617        MutexLocker locker(_private->pendingFixedPositionLayoutRectMutex);
3618        _private->pendingFixedPositionLayoutRect = rect;
3619    }
3620    [self _synchronizeCustomFixedPositionLayoutRect];
3621}
3622
3623- (BOOL)_fetchCustomFixedPositionLayoutRect:(NSRect*)rect
3624{
3625    MutexLocker locker(_private->pendingFixedPositionLayoutRectMutex);
3626    if (CGRectIsNull(_private->pendingFixedPositionLayoutRect))
3627        return false;
3628
3629    *rect = _private->pendingFixedPositionLayoutRect;
3630    _private->pendingFixedPositionLayoutRect = CGRectNull;
3631    return true;
3632}
3633
3634- (void)_viewGeometryDidChange
3635{
3636    ASSERT(WebThreadIsLocked());
3637
3638    if (Frame* coreFrame = [self _mainCoreFrame])
3639        coreFrame->viewportOffsetChanged(Frame::IncrementalScrollOffset);
3640}
3641
3642- (void)_overflowScrollPositionChangedTo:(CGPoint)offset forNode:(DOMNode *)domNode isUserScroll:(BOOL)userScroll
3643{
3644    // Find the frame
3645    Node* node = core(domNode);
3646    Frame* frame = node->document().frame();
3647    if (!frame)
3648        return;
3649
3650    frame->overflowScrollPositionChangedForNode(roundedIntPoint(offset), node, userScroll);
3651}
3652
3653+ (void)_doNotStartObservingNetworkReachability
3654{
3655    Settings::setShouldOptOutOfNetworkStateObservation(true);
3656}
3657#endif // PLATFORM(IOS)
3658
3659#if ENABLE(TOUCH_EVENTS)
3660- (NSArray *)_touchEventRegions
3661{
3662    Frame* frame = [self _mainCoreFrame];
3663    if (!frame)
3664        return nil;
3665
3666    Document* document = frame->document();
3667    if (!document)
3668        return nil;
3669
3670    Vector<IntRect> rects;
3671    document->getTouchRects(rects);
3672
3673    if (rects.size() == 0)
3674        return nil;
3675
3676    NSMutableArray *eventRegionArray = [[[NSMutableArray alloc] initWithCapacity:rects.size()] autorelease];
3677
3678    Vector<IntRect>::const_iterator end = rects.end();
3679    for (Vector<IntRect>::const_iterator it = rects.begin(); it != end; ++it) {
3680        const IntRect& rect = *it;
3681        if (rect.isEmpty())
3682            continue;
3683
3684        // The event region wants this points in this order:
3685        //  p2------p3
3686        //  |       |
3687        //  p1------p4
3688        //
3689        WebEventRegion *eventRegion = [[WebEventRegion alloc] initWithPoints:FloatPoint(rect.x(), rect.maxY())
3690                                                                            :FloatPoint(rect.x(), rect.y())
3691                                                                            :FloatPoint(rect.maxX(), rect.y())
3692                                                                            :FloatPoint(rect.maxX(), rect.maxY())];
3693        if (eventRegion) {
3694            [eventRegionArray addObject:eventRegion];
3695            [eventRegion release];
3696        }
3697    }
3698
3699    return eventRegionArray;
3700}
3701#endif // ENABLE(TOUCH_EVENTS)
3702
3703// For backwards compatibility with the WebBackForwardList API, we honor both
3704// a per-WebView and a per-preferences setting for whether to use the page cache.
3705
3706- (BOOL)usesPageCache
3707{
3708    return _private->usesPageCache && [[self preferences] usesPageCache];
3709}
3710
3711- (void)setUsesPageCache:(BOOL)usesPageCache
3712{
3713    _private->usesPageCache = usesPageCache;
3714
3715    // Update our own settings and post the public notification only
3716    [self _preferencesChanged:[self preferences]];
3717    [[self preferences] _postPreferencesChangedAPINotification];
3718}
3719
3720- (WebHistoryItem *)_globalHistoryItem
3721{
3722    if (!_private)
3723        return nil;
3724
3725    return kit(_private->_globalHistoryItem.get());
3726}
3727
3728- (void)_setGlobalHistoryItem:(HistoryItem*)historyItem
3729{
3730    _private->_globalHistoryItem = historyItem;
3731}
3732
3733- (WebTextIterator *)textIteratorForRect:(NSRect)rect
3734{
3735    IntPoint rectStart(rect.origin.x, rect.origin.y);
3736    IntPoint rectEnd(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
3737
3738    Frame* coreFrame = [self _mainCoreFrame];
3739    if (!coreFrame)
3740        return nil;
3741
3742    VisibleSelection selectionInsideRect(coreFrame->visiblePositionForPoint(rectStart), coreFrame->visiblePositionForPoint(rectEnd));
3743
3744    return [[[WebTextIterator alloc] initWithRange:kit(selectionInsideRect.toNormalizedRange().get())] autorelease];
3745}
3746
3747#if ENABLE(DASHBOARD_SUPPORT)
3748- (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
3749{
3750    NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window];
3751    [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window];
3752}
3753#endif
3754
3755#if !PLATFORM(IOS)
3756- (void)_clearUndoRedoOperations
3757{
3758    if (!_private->page)
3759        return;
3760    _private->page->clearUndoRedoOperations();
3761}
3762#endif
3763
3764- (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value
3765{
3766    Frame* coreFrame = [self _mainCoreFrame];
3767    if (!coreFrame)
3768        return;
3769    coreFrame->editor().command(name).execute(value);
3770}
3771
3772- (void)_clearMainFrameName
3773{
3774    _private->page->mainFrame().tree().clearName();
3775}
3776
3777- (void)setSelectTrailingWhitespaceEnabled:(BOOL)flag
3778{
3779    if (_private->page->settings().selectTrailingWhitespaceEnabled() != flag) {
3780        _private->page->settings().setSelectTrailingWhitespaceEnabled(flag);
3781        [self setSmartInsertDeleteEnabled:!flag];
3782    }
3783}
3784
3785- (BOOL)isSelectTrailingWhitespaceEnabled
3786{
3787    return _private->page->settings().selectTrailingWhitespaceEnabled();
3788}
3789
3790- (void)setMemoryCacheDelegateCallsEnabled:(BOOL)enabled
3791{
3792    _private->page->setMemoryCacheClientCallsEnabled(enabled);
3793}
3794
3795- (BOOL)areMemoryCacheDelegateCallsEnabled
3796{
3797    return _private->page->areMemoryCacheClientCallsEnabled();
3798}
3799
3800#if !PLATFORM(IOS)
3801+ (NSCursor *)_pointingHandCursor
3802{
3803    return handCursor().platformCursor();
3804}
3805#endif
3806
3807- (BOOL)_postsAcceleratedCompositingNotifications
3808{
3809    return _private->postsAcceleratedCompositingNotifications;
3810}
3811- (void)_setPostsAcceleratedCompositingNotifications:(BOOL)flag
3812{
3813    _private->postsAcceleratedCompositingNotifications = flag;
3814}
3815
3816- (BOOL)_isUsingAcceleratedCompositing
3817{
3818    Frame* coreFrame = [self _mainCoreFrame];
3819    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
3820        NSView *documentView = [[kit(frame) frameView] documentView];
3821        if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _isUsingAcceleratedCompositing])
3822            return YES;
3823    }
3824
3825    return NO;
3826}
3827
3828- (void)_setBaseCTM:(CGAffineTransform)transform forContext:(CGContextRef)context
3829{
3830    WKSetBaseCTM(context, transform);
3831}
3832
3833- (BOOL)interactiveFormValidationEnabled
3834{
3835    return _private->interactiveFormValidationEnabled;
3836}
3837
3838- (void)setInteractiveFormValidationEnabled:(BOOL)enabled
3839{
3840    _private->interactiveFormValidationEnabled = enabled;
3841}
3842
3843- (int)validationMessageTimerMagnification
3844{
3845    return _private->validationMessageTimerMagnification;
3846}
3847
3848- (void)setValidationMessageTimerMagnification:(int)newValue
3849{
3850    _private->validationMessageTimerMagnification = newValue;
3851}
3852
3853- (BOOL)_isSoftwareRenderable
3854{
3855    Frame* coreFrame = [self _mainCoreFrame];
3856    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
3857        if (FrameView* view = frame->view()) {
3858            if (!view->isSoftwareRenderable())
3859                return NO;
3860        }
3861    }
3862
3863    return YES;
3864}
3865
3866- (void)_setIncludesFlattenedCompositingLayersWhenDrawingToBitmap:(BOOL)flag
3867{
3868    _private->includesFlattenedCompositingLayersWhenDrawingToBitmap = flag;
3869}
3870
3871- (BOOL)_includesFlattenedCompositingLayersWhenDrawingToBitmap
3872{
3873    return _private->includesFlattenedCompositingLayersWhenDrawingToBitmap;
3874}
3875
3876- (void)setTracksRepaints:(BOOL)flag
3877{
3878    Frame* coreFrame = [self _mainCoreFrame];
3879    if (FrameView* view = coreFrame->view())
3880        view->setTracksRepaints(flag);
3881}
3882
3883- (BOOL)isTrackingRepaints
3884{
3885    Frame* coreFrame = [self _mainCoreFrame];
3886    if (FrameView* view = coreFrame->view())
3887        return view->isTrackingRepaints();
3888
3889    return NO;
3890}
3891
3892- (void)resetTrackedRepaints
3893{
3894    Frame* coreFrame = [self _mainCoreFrame];
3895    if (FrameView* view = coreFrame->view())
3896        view->resetTrackedRepaints();
3897}
3898
3899- (NSArray*)trackedRepaintRects
3900{
3901    Frame* coreFrame = [self _mainCoreFrame];
3902    FrameView* view = coreFrame->view();
3903    if (!view || !view->isTrackingRepaints())
3904        return nil;
3905
3906    const Vector<FloatRect>& repaintRects = view->trackedRepaintRects();
3907    NSMutableArray* rectsArray = [[NSMutableArray alloc] initWithCapacity:repaintRects.size()];
3908
3909    for (unsigned i = 0; i < repaintRects.size(); ++i)
3910        [rectsArray addObject:[NSValue valueWithRect:pixelSnappedIntRect(LayoutRect(repaintRects[i]))]];
3911
3912    return [rectsArray autorelease];
3913}
3914
3915#if !PLATFORM(IOS)
3916- (NSPasteboard *)_insertionPasteboard
3917{
3918    return _private ? _private->insertionPasteboard : nil;
3919}
3920#endif
3921
3922+ (void)_addOriginAccessWhitelistEntryWithSourceOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains
3923{
3924    SecurityPolicy::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
3925}
3926
3927+ (void)_removeOriginAccessWhitelistEntryWithSourceOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains
3928{
3929    SecurityPolicy::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
3930}
3931
3932+ (void)_resetOriginAccessWhitelists
3933{
3934    SecurityPolicy::resetOriginAccessWhitelists();
3935}
3936
3937- (BOOL)_isViewVisible
3938{
3939    if (![self window])
3940        return false;
3941
3942    if (![[self window] isVisible])
3943        return false;
3944
3945    if ([self isHiddenOrHasHiddenAncestor])
3946        return false;
3947
3948    return true;
3949}
3950
3951- (void)_updateVisibilityState
3952{
3953    if (_private && _private->page)
3954        [self _setIsVisible:[self _isViewVisible]];
3955}
3956
3957- (void)_updateActiveState
3958{
3959    if (_private && _private->page)
3960#if PLATFORM(IOS)
3961        _private->page->focusController().setActive([[self window] isKeyWindow]);
3962#else
3963        _private->page->focusController().setActive([[self window] _hasKeyAppearance]);
3964#endif
3965}
3966
3967static Vector<String> toStringVector(NSArray* patterns)
3968{
3969    Vector<String> patternsVector;
3970
3971    NSUInteger count = [patterns count];
3972    if (!count)
3973        return patternsVector;
3974
3975    for (NSUInteger i = 0; i < count; ++i) {
3976        id entry = [patterns objectAtIndex:i];
3977        if ([entry isKindOfClass:[NSString class]])
3978            patternsVector.append(String((NSString *)entry));
3979    }
3980    return patternsVector;
3981}
3982
3983+ (void)_addUserScriptToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url
3984                    whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist
3985                injectionTime:(WebUserScriptInjectionTime)injectionTime
3986{
3987    [WebView _addUserScriptToGroup:groupName world:world source:source url:url whitelist:whitelist blacklist:blacklist injectionTime:injectionTime injectedFrames:WebInjectInAllFrames];
3988}
3989
3990+ (void)_addUserScriptToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url
3991                    whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist
3992                injectionTime:(WebUserScriptInjectionTime)injectionTime
3993               injectedFrames:(WebUserContentInjectedFrames)injectedFrames
3994{
3995    String group(groupName);
3996    if (group.isEmpty())
3997        return;
3998
3999    PageGroup* pageGroup = PageGroup::pageGroup(group);
4000    if (!pageGroup)
4001        return;
4002
4003    if (!world)
4004        return;
4005
4006    pageGroup->addUserScriptToWorld(*core(world), source, url, toStringVector(whitelist), toStringVector(blacklist),
4007                                    injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd,
4008                                    injectedFrames == WebInjectInAllFrames ? InjectInAllFrames : InjectInTopFrameOnly);
4009}
4010
4011+ (void)_addUserStyleSheetToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url
4012                        whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist
4013{
4014    [WebView _addUserStyleSheetToGroup:groupName world:world source:source url:url whitelist:whitelist blacklist:blacklist injectedFrames:WebInjectInAllFrames];
4015}
4016
4017+ (void)_addUserStyleSheetToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url
4018                        whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist
4019                   injectedFrames:(WebUserContentInjectedFrames)injectedFrames
4020{
4021    String group(groupName);
4022    if (group.isEmpty())
4023        return;
4024
4025    PageGroup* pageGroup = PageGroup::pageGroup(group);
4026    if (!pageGroup)
4027        return;
4028
4029    if (!world)
4030        return;
4031
4032    pageGroup->addUserStyleSheetToWorld(*core(world), source, url, toStringVector(whitelist), toStringVector(blacklist), injectedFrames == WebInjectInAllFrames ? InjectInAllFrames : InjectInTopFrameOnly);
4033}
4034
4035+ (void)_removeUserScriptFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url
4036{
4037    String group(groupName);
4038    if (group.isEmpty())
4039        return;
4040
4041    PageGroup* pageGroup = PageGroup::pageGroup(group);
4042    if (!pageGroup)
4043        return;
4044
4045    if (!world)
4046        return;
4047
4048    pageGroup->removeUserScriptFromWorld(*core(world), url);
4049}
4050
4051+ (void)_removeUserStyleSheetFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url
4052{
4053    String group(groupName);
4054    if (group.isEmpty())
4055        return;
4056
4057    PageGroup* pageGroup = PageGroup::pageGroup(group);
4058    if (!pageGroup)
4059        return;
4060
4061    if (!world)
4062        return;
4063
4064    pageGroup->removeUserStyleSheetFromWorld(*core(world), url);
4065}
4066
4067+ (void)_removeUserScriptsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world
4068{
4069    String group(groupName);
4070    if (group.isEmpty())
4071        return;
4072
4073    PageGroup* pageGroup = PageGroup::pageGroup(group);
4074    if (!pageGroup)
4075        return;
4076
4077    if (!world)
4078        return;
4079
4080    pageGroup->removeUserScriptsFromWorld(*core(world));
4081}
4082
4083+ (void)_removeUserStyleSheetsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world
4084{
4085    String group(groupName);
4086    if (group.isEmpty())
4087        return;
4088
4089    PageGroup* pageGroup = PageGroup::pageGroup(group);
4090    if (!pageGroup)
4091        return;
4092
4093    if (!world)
4094        return;
4095
4096    pageGroup->removeUserStyleSheetsFromWorld(*core(world));
4097}
4098
4099+ (void)_removeAllUserContentFromGroup:(NSString *)groupName
4100{
4101    String group(groupName);
4102    if (group.isEmpty())
4103        return;
4104
4105    PageGroup* pageGroup = PageGroup::pageGroup(group);
4106    if (!pageGroup)
4107        return;
4108
4109    pageGroup->removeAllUserContent();
4110}
4111
4112- (BOOL)allowsNewCSSAnimationsWhileSuspended
4113{
4114    Frame* frame = core([self mainFrame]);
4115    if (frame)
4116        return frame->animation().allowsNewAnimationsWhileSuspended();
4117
4118    return false;
4119}
4120
4121- (void)setAllowsNewCSSAnimationsWhileSuspended:(BOOL)allowed
4122{
4123    Frame* frame = core([self mainFrame]);
4124    if (frame)
4125        frame->animation().setAllowsNewAnimationsWhileSuspended(allowed);
4126}
4127
4128- (BOOL)cssAnimationsSuspended
4129{
4130    // should ask the page!
4131    Frame* frame = core([self mainFrame]);
4132    if (frame)
4133        return frame->animation().isSuspended();
4134
4135    return false;
4136}
4137
4138- (void)setCSSAnimationsSuspended:(BOOL)suspended
4139{
4140    Frame* frame = core([self mainFrame]);
4141    if (suspended == frame->animation().isSuspended())
4142        return;
4143
4144    if (suspended)
4145        frame->animation().suspendAnimations();
4146    else
4147        frame->animation().resumeAnimations();
4148}
4149
4150+ (void)_setDomainRelaxationForbidden:(BOOL)forbidden forURLScheme:(NSString *)scheme
4151{
4152    SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
4153}
4154
4155+ (void)_registerURLSchemeAsSecure:(NSString *)scheme
4156{
4157    SchemeRegistry::registerURLSchemeAsSecure(scheme);
4158}
4159
4160+ (void)_registerURLSchemeAsAllowingLocalStorageAccessInPrivateBrowsing:(NSString *)scheme
4161{
4162    SchemeRegistry::registerURLSchemeAsAllowingLocalStorageAccessInPrivateBrowsing(scheme);
4163}
4164
4165+ (void)_registerURLSchemeAsAllowingDatabaseAccessInPrivateBrowsing:(NSString *)scheme
4166{
4167    SchemeRegistry::registerURLSchemeAsAllowingDatabaseAccessInPrivateBrowsing(scheme);
4168}
4169
4170- (void)_scaleWebView:(float)scale atOrigin:(NSPoint)origin
4171{
4172    _private->page->setPageScaleFactor(scale, IntPoint(origin));
4173}
4174
4175- (float)_viewScaleFactor
4176{
4177    return _private->page->pageScaleFactor();
4178}
4179
4180- (void)_setUseFixedLayout:(BOOL)fixed
4181{
4182    Frame* coreFrame = [self _mainCoreFrame];
4183    if (!coreFrame)
4184        return;
4185
4186    FrameView* view = coreFrame->view();
4187    if (!view)
4188        return;
4189
4190    view->setUseFixedLayout(fixed);
4191    if (!fixed)
4192        view->setFixedLayoutSize(IntSize());
4193}
4194
4195#if !PLATFORM(IOS)
4196- (void)_setFixedLayoutSize:(NSSize)size
4197{
4198    Frame* coreFrame = [self _mainCoreFrame];
4199    if (!coreFrame)
4200        return;
4201
4202    FrameView* view = coreFrame->view();
4203    if (!view)
4204        return;
4205
4206    view->setFixedLayoutSize(IntSize(size));
4207    view->forceLayout();
4208}
4209#endif
4210
4211- (BOOL)_useFixedLayout
4212{
4213    Frame* coreFrame = [self _mainCoreFrame];
4214    if (!coreFrame)
4215        return NO;
4216
4217    FrameView* view = coreFrame->view();
4218    if (!view)
4219        return NO;
4220
4221    return view->useFixedLayout();
4222}
4223
4224#if !PLATFORM(IOS)
4225- (NSSize)_fixedLayoutSize
4226{
4227    Frame* coreFrame = [self _mainCoreFrame];
4228    if (!coreFrame)
4229        return IntSize();
4230
4231    FrameView* view = coreFrame->view();
4232    if (!view)
4233        return IntSize();
4234
4235    return view->fixedLayoutSize();
4236}
4237#endif
4238
4239- (void)_setPaginationMode:(WebPaginationMode)paginationMode
4240{
4241    Page* page = core(self);
4242    if (!page)
4243        return;
4244
4245    Pagination pagination = page->pagination();
4246    switch (paginationMode) {
4247    case WebPaginationModeUnpaginated:
4248        pagination.mode = Pagination::Unpaginated;
4249        break;
4250    case WebPaginationModeLeftToRight:
4251        pagination.mode = Pagination::LeftToRightPaginated;
4252        break;
4253    case WebPaginationModeRightToLeft:
4254        pagination.mode = Pagination::RightToLeftPaginated;
4255        break;
4256    case WebPaginationModeTopToBottom:
4257        pagination.mode = Pagination::TopToBottomPaginated;
4258        break;
4259    case WebPaginationModeBottomToTop:
4260        pagination.mode = Pagination::BottomToTopPaginated;
4261        break;
4262    default:
4263        return;
4264    }
4265
4266    page->setPagination(pagination);
4267}
4268
4269- (WebPaginationMode)_paginationMode
4270{
4271    Page* page = core(self);
4272    if (!page)
4273        return WebPaginationModeUnpaginated;
4274
4275    switch (page->pagination().mode) {
4276    case Pagination::Unpaginated:
4277        return WebPaginationModeUnpaginated;
4278    case Pagination::LeftToRightPaginated:
4279        return WebPaginationModeLeftToRight;
4280    case Pagination::RightToLeftPaginated:
4281        return WebPaginationModeRightToLeft;
4282    case Pagination::TopToBottomPaginated:
4283        return WebPaginationModeTopToBottom;
4284    case Pagination::BottomToTopPaginated:
4285        return WebPaginationModeBottomToTop;
4286    }
4287
4288    ASSERT_NOT_REACHED();
4289    return WebPaginationModeUnpaginated;
4290}
4291
4292- (void)_listenForLayoutMilestones:(WebLayoutMilestones)layoutMilestones
4293{
4294    Page* page = core(self);
4295    if (!page)
4296        return;
4297
4298    page->addLayoutMilestones(coreLayoutMilestones(layoutMilestones));
4299}
4300
4301- (WebLayoutMilestones)_layoutMilestones
4302{
4303    Page* page = core(self);
4304    if (!page)
4305        return 0;
4306
4307    return kitLayoutMilestones(page->requestedLayoutMilestones());
4308}
4309
4310- (WebPageVisibilityState)_visibilityState
4311{
4312    if (_private->page)
4313        return kit(_private->page->visibilityState());
4314    return WebPageVisibilityStateVisible;
4315}
4316
4317- (void)_setIsVisible:(BOOL)isVisible
4318{
4319    if (_private->page)
4320        _private->page->setIsVisible(isVisible);
4321}
4322
4323- (void)_setVisibilityState:(WebPageVisibilityState)visibilityState isInitialState:(BOOL)isInitialState
4324{
4325    UNUSED_PARAM(isInitialState);
4326
4327    if (_private->page) {
4328        _private->page->setIsVisible(visibilityState == WebPageVisibilityStateVisible);
4329        if (visibilityState == WebPageVisibilityStatePrerender)
4330            _private->page->setIsPrerender();
4331    }
4332}
4333
4334- (void)_setPaginationBehavesLikeColumns:(BOOL)behavesLikeColumns
4335{
4336    Page* page = core(self);
4337    if (!page)
4338        return;
4339
4340    Pagination pagination = page->pagination();
4341    pagination.behavesLikeColumns = behavesLikeColumns;
4342
4343    page->setPagination(pagination);
4344}
4345
4346- (BOOL)_paginationBehavesLikeColumns
4347{
4348    Page* page = core(self);
4349    if (!page)
4350        return NO;
4351
4352    return page->pagination().behavesLikeColumns;
4353}
4354
4355- (void)_setPageLength:(CGFloat)pageLength
4356{
4357    Page* page = core(self);
4358    if (!page)
4359        return;
4360
4361    Pagination pagination = page->pagination();
4362    pagination.pageLength = pageLength;
4363
4364    page->setPagination(pagination);
4365}
4366
4367- (CGFloat)_pageLength
4368{
4369    Page* page = core(self);
4370    if (!page)
4371        return 1;
4372
4373    return page->pagination().pageLength;
4374}
4375
4376- (void)_setGapBetweenPages:(CGFloat)pageGap
4377{
4378    Page* page = core(self);
4379    if (!page)
4380        return;
4381
4382    Pagination pagination = page->pagination();
4383    pagination.gap = pageGap;
4384    page->setPagination(pagination);
4385}
4386
4387- (CGFloat)_gapBetweenPages
4388{
4389    Page* page = core(self);
4390    if (!page)
4391        return 0;
4392
4393    return page->pagination().gap;
4394}
4395
4396- (NSUInteger)_pageCount
4397{
4398    Page* page = core(self);
4399    if (!page)
4400        return 0;
4401
4402    return page->pageCount();
4403}
4404
4405#if !PLATFORM(IOS)
4406- (CGFloat)_backingScaleFactor
4407{
4408    return [self _deviceScaleFactor];
4409}
4410
4411- (void)_setCustomBackingScaleFactor:(CGFloat)customScaleFactor
4412{
4413    float oldScaleFactor = [self _deviceScaleFactor];
4414
4415    _private->customDeviceScaleFactor = customScaleFactor;
4416
4417    if (oldScaleFactor != [self _deviceScaleFactor])
4418        _private->page->setDeviceScaleFactor([self _deviceScaleFactor]);
4419}
4420#endif
4421
4422- (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit
4423{
4424    return [self countMatchesForText:string options:(caseFlag ? 0 : WebFindOptionsCaseInsensitive) highlight:highlight limit:limit markMatches:YES];
4425}
4426
4427- (NSUInteger)countMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit markMatches:(BOOL)markMatches
4428{
4429    return [self countMatchesForText:string options:(caseFlag ? 0 : WebFindOptionsCaseInsensitive) highlight:highlight limit:limit markMatches:markMatches];
4430}
4431
4432- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
4433{
4434    return [self findString:string options:((forward ? 0 : WebFindOptionsBackwards) | (caseFlag ? 0 : WebFindOptionsCaseInsensitive) | (wrapFlag ? WebFindOptionsWrapAround : 0) | (startInSelection ? WebFindOptionsStartInSelection : 0))];
4435}
4436
4437+ (void)_setLoadResourcesSerially:(BOOL)serialize
4438{
4439    WebPlatformStrategies::initializeIfNecessary();
4440    resourceLoadScheduler()->setSerialLoadingEnabled(serialize);
4441}
4442
4443+ (BOOL)_HTTPPipeliningEnabled
4444{
4445    return ResourceRequest::httpPipeliningEnabled();
4446}
4447
4448+ (void)_setHTTPPipeliningEnabled:(BOOL)enabled
4449{
4450    ResourceRequest::setHTTPPipeliningEnabled(enabled);
4451}
4452
4453#if PLATFORM(IOS)
4454- (WebFixedPositionContent*)_fixedPositionContent
4455{
4456    return _private ? _private->_fixedPositionContent : nil;
4457}
4458
4459- (void)_documentScaleChanged
4460{
4461    if (WebNodeHighlight *currentHighlight = [self currentNodeHighlight])
4462        [currentHighlight setNeedsDisplay];
4463
4464    if (_private->indicateLayer) {
4465        [_private->indicateLayer setNeedsLayout];
4466        [_private->indicateLayer setNeedsDisplay];
4467    }
4468}
4469
4470- (BOOL)_wantsTelephoneNumberParsing
4471{
4472    if (!_private->page)
4473        return NO;
4474    return _private->page->settings().telephoneNumberParsingEnabled();
4475}
4476
4477- (void)_setWantsTelephoneNumberParsing:(BOOL)flag
4478{
4479    if (_private->page)
4480        _private->page->settings().setTelephoneNumberParsingEnabled(flag);
4481}
4482
4483- (BOOL)_webGLEnabled
4484{
4485    if (!_private->page)
4486        return NO;
4487    return _private->page->settings().webGLEnabled();
4488}
4489
4490- (void)_setWebGLEnabled:(BOOL)enabled
4491{
4492    if (_private->page)
4493        _private->page->settings().setWebGLEnabled(enabled);
4494}
4495
4496+ (void)_setTileCacheLayerPoolCapacity:(unsigned)capacity
4497{
4498    LegacyTileCache::setLayerPoolCapacity(capacity);
4499}
4500#endif // PLATFORM(IOS)
4501
4502- (void)_setSourceApplicationAuditData:(NSData *)sourceApplicationAuditData
4503{
4504    if (_private->sourceApplicationAuditData == sourceApplicationAuditData)
4505        return;
4506
4507    _private->sourceApplicationAuditData = adoptNS([sourceApplicationAuditData copy]);
4508}
4509
4510- (NSData *)_sourceApplicationAuditData
4511{
4512    return _private->sourceApplicationAuditData.get();
4513}
4514
4515- (void)_setFontFallbackPrefersPictographs:(BOOL)flag
4516{
4517    if (_private->page)
4518        _private->page->settings().setFontFallbackPrefersPictographs(flag);
4519}
4520
4521@end
4522
4523@implementation _WebSafeForwarder
4524
4525// Used to send messages to delegates that implement informal protocols.
4526
4527- (instancetype)initWithTarget:(id)t defaultTarget:(id)dt
4528{
4529    self = [super init];
4530    if (!self)
4531        return nil;
4532    target = t; // Non retained.
4533    defaultTarget = dt;
4534    return self;
4535}
4536
4537#if PLATFORM(IOS)
4538- (id)asyncForwarder
4539{
4540    dispatch_once(&asyncForwarderPred, ^{
4541        asyncForwarder = [[_WebSafeAsyncForwarder alloc] initWithForwarder:self];
4542    });
4543    return asyncForwarder;
4544}
4545
4546- (void)dealloc
4547{
4548    [asyncForwarder release];
4549    [super dealloc];
4550}
4551
4552- (void)clearTarget
4553{
4554    target = nil;
4555}
4556#endif
4557
4558- (void)forwardInvocation:(NSInvocation *)invocation
4559{
4560#if PLATFORM(IOS)
4561    if (WebThreadIsCurrent()) {
4562        [invocation retainArguments];
4563        WebThreadCallDelegate(invocation);
4564        return;
4565    }
4566#endif
4567    if ([target respondsToSelector:[invocation selector]]) {
4568        @try {
4569            [invocation invokeWithTarget:target];
4570        } @catch(id exception) {
4571            ReportDiscardedDelegateException([invocation selector], exception);
4572        }
4573        return;
4574    }
4575
4576    if ([defaultTarget respondsToSelector:[invocation selector]])
4577        [invocation invokeWithTarget:defaultTarget];
4578
4579    // Do nothing quietly if method not implemented.
4580}
4581
4582#if PLATFORM(IOS)
4583- (BOOL)respondsToSelector:(SEL)aSelector
4584{
4585    return [defaultTarget respondsToSelector:aSelector];
4586}
4587#endif
4588
4589- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
4590{
4591    return [defaultTarget methodSignatureForSelector:aSelector];
4592}
4593
4594@end
4595
4596#if PLATFORM(IOS)
4597@implementation _WebSafeAsyncForwarder
4598
4599- (id)initWithForwarder:(_WebSafeForwarder *)forwarder
4600{
4601    if (!(self = [super init]))
4602        return nil;
4603    _forwarder = forwarder;
4604    return self;
4605}
4606
4607- (void)forwardInvocation:(NSInvocation *)invocation
4608{
4609    // Store _forwarder in an ivar so it is retained by the block.
4610    _WebSafeForwarder *forwarder = _forwarder;
4611    if (WebThreadIsCurrent()) {
4612        [invocation retainArguments];
4613        dispatch_async(dispatch_get_main_queue(), ^{
4614            [forwarder forwardInvocation:invocation];
4615        });
4616    } else
4617        [forwarder forwardInvocation:invocation];
4618}
4619
4620- (BOOL)respondsToSelector:(SEL)aSelector
4621{
4622    return [_forwarder respondsToSelector:aSelector];
4623}
4624
4625- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
4626{
4627    return [_forwarder methodSignatureForSelector:aSelector];
4628}
4629
4630@end
4631#endif
4632
4633@implementation WebView
4634
4635+ (void)initialize
4636{
4637    static BOOL initialized = NO;
4638    if (initialized)
4639        return;
4640    initialized = YES;
4641
4642    InitWebCoreSystemInterface();
4643#if !PLATFORM(IOS)
4644    JSC::initializeThreading();
4645    WTF::initializeMainThreadToProcessMainThread();
4646    RunLoop::initializeMainRunLoop();
4647#endif
4648
4649#if !PLATFORM(IOS)
4650    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp];
4651#endif
4652    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_cacheModelChangedNotification:) name:WebPreferencesCacheModelChangedInternalNotification object:nil];
4653    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil];
4654
4655    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
4656
4657#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
4658    [defaults registerDefaults:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:WebKitKerningAndLigaturesEnabledByDefaultDefaultsKey]];
4659#endif
4660
4661#if PLATFORM(IOS)
4662    continuousSpellCheckingEnabled = NO;
4663#endif
4664
4665#if !PLATFORM(IOS)
4666    continuousSpellCheckingEnabled = [defaults boolForKey:WebContinuousSpellCheckingEnabled];
4667    grammarCheckingEnabled = [defaults boolForKey:WebGrammarCheckingEnabled];
4668#endif
4669
4670    Font::setDefaultTypesettingFeatures([defaults boolForKey:WebKitKerningAndLigaturesEnabledByDefaultDefaultsKey] ? Kerning | Ligatures : 0);
4671
4672#if !PLATFORM(IOS)
4673    automaticQuoteSubstitutionEnabled = [self _shouldAutomaticQuoteSubstitutionBeEnabled];
4674    automaticLinkDetectionEnabled = [defaults boolForKey:WebAutomaticLinkDetectionEnabled];
4675    automaticDashSubstitutionEnabled = [self _shouldAutomaticDashSubstitutionBeEnabled];
4676    automaticTextReplacementEnabled = [self _shouldAutomaticTextReplacementBeEnabled];
4677    automaticSpellingCorrectionEnabled = [self _shouldAutomaticSpellingCorrectionBeEnabled];
4678
4679    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didChangeAutomaticTextReplacementEnabled:)
4680        name:NSSpellCheckerDidChangeAutomaticTextReplacementNotification object:nil];
4681    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didChangeAutomaticSpellingCorrectionEnabled:)
4682        name:NSSpellCheckerDidChangeAutomaticSpellingCorrectionNotification object:nil];
4683
4684#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
4685    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didChangeAutomaticQuoteSubstitutionEnabled:)
4686        name:NSSpellCheckerDidChangeAutomaticQuoteSubstitutionNotification object:nil];
4687    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didChangeAutomaticDashSubstitutionEnabled:)
4688        name:NSSpellCheckerDidChangeAutomaticDashSubstitutionNotification object:nil];
4689#endif
4690#endif
4691}
4692
4693#if !PLATFORM(IOS)
4694+ (BOOL)_shouldAutomaticTextReplacementBeEnabled
4695{
4696    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
4697    if (![defaults objectForKey:WebAutomaticTextReplacementEnabled])
4698        return [NSSpellChecker isAutomaticTextReplacementEnabled];
4699    return [defaults boolForKey:WebAutomaticTextReplacementEnabled];
4700}
4701
4702+ (void)_didChangeAutomaticTextReplacementEnabled:(NSNotification *)notification
4703{
4704    automaticTextReplacementEnabled = [self _shouldAutomaticTextReplacementBeEnabled];
4705    [[NSSpellChecker sharedSpellChecker] updatePanels];
4706}
4707
4708+ (BOOL)_shouldAutomaticSpellingCorrectionBeEnabled
4709{
4710    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
4711    if (![defaults objectForKey:WebAutomaticSpellingCorrectionEnabled])
4712        return [NSSpellChecker isAutomaticTextReplacementEnabled];
4713    return [defaults boolForKey:WebAutomaticSpellingCorrectionEnabled];
4714}
4715
4716+ (void)_didChangeAutomaticSpellingCorrectionEnabled:(NSNotification *)notification
4717{
4718    automaticSpellingCorrectionEnabled = [self _shouldAutomaticSpellingCorrectionBeEnabled];
4719    [[NSSpellChecker sharedSpellChecker] updatePanels];
4720}
4721
4722+ (BOOL)_shouldAutomaticQuoteSubstitutionBeEnabled
4723{
4724    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
4725#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
4726    if (![defaults objectForKey:WebAutomaticQuoteSubstitutionEnabled])
4727        return [NSSpellChecker isAutomaticQuoteSubstitutionEnabled];
4728#endif
4729    return [defaults boolForKey:WebAutomaticQuoteSubstitutionEnabled];
4730}
4731
4732+ (BOOL)_shouldAutomaticDashSubstitutionBeEnabled
4733{
4734    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
4735#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
4736    if (![defaults objectForKey:WebAutomaticDashSubstitutionEnabled])
4737        return [NSSpellChecker isAutomaticDashSubstitutionEnabled];
4738#endif
4739    return [defaults boolForKey:WebAutomaticDashSubstitutionEnabled];
4740}
4741
4742#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
4743+ (void)_didChangeAutomaticQuoteSubstitutionEnabled:(NSNotification *)notification
4744{
4745    automaticQuoteSubstitutionEnabled = [self _shouldAutomaticQuoteSubstitutionBeEnabled];
4746    [[NSSpellChecker sharedSpellChecker] updatePanels];
4747}
4748
4749+ (void)_didChangeAutomaticDashSubstitutionEnabled:(NSNotification *)notification
4750{
4751    automaticDashSubstitutionEnabled = [self _shouldAutomaticDashSubstitutionBeEnabled];
4752    [[NSSpellChecker sharedSpellChecker] updatePanels];
4753}
4754#endif
4755
4756+ (void)_applicationWillTerminate
4757{
4758    applicationIsTerminating = YES;
4759
4760    if (fastDocumentTeardownEnabled())
4761        [self closeAllWebViews];
4762
4763    if (!pluginDatabaseClientCount)
4764        [WebPluginDatabase closeSharedDatabase];
4765
4766    PageGroup::closeLocalStorage();
4767}
4768#endif // !PLATFORM(IOS)
4769
4770+ (BOOL)_canShowMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
4771{
4772    return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins];
4773}
4774
4775+ (BOOL)canShowMIMEType:(NSString *)MIMEType
4776{
4777    return [self _canShowMIMEType:MIMEType allowingPlugins:YES];
4778}
4779
4780- (BOOL)_canShowMIMEType:(NSString *)MIMEType
4781{
4782    return [[self class] _canShowMIMEType:MIMEType allowingPlugins:[_private->preferences arePlugInsEnabled]];
4783}
4784
4785- (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
4786{
4787    if (![_private->preferences arePlugInsEnabled])
4788        return nil;
4789
4790    WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType];
4791    if (pluginPackage)
4792        return pluginPackage;
4793
4794#if !PLATFORM(IOS)
4795    if (_private->pluginDatabase)
4796        return [_private->pluginDatabase pluginForMIMEType:MIMEType];
4797#endif
4798
4799    return nil;
4800}
4801
4802- (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
4803{
4804    if (![_private->preferences arePlugInsEnabled])
4805        return nil;
4806
4807    WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension];
4808    if (pluginPackage)
4809        return pluginPackage;
4810
4811#if !PLATFORM(IOS)
4812    if (_private->pluginDatabase)
4813        return [_private->pluginDatabase pluginForExtension:extension];
4814#endif
4815
4816    return nil;
4817}
4818
4819#if !PLATFORM(IOS)
4820- (void)addPluginInstanceView:(NSView *)view
4821{
4822    if (!_private->pluginDatabase)
4823        _private->pluginDatabase = [[WebPluginDatabase alloc] init];
4824    [_private->pluginDatabase addPluginInstanceView:view];
4825}
4826
4827- (void)removePluginInstanceView:(NSView *)view
4828{
4829    if (_private->pluginDatabase)
4830        [_private->pluginDatabase removePluginInstanceView:view];
4831}
4832
4833- (void)removePluginInstanceViewsFor:(WebFrame*)webFrame
4834{
4835    if (_private->pluginDatabase)
4836        [_private->pluginDatabase removePluginInstanceViewsFor:webFrame];
4837}
4838#endif
4839
4840- (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
4841{
4842    if (![_private->preferences arePlugInsEnabled])
4843        return NO;
4844
4845    if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType])
4846        return YES;
4847
4848#if !PLATFORM(IOS)
4849    if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
4850        return YES;
4851#endif
4852
4853    return NO;
4854}
4855
4856+ (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
4857{
4858#if PLATFORM(IOS)
4859    // FIXME: <rdar://problem/7961656> +[WebView canShowMIMETypeAsHTML:] regressed significantly in iOS 4.0
4860    // Fast path for the common case to avoid creating the MIME type registry.
4861    if ([MIMEType isEqualToString:@"text/html"])
4862        return YES;
4863#endif
4864    return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
4865}
4866
4867+ (NSArray *)MIMETypesShownAsHTML
4868{
4869    NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
4870    NSEnumerator *enumerator = [viewTypes keyEnumerator];
4871    id key;
4872    NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
4873
4874    while ((key = [enumerator nextObject])) {
4875        if ([viewTypes objectForKey:key] == [WebHTMLView class])
4876            [array addObject:key];
4877    }
4878
4879    return array;
4880}
4881
4882+ (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
4883{
4884    NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy];
4885    NSEnumerator *enumerator = [viewTypes keyEnumerator];
4886    id key;
4887    while ((key = [enumerator nextObject])) {
4888        if ([viewTypes objectForKey:key] == [WebHTMLView class])
4889            [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
4890    }
4891
4892    int i, count = [MIMETypes count];
4893    for (i = 0; i < count; i++) {
4894        [WebView registerViewClass:[WebHTMLView class]
4895                representationClass:[WebHTMLRepresentation class]
4896                forMIMEType:[MIMETypes objectAtIndex:i]];
4897    }
4898    [viewTypes release];
4899}
4900
4901#if !PLATFORM(IOS)
4902+ (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
4903{
4904    return [pasteboard _web_bestURL];
4905}
4906
4907+ (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
4908{
4909    return [pasteboard stringForType:WebURLNamePboardType];
4910}
4911#endif
4912
4913+ (void)registerURLSchemeAsLocal:(NSString *)protocol
4914{
4915    SchemeRegistry::registerURLSchemeAsLocal(protocol);
4916}
4917
4918- (id)_initWithArguments:(NSDictionary *) arguments
4919{
4920#if !PLATFORM(IOS)
4921    NSCoder *decoder = [arguments objectForKey:@"decoder"];
4922    if (decoder) {
4923        self = [self initWithCoder:decoder];
4924    } else {
4925#endif
4926        ASSERT([arguments objectForKey:@"frame"]);
4927        NSValue *frameValue = [arguments objectForKey:@"frame"];
4928        NSRect frame = (frameValue ? [frameValue rectValue] : NSZeroRect);
4929        NSString *frameName = [arguments objectForKey:@"frameName"];
4930        NSString *groupName = [arguments objectForKey:@"groupName"];
4931        self = [self initWithFrame:frame frameName:frameName groupName:groupName];
4932#if !PLATFORM(IOS)
4933    }
4934#endif
4935
4936    return self;
4937}
4938
4939#if !PLATFORM(IOS)
4940static bool clientNeedsWebViewInitThreadWorkaround()
4941{
4942    if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND))
4943        return false;
4944
4945    NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
4946
4947    // Installer.
4948    if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.installer"])
4949        return true;
4950
4951    // Automator.
4952    if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Automator"])
4953        return true;
4954
4955    // Automator Runner.
4956    if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.AutomatorRunner"])
4957        return true;
4958
4959    // Automator workflows.
4960    if ([bundleIdentifier _webkit_hasCaseInsensitivePrefix:@"com.apple.Automator."])
4961        return true;
4962
4963    return false;
4964}
4965
4966static bool needsWebViewInitThreadWorkaround()
4967{
4968    static bool isOldClient = clientNeedsWebViewInitThreadWorkaround();
4969    return isOldClient && !pthread_main_np();
4970}
4971#endif // !PLATFORM(IOS)
4972
4973- (instancetype)initWithFrame:(NSRect)f
4974{
4975    return [self initWithFrame:f frameName:nil groupName:nil];
4976}
4977
4978- (instancetype)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName
4979{
4980#if !PLATFORM(IOS)
4981    if (needsWebViewInitThreadWorkaround())
4982        return [[self _webkit_invokeOnMainThread] initWithFrame:f frameName:frameName groupName:groupName];
4983#endif
4984
4985    WebCoreThreadViolationCheckRoundTwo();
4986    return [self _initWithFrame:f frameName:frameName groupName:groupName];
4987}
4988
4989#if !PLATFORM(IOS)
4990- (instancetype)initWithCoder:(NSCoder *)decoder
4991{
4992    if (needsWebViewInitThreadWorkaround())
4993        return [[self _webkit_invokeOnMainThread] initWithCoder:decoder];
4994
4995    WebCoreThreadViolationCheckRoundTwo();
4996    WebView *result = nil;
4997
4998    @try {
4999        NSString *frameName;
5000        NSString *groupName;
5001        WebPreferences *preferences;
5002        BOOL useBackForwardList = NO;
5003        BOOL allowsUndo = YES;
5004
5005        result = [super initWithCoder:decoder];
5006        result->_private = [[WebViewPrivate alloc] init];
5007
5008        // We don't want any of the archived subviews. The subviews will always
5009        // be created in _commonInitializationFrameName:groupName:.
5010        [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
5011
5012        if ([decoder allowsKeyedCoding]) {
5013            frameName = [decoder decodeObjectForKey:@"FrameName"];
5014            groupName = [decoder decodeObjectForKey:@"GroupName"];
5015            preferences = [decoder decodeObjectForKey:@"Preferences"];
5016            useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
5017            if ([decoder containsValueForKey:@"AllowsUndo"])
5018                allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"];
5019        } else {
5020            int version;
5021            [decoder decodeValueOfObjCType:@encode(int) at:&version];
5022            frameName = [decoder decodeObject];
5023            groupName = [decoder decodeObject];
5024            preferences = [decoder decodeObject];
5025            if (version > 1)
5026                [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList];
5027            // The allowsUndo field is no longer written out in encodeWithCoder, but since there are
5028            // version 3 NIBs that have this field encoded, we still need to read it in.
5029            if (version == 3)
5030                [decoder decodeValuesOfObjCTypes:"c", &allowsUndo];
5031        }
5032
5033        if (![frameName isKindOfClass:[NSString class]])
5034            frameName = nil;
5035        if (![groupName isKindOfClass:[NSString class]])
5036            groupName = nil;
5037        if (![preferences isKindOfClass:[WebPreferences class]])
5038            preferences = nil;
5039
5040        LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList);
5041        [result _commonInitializationWithFrameName:frameName groupName:groupName];
5042        static_cast<BackForwardList*>([result page]->backForward().client())->setEnabled(useBackForwardList);
5043        result->_private->allowsUndo = allowsUndo;
5044        if (preferences)
5045            [result setPreferences:preferences];
5046    } @catch (NSException *localException) {
5047        result = nil;
5048        [self release];
5049    }
5050
5051    return result;
5052}
5053
5054- (void)encodeWithCoder:(NSCoder *)encoder
5055{
5056    // Set asside the subviews before we archive. We don't want to archive any subviews.
5057    // The subviews will always be created in _commonInitializationFrameName:groupName:.
5058    id originalSubviews = _subviews;
5059    _subviews = nil;
5060
5061    [super encodeWithCoder:encoder];
5062
5063    // Restore the subviews we set aside.
5064    _subviews = originalSubviews;
5065
5066    BOOL useBackForwardList = _private->page && static_cast<BackForwardList*>(_private->page->backForward().client())->enabled();
5067    if ([encoder allowsKeyedCoding]) {
5068        [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
5069        [encoder encodeObject:[self groupName] forKey:@"GroupName"];
5070        [encoder encodeObject:[self preferences] forKey:@"Preferences"];
5071        [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"];
5072        [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"];
5073    } else {
5074        int version = WebViewVersion;
5075        [encoder encodeValueOfObjCType:@encode(int) at:&version];
5076        [encoder encodeObject:[[self mainFrame] name]];
5077        [encoder encodeObject:[self groupName]];
5078        [encoder encodeObject:[self preferences]];
5079        [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList];
5080        // DO NOT encode any new fields here, doing so will break older WebKit releases.
5081    }
5082
5083    LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList);
5084}
5085#endif // !PLATFORM(IOS)
5086
5087- (void)dealloc
5088{
5089    if (WebCoreObjCScheduleDeallocateOnMainThread([WebView class], self))
5090        return;
5091
5092#if PLATFORM(IOS)
5093    if (_private)
5094        [_private->_geolocationProvider stopTrackingWebView:self];
5095#endif
5096
5097    // call close to ensure we tear-down completely
5098    // this maintains our old behavior for existing applications
5099    [self close];
5100
5101    if ([[self class] shouldIncludeInWebKitStatistics])
5102        --WebViewCount;
5103
5104#if !PLATFORM(IOS)
5105    if ([self _needsFrameLoadDelegateRetainQuirk])
5106        [_private->frameLoadDelegate release];
5107#endif
5108
5109    [_private release];
5110    // [super dealloc] can end up dispatching against _private (3466082)
5111    _private = nil;
5112
5113    [super dealloc];
5114}
5115
5116- (void)finalize
5117{
5118    ASSERT(_private->closed);
5119
5120    --WebViewCount;
5121
5122    [super finalize];
5123}
5124
5125- (void)close
5126{
5127    // _close existed first, and some clients might be calling or overriding it, so call through.
5128    [self _close];
5129
5130#if PLATFORM(IOS)
5131    if (_private->layerFlushController) {
5132        _private->layerFlushController->invalidate();
5133        _private->layerFlushController = nullptr;
5134    }
5135#endif
5136}
5137
5138- (void)setShouldCloseWithWindow:(BOOL)close
5139{
5140    _private->shouldCloseWithWindow = close;
5141}
5142
5143- (BOOL)shouldCloseWithWindow
5144{
5145    return _private->shouldCloseWithWindow;
5146}
5147
5148#if !PLATFORM(IOS)
5149// FIXME: Use AppKit constants for these when they are available.
5150static NSString * const windowDidChangeBackingPropertiesNotification = @"NSWindowDidChangeBackingPropertiesNotification";
5151static NSString * const backingPropertyOldScaleFactorKey = @"NSBackingPropertyOldScaleFactorKey";
5152
5153- (void)addWindowObserversForWindow:(NSWindow *)window
5154{
5155    if (window) {
5156        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowKeyStateChanged:)
5157            name:NSWindowDidBecomeKeyNotification object:window];
5158        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowKeyStateChanged:)
5159            name:NSWindowDidResignKeyNotification object:window];
5160        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOnScreen:)
5161            name:WKWindowWillOrderOnScreenNotification() object:window];
5162        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOffScreen:)
5163            name:WKWindowWillOrderOffScreenNotification() object:window];
5164        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeBackingProperties:)
5165            name:windowDidChangeBackingPropertiesNotification object:window];
5166        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeScreen:)
5167            name:NSWindowDidChangeScreenNotification object:window];
5168        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowVisibilityChanged:)
5169            name:NSWindowDidMiniaturizeNotification object:window];
5170        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowVisibilityChanged:)
5171            name:NSWindowDidDeminiaturizeNotification object:window];
5172        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowVisibilityChanged:)
5173            name:@"NSWindowDidOrderOffScreenNotification" object:window];
5174        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowVisibilityChanged:)
5175            name:@"_NSWindowDidBecomeVisible" object:window];
5176    }
5177}
5178
5179- (void)removeWindowObservers
5180{
5181    NSWindow *window = [self window];
5182    if (window) {
5183        [[NSNotificationCenter defaultCenter] removeObserver:self
5184            name:NSWindowDidBecomeKeyNotification object:window];
5185        [[NSNotificationCenter defaultCenter] removeObserver:self
5186            name:NSWindowDidResignKeyNotification object:window];
5187        [[NSNotificationCenter defaultCenter] removeObserver:self
5188            name:WKWindowWillOrderOnScreenNotification() object:window];
5189        [[NSNotificationCenter defaultCenter] removeObserver:self
5190            name:WKWindowWillOrderOffScreenNotification() object:window];
5191        [[NSNotificationCenter defaultCenter] removeObserver:self
5192            name:windowDidChangeBackingPropertiesNotification object:window];
5193        [[NSNotificationCenter defaultCenter] removeObserver:self
5194            name:NSWindowDidChangeScreenNotification object:window];
5195        [[NSNotificationCenter defaultCenter] removeObserver:self
5196            name:NSWindowDidMiniaturizeNotification object:window];
5197        [[NSNotificationCenter defaultCenter] removeObserver:self
5198            name:NSWindowDidDeminiaturizeNotification object:window];
5199        [[NSNotificationCenter defaultCenter] removeObserver:self
5200            name:@"NSWindowDidOrderOffScreenNotification" object:window];
5201        [[NSNotificationCenter defaultCenter] removeObserver:self
5202            name:@"_NSWindowDidBecomeVisible" object:window];
5203    }
5204}
5205
5206- (void)viewWillMoveToWindow:(NSWindow *)window
5207{
5208    // Don't do anything if the WebView isn't initialized.
5209    // This happens when decoding a WebView in a nib.
5210    // FIXME: What sets up the observer of NSWindowWillCloseNotification in this case?
5211    if (!_private || _private->closed)
5212        return;
5213
5214    if ([self window] && [self window] != [self hostWindow])
5215        [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]];
5216
5217    if (window) {
5218        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window];
5219
5220        // Ensure that we will receive the events that WebHTMLView (at least) needs.
5221        // The following are expensive enough that we don't want to call them over
5222        // and over, so do them when we move into a window.
5223        [window setAcceptsMouseMovedEvents:YES];
5224        WKSetNSWindowShouldPostEventNotifications(window, YES);
5225    } else {
5226        _private->page->setCanStartMedia(false);
5227        _private->page->setIsInWindow(false);
5228    }
5229
5230    if (window != [self window]) {
5231        [self removeWindowObservers];
5232        [self addWindowObserversForWindow:window];
5233    }
5234}
5235#endif // !PLATFORM(IOS)
5236
5237- (void)viewDidMoveToWindow
5238{
5239    // Don't do anything if we aren't initialized.  This happens
5240    // when decoding a WebView.  When WebViews are decoded their subviews
5241    // are created by initWithCoder: and so won't be normally
5242    // initialized.  The stub views are discarded by WebView.
5243    if (!_private || _private->closed)
5244        return;
5245
5246    if ([self window]) {
5247        _private->page->setCanStartMedia(true);
5248        _private->page->setIsInWindow(true);
5249
5250#if PLATFORM(IOS)
5251        WebPreferences *preferences = [self preferences];
5252        NSWindow *window = [self window];
5253        [window setTileBordersVisible:[preferences showDebugBorders]];
5254        [window setTilePaintCountsVisible:[preferences showRepaintCounter]];
5255        [window setAcceleratedDrawingEnabled:[preferences acceleratedDrawingEnabled]];
5256#endif
5257    }
5258#if PLATFORM(IOS)
5259    else
5260        [_private->fullscreenController requestHideAndExitFullscreen];
5261#endif
5262
5263#if !PLATFORM(IOS)
5264    _private->page->setDeviceScaleFactor([self _deviceScaleFactor]);
5265#endif
5266
5267    [self _updateActiveState];
5268    [self _updateVisibilityState];
5269}
5270
5271#if !PLATFORM(IOS)
5272- (void)doWindowDidChangeScreen
5273{
5274    if (_private && _private->page)
5275        _private->page->chrome().windowScreenDidChange((PlatformDisplayID)[[[[[self window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
5276}
5277
5278- (void)_windowChangedKeyState
5279{
5280    [self _updateActiveState];
5281    [super _windowChangedKeyState];
5282}
5283
5284- (void)windowKeyStateChanged:(NSNotification *)notification
5285{
5286    [self _updateActiveState];
5287}
5288
5289- (void)viewDidHide
5290{
5291    [self _updateVisibilityState];
5292}
5293
5294- (void)viewDidUnhide
5295{
5296    [self _updateVisibilityState];
5297}
5298
5299- (void)_windowWillOrderOnScreen:(NSNotification *)notification
5300{
5301    if (![self shouldUpdateWhileOffscreen])
5302        [self setNeedsDisplay:YES];
5303
5304    // Send a change screen to make sure the initial displayID is set
5305    [self doWindowDidChangeScreen];
5306
5307    if (_private && _private->page) {
5308        _private->page->resumeScriptedAnimations();
5309        _private->page->setIsVisible(true);
5310    }
5311}
5312
5313- (void)_windowDidChangeScreen:(NSNotification *)notification
5314{
5315    [self doWindowDidChangeScreen];
5316}
5317
5318- (void)_windowWillOrderOffScreen:(NSNotification *)notification
5319{
5320    if (_private && _private->page) {
5321        _private->page->suspendScriptedAnimations();
5322        _private->page->setIsVisible(false);
5323    }
5324}
5325
5326- (void)_windowVisibilityChanged:(NSNotification *)notification
5327{
5328    [self _updateVisibilityState];
5329}
5330
5331- (void)_windowWillClose:(NSNotification *)notification
5332{
5333    if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow])))
5334        [self close];
5335}
5336
5337- (void)_windowDidChangeBackingProperties:(NSNotification *)notification
5338{
5339    CGFloat oldBackingScaleFactor = [[notification.userInfo objectForKey:backingPropertyOldScaleFactorKey] doubleValue];
5340    CGFloat newBackingScaleFactor = [self _deviceScaleFactor];
5341    if (oldBackingScaleFactor == newBackingScaleFactor)
5342        return;
5343
5344    _private->page->setDeviceScaleFactor(newBackingScaleFactor);
5345}
5346#else
5347- (void)_wakWindowScreenScaleChanged:(NSNotification *)notification
5348{
5349    [self _updateScreenScaleFromWindow];
5350}
5351
5352- (void)_wakWindowVisibilityChanged:(NSNotification *)notification
5353{
5354    if ([notification object] == [self window])
5355        [self _updateVisibilityState];
5356}
5357
5358- (void)_updateScreenScaleFromWindow
5359{
5360    float scaleFactor = 1.0f;
5361    if (WAKWindow *window = [self window])
5362        scaleFactor = [window screenScale];
5363    else
5364        scaleFactor = WKGetScreenScaleFactor();
5365
5366    _private->page->setDeviceScaleFactor(scaleFactor);
5367}
5368#endif // PLATFORM(IOS)
5369
5370- (void)setPreferences:(WebPreferences *)prefs
5371{
5372    if (!prefs)
5373        prefs = [WebPreferences standardPreferences];
5374
5375    if (_private->preferences == prefs)
5376        return;
5377
5378    [prefs willAddToWebView];
5379
5380    WebPreferences *oldPrefs = _private->preferences;
5381
5382    [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedInternalNotification object:[self preferences]];
5383    [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]];
5384
5385    _private->preferences = [prefs retain];
5386
5387    // After registering for the notification, post it so the WebCore settings update.
5388    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
5389        name:WebPreferencesChangedInternalNotification object:[self preferences]];
5390    [self _preferencesChanged:[self preferences]];
5391    [[self preferences] _postPreferencesChangedAPINotification];
5392
5393    [oldPrefs didRemoveFromWebView];
5394    [oldPrefs release];
5395}
5396
5397- (WebPreferences *)preferences
5398{
5399    return _private->preferences;
5400}
5401
5402- (void)setPreferencesIdentifier:(NSString *)anIdentifier
5403{
5404    if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) {
5405        WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier];
5406        [self setPreferences:prefs];
5407        [prefs release];
5408    }
5409}
5410
5411- (NSString *)preferencesIdentifier
5412{
5413    return [[self preferences] identifier];
5414}
5415
5416
5417- (void)setUIDelegate:delegate
5418{
5419    _private->UIDelegate = delegate;
5420#if PLATFORM(IOS)
5421    [_private->UIDelegateForwarder clearTarget];
5422#endif
5423    [_private->UIDelegateForwarder release];
5424    _private->UIDelegateForwarder = nil;
5425}
5426
5427- (id)UIDelegate
5428{
5429    return _private->UIDelegate;
5430}
5431
5432#if PLATFORM(IOS)
5433- (id)_resourceLoadDelegateForwarder
5434{
5435    if (_private->closing)
5436        return nil;
5437
5438    if (!_private->resourceProgressDelegateForwarder)
5439        _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:[self resourceLoadDelegate] defaultTarget:[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate]];
5440    return _private->resourceProgressDelegateForwarder;
5441}
5442#endif
5443
5444- (void)setResourceLoadDelegate: delegate
5445{
5446#if PLATFORM(IOS)
5447    [_private->resourceProgressDelegateForwarder clearTarget];
5448    [_private->resourceProgressDelegateForwarder release];
5449    _private->resourceProgressDelegateForwarder = nil;
5450#endif
5451    _private->resourceProgressDelegate = delegate;
5452    [self _cacheResourceLoadDelegateImplementations];
5453}
5454
5455- (id)resourceLoadDelegate
5456{
5457    return _private->resourceProgressDelegate;
5458}
5459
5460- (void)setDownloadDelegate: delegate
5461{
5462    _private->downloadDelegate = delegate;
5463}
5464
5465
5466- (id)downloadDelegate
5467{
5468    return _private->downloadDelegate;
5469}
5470
5471- (void)setPolicyDelegate:delegate
5472{
5473    _private->policyDelegate = delegate;
5474#if PLATFORM(IOS)
5475    [_private->policyDelegateForwarder clearTarget];
5476#endif
5477    [_private->policyDelegateForwarder release];
5478    _private->policyDelegateForwarder = nil;
5479}
5480
5481- (id)policyDelegate
5482{
5483    return _private->policyDelegate;
5484}
5485
5486#if PLATFORM(IOS)
5487- (id)_frameLoadDelegateForwarder
5488{
5489    if (_private->closing)
5490        return nil;
5491
5492    if (!_private->frameLoadDelegateForwarder)
5493        _private->frameLoadDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:[self frameLoadDelegate] defaultTarget:[WebDefaultFrameLoadDelegate sharedFrameLoadDelegate]];
5494    return _private->frameLoadDelegateForwarder;
5495}
5496#endif
5497
5498- (void)setFrameLoadDelegate:delegate
5499{
5500    // <rdar://problem/6950660> - Due to some subtle WebKit changes - presumably to delegate callback behavior - we've
5501    // unconvered a latent bug in at least one WebKit app where the delegate wasn't properly retained by the app and
5502    // was dealloc'ed before being cleared.
5503    // This is an effort to keep such apps working for now.
5504#if !PLATFORM(IOS)
5505    if ([self _needsFrameLoadDelegateRetainQuirk]) {
5506        [delegate retain];
5507        [_private->frameLoadDelegate release];
5508    }
5509#else
5510    [_private->frameLoadDelegateForwarder clearTarget];
5511    [_private->frameLoadDelegateForwarder release];
5512    _private->frameLoadDelegateForwarder = nil;
5513#endif
5514
5515    _private->frameLoadDelegate = delegate;
5516    [self _cacheFrameLoadDelegateImplementations];
5517
5518#if ENABLE(ICONDATABASE)
5519    // If this delegate wants callbacks for icons, fire up the icon database.
5520    if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc)
5521        [WebIconDatabase sharedIconDatabase];
5522#endif
5523}
5524
5525- (id)frameLoadDelegate
5526{
5527    return _private->frameLoadDelegate;
5528}
5529
5530- (WebFrame *)mainFrame
5531{
5532    // This can be called in initialization, before _private has been set up (3465613)
5533    if (!_private || !_private->page)
5534        return nil;
5535    return kit(&_private->page->mainFrame());
5536}
5537
5538- (WebFrame *)selectedFrame
5539{
5540    // If the first responder is a view in our tree, we get the frame containing the first responder.
5541    // This is faster than searching the frame hierarchy, and will give us a result even in the case
5542    // where the focused frame doesn't actually contain a selection.
5543    WebFrame *focusedFrame = [self _focusedFrame];
5544    if (focusedFrame)
5545        return focusedFrame;
5546
5547    // If the first responder is outside of our view tree, we search for a frame containing a selection.
5548    // There should be at most only one of these.
5549    return [[self mainFrame] _findFrameWithSelection];
5550}
5551
5552- (WebBackForwardList *)backForwardList
5553{
5554    if (!_private->page)
5555        return nil;
5556    BackForwardList* list = static_cast<BackForwardList*>(_private->page->backForward().client());
5557    if (!list->enabled())
5558        return nil;
5559    return kit(list);
5560}
5561
5562- (void)setMaintainsBackForwardList:(BOOL)flag
5563{
5564    if (!_private->page)
5565        return;
5566    static_cast<BackForwardList*>(_private->page->backForward().client())->setEnabled(flag);
5567}
5568
5569- (BOOL)goBack
5570{
5571    if (!_private->page)
5572        return NO;
5573
5574#if PLATFORM(IOS)
5575    if (WebThreadIsCurrent() || !WebThreadIsEnabled())
5576#endif
5577    return _private->page->backForward().goBack();
5578#if PLATFORM(IOS)
5579    WebThreadRun(^{
5580        _private->page->backForward().goBack();
5581    });
5582    // FIXME: <rdar://problem/9157572> -[WebView goBack] and -goForward always return YES when called from the main thread
5583    return YES;
5584#endif
5585}
5586
5587- (BOOL)goForward
5588{
5589    if (!_private->page)
5590        return NO;
5591
5592#if PLATFORM(IOS)
5593    if (WebThreadIsCurrent() || !WebThreadIsEnabled())
5594#endif
5595    return _private->page->backForward().goForward();
5596#if PLATFORM(IOS)
5597    WebThreadRun(^{
5598        _private->page->backForward().goForward();
5599    });
5600    // FIXME: <rdar://problem/9157572> -[WebView goBack] and -goForward always return YES when called from the main thread
5601    return YES;
5602#endif
5603}
5604
5605- (BOOL)goToBackForwardItem:(WebHistoryItem *)item
5606{
5607    if (!_private->page)
5608        return NO;
5609
5610    _private->page->goToItem(core(item), FrameLoadType::IndexedBackForward);
5611    return YES;
5612}
5613
5614- (void)setTextSizeMultiplier:(float)m
5615{
5616    [self _setZoomMultiplier:m isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
5617}
5618
5619- (float)textSizeMultiplier
5620{
5621    return [self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f;
5622}
5623
5624- (void)_setZoomMultiplier:(float)multiplier isTextOnly:(BOOL)isTextOnly
5625{
5626    // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>)
5627    _private->zoomMultiplier = multiplier;
5628    _private->zoomsTextOnly = isTextOnly;
5629
5630    // FIXME: It might be nice to rework this code so that _private->zoomMultiplier doesn't exist
5631    // and instead the zoom factors stored in Frame are used.
5632    Frame* coreFrame = [self _mainCoreFrame];
5633    if (coreFrame) {
5634        if (_private->zoomsTextOnly)
5635            coreFrame->setPageAndTextZoomFactors(1, multiplier);
5636        else
5637            coreFrame->setPageAndTextZoomFactors(multiplier, 1);
5638    }
5639}
5640
5641- (float)_zoomMultiplier:(BOOL)isTextOnly
5642{
5643    if (isTextOnly != [self _realZoomMultiplierIsTextOnly])
5644        return 1.0f;
5645    return _private->zoomMultiplier;
5646}
5647
5648- (float)_realZoomMultiplier
5649{
5650    return _private->zoomMultiplier;
5651}
5652
5653- (BOOL)_realZoomMultiplierIsTextOnly
5654{
5655    if (!_private->page)
5656        return NO;
5657
5658    return _private->zoomsTextOnly;
5659}
5660
5661#define MinimumZoomMultiplier       0.5f
5662#define MaximumZoomMultiplier       3.0f
5663#define ZoomMultiplierRatio         1.2f
5664
5665- (BOOL)_canZoomOut:(BOOL)isTextOnly
5666{
5667    id docView = [[[self mainFrame] frameView] documentView];
5668    if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
5669        id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
5670        return [zoomingDocView _canZoomOut];
5671    }
5672    return [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio > MinimumZoomMultiplier;
5673}
5674
5675
5676- (BOOL)_canZoomIn:(BOOL)isTextOnly
5677{
5678    id docView = [[[self mainFrame] frameView] documentView];
5679    if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
5680        id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
5681        return [zoomingDocView _canZoomIn];
5682    }
5683    return [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio < MaximumZoomMultiplier;
5684}
5685
5686- (IBAction)_zoomOut:(id)sender isTextOnly:(BOOL)isTextOnly
5687{
5688    id docView = [[[self mainFrame] frameView] documentView];
5689    if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
5690        id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
5691        return [zoomingDocView _zoomOut:sender];
5692    }
5693    float newScale = [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio;
5694    if (newScale > MinimumZoomMultiplier)
5695        [self _setZoomMultiplier:newScale isTextOnly:isTextOnly];
5696}
5697
5698- (IBAction)_zoomIn:(id)sender isTextOnly:(BOOL)isTextOnly
5699{
5700    id docView = [[[self mainFrame] frameView] documentView];
5701    if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
5702        id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
5703        return [zoomingDocView _zoomIn:sender];
5704    }
5705    float newScale = [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio;
5706    if (newScale < MaximumZoomMultiplier)
5707        [self _setZoomMultiplier:newScale isTextOnly:isTextOnly];
5708}
5709
5710- (BOOL)_canResetZoom:(BOOL)isTextOnly
5711{
5712    id docView = [[[self mainFrame] frameView] documentView];
5713    if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
5714        id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
5715        return [zoomingDocView _canResetZoom];
5716    }
5717    return [self _zoomMultiplier:isTextOnly] != 1.0f;
5718}
5719
5720- (IBAction)_resetZoom:(id)sender isTextOnly:(BOOL)isTextOnly
5721{
5722    id docView = [[[self mainFrame] frameView] documentView];
5723    if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
5724        id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
5725        return [zoomingDocView _resetZoom:sender];
5726    }
5727    if ([self _zoomMultiplier:isTextOnly] != 1.0f)
5728        [self _setZoomMultiplier:1.0f isTextOnly:isTextOnly];
5729}
5730
5731- (void)setApplicationNameForUserAgent:(NSString *)applicationName
5732{
5733    NSString *name = [applicationName copy];
5734    [_private->applicationNameForUserAgent release];
5735    _private->applicationNameForUserAgent = name;
5736    if (!_private->userAgentOverridden)
5737        _private->userAgent = String();
5738}
5739
5740- (NSString *)applicationNameForUserAgent
5741{
5742    return [[_private->applicationNameForUserAgent retain] autorelease];
5743}
5744
5745- (void)setCustomUserAgent:(NSString *)userAgentString
5746{
5747    _private->userAgent = userAgentString;
5748    _private->userAgentOverridden = userAgentString != nil;
5749}
5750
5751- (NSString *)customUserAgent
5752{
5753    if (!_private->userAgentOverridden)
5754        return nil;
5755    return _private->userAgent;
5756}
5757
5758- (void)setMediaStyle:(NSString *)mediaStyle
5759{
5760    if (_private->mediaStyle != mediaStyle) {
5761        [_private->mediaStyle release];
5762        _private->mediaStyle = [mediaStyle copy];
5763    }
5764}
5765
5766- (NSString *)mediaStyle
5767{
5768    return _private->mediaStyle;
5769}
5770
5771- (BOOL)supportsTextEncoding
5772{
5773    id documentView = [[[self mainFrame] frameView] documentView];
5774    return [documentView conformsToProtocol:@protocol(WebDocumentText)]
5775        && [documentView supportsTextEncoding];
5776}
5777
5778- (void)setCustomTextEncodingName:(NSString *)encoding
5779{
5780    NSString *oldEncoding = [self customTextEncodingName];
5781    if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding])
5782        return;
5783    if (Frame* mainFrame = [self _mainCoreFrame])
5784        mainFrame->loader().reloadWithOverrideEncoding(encoding);
5785}
5786
5787- (NSString *)_mainFrameOverrideEncoding
5788{
5789    WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
5790    if (dataSource == nil)
5791        dataSource = [[self mainFrame] _dataSource];
5792    if (dataSource == nil)
5793        return nil;
5794    return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding());
5795}
5796
5797- (NSString *)customTextEncodingName
5798{
5799    return [self _mainFrameOverrideEncoding];
5800}
5801
5802- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
5803{
5804#if !PLATFORM(IOS)
5805    // Return statements are only valid in a function but some applications pass in scripts
5806    // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions
5807    // silently ignored the return. If the application is linked against an earlier version
5808    // of WebKit we will strip the return so the script wont fail.
5809    if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) {
5810        NSRange returnStringRange = [script rangeOfString:@"return "];
5811        if (returnStringRange.length && !returnStringRange.location)
5812            script = [script substringFromIndex:returnStringRange.location + returnStringRange.length];
5813    }
5814#endif
5815
5816    NSString *result = [[self mainFrame] _stringByEvaluatingJavaScriptFromString:script];
5817    // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script
5818    // Since there's no way to get rid of the main frame, result will never ever be nil here.
5819    ASSERT(result);
5820
5821    return result;
5822}
5823
5824- (WebScriptObject *)windowScriptObject
5825{
5826    Frame* coreFrame = [self _mainCoreFrame];
5827    if (!coreFrame)
5828        return nil;
5829    return coreFrame->script().windowScriptObject();
5830}
5831
5832- (String)_userAgentString
5833{
5834    if (_private->userAgent.isNull())
5835        _private->userAgent = [[self class] _standardUserAgentWithApplicationName:_private->applicationNameForUserAgent];
5836
5837    return _private->userAgent;
5838}
5839
5840// Get the appropriate user-agent string for a particular URL.
5841- (NSString *)userAgentForURL:(NSURL *)url
5842{
5843    return [self _userAgentString];
5844}
5845
5846- (void)setHostWindow:(NSWindow *)hostWindow
5847{
5848    if (_private->closed && hostWindow)
5849        return;
5850    if (hostWindow == _private->hostWindow)
5851        return;
5852
5853    Frame* coreFrame = [self _mainCoreFrame];
5854#if !PLATFORM(IOS)
5855    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame))
5856        [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow];
5857    if (_private->hostWindow && [self window] != _private->hostWindow)
5858        [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow];
5859    if (hostWindow)
5860        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow];
5861#endif
5862    [_private->hostWindow release];
5863    _private->hostWindow = [hostWindow retain];
5864    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame))
5865        [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow];
5866#if !PLATFORM(IOS)
5867    _private->page->setDeviceScaleFactor([self _deviceScaleFactor]);
5868#endif
5869}
5870
5871- (NSWindow *)hostWindow
5872{
5873    // -[WebView hostWindow] can sometimes be called from the WebView's [super dealloc] method
5874    // so we check here to make sure it's not null.
5875    if (!_private)
5876        return nil;
5877
5878    return _private->hostWindow;
5879}
5880
5881- (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
5882{
5883    return [[self _frameViewAtWindowPoint:point] documentView];
5884}
5885
5886- (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
5887{
5888    WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
5889    if (!frameView)
5890        return nil;
5891    NSView <WebDocumentView> *documentView = [frameView documentView];
5892    if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
5893        NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
5894        return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
5895    }
5896    return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
5897}
5898
5899- (NSDictionary *)elementAtPoint:(NSPoint)point
5900{
5901    return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
5902}
5903
5904#if ENABLE(DRAG_SUPPORT)
5905// The following 2 internal NSView methods are called on the drag destination to make scrolling while dragging work.
5906// Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination.
5907// When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination.
5908// Forward these calls to the document subview to make its scroll view scroll.
5909- (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
5910{
5911    NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
5912    [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
5913}
5914
5915- (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
5916{
5917    NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
5918    return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
5919}
5920
5921- (DragApplicationFlags)applicationFlags:(id <NSDraggingInfo>)draggingInfo
5922{
5923    uint32_t flags = 0;
5924    if ([NSApp modalWindow])
5925        flags = DragApplicationIsModal;
5926    if ([[self window] attachedSheet])
5927        flags |= DragApplicationHasAttachedSheet;
5928    if ([draggingInfo draggingSource] == self)
5929        flags |= DragApplicationIsSource;
5930    if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
5931        flags |= DragApplicationIsCopyKeyDown;
5932    return static_cast<DragApplicationFlags>(flags);
5933}
5934
5935- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
5936{
5937    IntPoint client([draggingInfo draggingLocation]);
5938    IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
5939    DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
5940    return core(self)->dragController().dragEntered(dragData);
5941}
5942
5943- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
5944{
5945    Page* page = core(self);
5946    if (!page)
5947        return NSDragOperationNone;
5948
5949    IntPoint client([draggingInfo draggingLocation]);
5950    IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
5951    DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
5952    return page->dragController().dragUpdated(dragData);
5953}
5954
5955- (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
5956{
5957    Page* page = core(self);
5958    if (!page)
5959        return;
5960
5961    IntPoint client([draggingInfo draggingLocation]);
5962    IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
5963    DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
5964    page->dragController().dragExited(dragData);
5965}
5966
5967- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
5968{
5969    return YES;
5970}
5971
5972- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
5973{
5974    IntPoint client([draggingInfo draggingLocation]);
5975    IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
5976    DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
5977    return core(self)->dragController().performDragOperation(dragData);
5978}
5979
5980- (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types
5981{
5982    NSView *hitView = [super _hitTest:point dragTypes:types];
5983    if (!hitView && [[self superview] mouse:*point inRect:[self frame]])
5984        return self;
5985    return hitView;
5986}
5987#endif
5988
5989- (BOOL)acceptsFirstResponder
5990{
5991    return [[[self mainFrame] frameView] acceptsFirstResponder];
5992}
5993
5994- (BOOL)becomeFirstResponder
5995{
5996    if (_private->becomingFirstResponder) {
5997        // Fix for unrepro infinite recursion reported in Radar 4448181. If we hit this assert on
5998        // a debug build, we should figure out what causes the problem and do a better fix.
5999        ASSERT_NOT_REACHED();
6000        return NO;
6001    }
6002
6003    // This works together with setNextKeyView to splice the WebView into
6004    // the key loop similar to the way NSScrollView does this. Note that
6005    // WebFrameView has very similar code.
6006#if !PLATFORM(IOS)
6007    NSWindow *window = [self window];
6008#endif
6009    WebFrameView *mainFrameView = [[self mainFrame] frameView];
6010
6011#if !PLATFORM(IOS)
6012    NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming];
6013    BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self);
6014
6015    if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
6016        NSView *previousValidKeyView = [self previousValidKeyView];
6017        if (previousValidKeyView != self && previousValidKeyView != mainFrameView) {
6018            _private->becomingFirstResponder = YES;
6019            _private->becomingFirstResponderFromOutside = fromOutside;
6020            [window makeFirstResponder:previousValidKeyView];
6021            _private->becomingFirstResponderFromOutside = NO;
6022            _private->becomingFirstResponder = NO;
6023            return YES;
6024        }
6025        return NO;
6026    }
6027#endif
6028
6029    if ([mainFrameView acceptsFirstResponder]) {
6030#if !PLATFORM(IOS)
6031        _private->becomingFirstResponder = YES;
6032        _private->becomingFirstResponderFromOutside = fromOutside;
6033        [window makeFirstResponder:mainFrameView];
6034        _private->becomingFirstResponderFromOutside = NO;
6035        _private->becomingFirstResponder = NO;
6036#endif
6037        return YES;
6038    }
6039
6040    return NO;
6041}
6042
6043- (NSView *)_webcore_effectiveFirstResponder
6044{
6045    if (WebFrameView *frameView = [[self mainFrame] frameView])
6046        return [frameView _webcore_effectiveFirstResponder];
6047
6048    return [super _webcore_effectiveFirstResponder];
6049}
6050
6051- (void)setNextKeyView:(NSView *)view
6052{
6053    // This works together with becomeFirstResponder to splice the WebView into
6054    // the key loop similar to the way NSScrollView does this. Note that
6055    // WebFrameView has similar code.
6056    if (WebFrameView *mainFrameView = [[self mainFrame] frameView]) {
6057        [mainFrameView setNextKeyView:view];
6058        return;
6059    }
6060
6061    [super setNextKeyView:view];
6062}
6063
6064static WebFrame *incrementFrame(WebFrame *frame, WebFindOptions options = 0)
6065{
6066    Frame* coreFrame = core(frame);
6067    return kit((options & WebFindOptionsBackwards)
6068        ? coreFrame->tree().traversePreviousWithWrap(options & WebFindOptionsWrapAround)
6069        : coreFrame->tree().traverseNextWithWrap(options & WebFindOptionsWrapAround));
6070}
6071
6072- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
6073{
6074    return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
6075}
6076
6077+ (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
6078{
6079    [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
6080    [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
6081
6082    // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
6083    // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
6084    // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
6085    if ([viewClass class] == [WebHTMLView class])
6086        MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
6087}
6088
6089- (void)setGroupName:(NSString *)groupName
6090{
6091    if (_private->group)
6092        _private->group->removeWebView(self);
6093
6094    _private->group = WebViewGroup::getOrCreate(groupName);
6095    _private->group->addWebView(self);
6096
6097    if (!_private->page)
6098        return;
6099    _private->page->setGroupName(groupName);
6100}
6101
6102- (NSString *)groupName
6103{
6104    if (!_private->page)
6105        return nil;
6106    return _private->page->groupName();
6107}
6108
6109- (double)estimatedProgress
6110{
6111    if (!_private->page)
6112        return 0.0;
6113    return _private->page->progress().estimatedProgress();
6114}
6115
6116#if !PLATFORM(IOS)
6117- (NSArray *)pasteboardTypesForSelection
6118{
6119    NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
6120    if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
6121        return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
6122    }
6123    return [NSArray array];
6124}
6125
6126- (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
6127{
6128    WebFrame *frame = [self _selectedOrMainFrame];
6129    if (frame && [frame _hasSelection]) {
6130        NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
6131        if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)])
6132            [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
6133    }
6134}
6135
6136- (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
6137{
6138    if ([element objectForKey:WebElementImageURLKey] != nil) {
6139        return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
6140    } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
6141        return [NSPasteboard _web_writableTypesForURL];
6142    } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
6143        return [self pasteboardTypesForSelection];
6144    }
6145    return [NSArray array];
6146}
6147
6148- (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
6149{
6150    if ([element objectForKey:WebElementImageURLKey] != nil) {
6151        [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard];
6152    } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
6153        [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
6154    } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
6155        [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
6156    }
6157}
6158
6159- (void)moveDragCaretToPoint:(NSPoint)point
6160{
6161#if ENABLE(DRAG_SUPPORT)
6162    if (Page* page = core(self))
6163        page->dragController().placeDragCaret(IntPoint([self convertPoint:point toView:nil]));
6164#endif
6165}
6166
6167- (void)removeDragCaret
6168{
6169#if ENABLE(DRAG_SUPPORT)
6170    if (Page* page = core(self))
6171        page->dragController().dragEnded();
6172#endif
6173}
6174#endif // !PLATFORM(IOS)
6175
6176- (void)setMainFrameURL:(NSString *)URLString
6177{
6178    NSURL *url;
6179    if ([URLString hasPrefix:@"/"])
6180        url = [NSURL fileURLWithPath:URLString];
6181    else
6182        url = [NSURL _web_URLWithDataAsString:URLString];
6183
6184    [[self mainFrame] loadRequest:[NSURLRequest requestWithURL:url]];
6185}
6186
6187- (NSString *)mainFrameURL
6188{
6189    WebDataSource *ds;
6190    ds = [[self mainFrame] provisionalDataSource];
6191    if (!ds)
6192        ds = [[self mainFrame] _dataSource];
6193    return [[[ds request] URL] _web_originalDataAsString];
6194}
6195
6196- (BOOL)isLoading
6197{
6198    LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
6199    return [self _isLoading];
6200}
6201
6202- (NSString *)mainFrameTitle
6203{
6204    NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle];
6205    return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
6206}
6207
6208#if !PLATFORM(IOS)
6209- (NSImage *)mainFrameIcon
6210{
6211    return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
6212}
6213#else
6214- (NSURL *)mainFrameIconURL
6215{
6216    WebFrame *mainFrame = [self mainFrame];
6217    Frame *coreMainFrame = core(mainFrame);
6218    if (!coreMainFrame)
6219        return nil;
6220
6221    NSURL *url = (NSURL *)coreMainFrame->loader().icon().url();
6222    return url;
6223}
6224#endif
6225
6226- (DOMDocument *)mainFrameDocument
6227{
6228    // only return the actual value if the state we're in gives NSTreeController
6229    // enough time to release its observers on the old model
6230    if (_private->mainFrameDocumentReady)
6231        return [[self mainFrame] DOMDocument];
6232    return nil;
6233}
6234
6235- (void)setDrawsBackground:(BOOL)drawsBackground
6236{
6237    if (_private->drawsBackground == drawsBackground)
6238        return;
6239    _private->drawsBackground = drawsBackground;
6240    [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
6241}
6242
6243- (BOOL)drawsBackground
6244{
6245    // This method can be called beneath -[NSView dealloc] after we have cleared _private,
6246    // indirectly via -[WebFrameView viewDidMoveToWindow].
6247    return !_private || _private->drawsBackground;
6248}
6249
6250- (void)setShouldUpdateWhileOffscreen:(BOOL)updateWhileOffscreen
6251{
6252    if (_private->shouldUpdateWhileOffscreen == updateWhileOffscreen)
6253        return;
6254    _private->shouldUpdateWhileOffscreen = updateWhileOffscreen;
6255    [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
6256}
6257
6258- (BOOL)shouldUpdateWhileOffscreen
6259{
6260    return _private->shouldUpdateWhileOffscreen;
6261}
6262
6263- (void)setCurrentNodeHighlight:(WebNodeHighlight *)nodeHighlight
6264{
6265    id old = _private->currentNodeHighlight;
6266    _private->currentNodeHighlight = [nodeHighlight retain];
6267    [old release];
6268}
6269
6270- (WebNodeHighlight *)currentNodeHighlight
6271{
6272    return _private->currentNodeHighlight;
6273}
6274
6275- (NSView *)previousValidKeyView
6276{
6277    NSView *result = [super previousValidKeyView];
6278
6279    // Work around AppKit bug 6905484. If the result is a view that's inside this one, it's
6280    // possible it is the wrong answer, because the fact that it's a descendant causes the
6281    // code that implements key view redirection to fail; this means we won't redirect to
6282    // the toolbar, for example, when we hit the edge of a window. Since the bug is specific
6283    // to cases where the receiver of previousValidKeyView is an ancestor of the last valid
6284    // key view in the loop, we can sidestep it by walking along previous key views until
6285    // we find one that is not a superview, then using that to call previousValidKeyView.
6286
6287    if (![result isDescendantOf:self])
6288        return result;
6289
6290    // Use a visited set so we don't loop indefinitely when walking crazy key loops.
6291    // AppKit uses such sets internally and we want our loop to be as robust as its loops.
6292    RetainPtr<CFMutableSetRef> visitedViews = adoptCF(CFSetCreateMutable(0, 0, 0));
6293    CFSetAddValue(visitedViews.get(), result);
6294
6295    NSView *previousView = self;
6296    do {
6297        CFSetAddValue(visitedViews.get(), previousView);
6298        previousView = [previousView previousKeyView];
6299        if (!previousView || CFSetGetValue(visitedViews.get(), previousView))
6300            return result;
6301    } while ([result isDescendantOf:previousView]);
6302    return [previousView previousValidKeyView];
6303}
6304
6305@end
6306
6307@implementation WebView (WebIBActions)
6308
6309- (IBAction)takeStringURLFrom: sender
6310{
6311    NSString *URLString = [sender stringValue];
6312
6313    [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
6314}
6315
6316- (BOOL)canGoBack
6317{
6318#if PLATFORM(IOS)
6319    WebThreadLock();
6320    if (!_private->page)
6321#else
6322    if (!_private->page || _private->page->defersLoading())
6323#endif
6324        return NO;
6325
6326    return _private->page->backForward().canGoBackOrForward(-1);
6327}
6328
6329- (BOOL)canGoForward
6330{
6331#if PLATFORM(IOS)
6332    WebThreadLock();
6333    if (!_private->page)
6334#else
6335    if (!_private->page || _private->page->defersLoading())
6336#endif
6337        return NO;
6338
6339    return !!_private->page->backForward().canGoBackOrForward(1);
6340}
6341
6342- (IBAction)goBack:(id)sender
6343{
6344    [self goBack];
6345}
6346
6347- (IBAction)goForward:(id)sender
6348{
6349    [self goForward];
6350}
6351
6352- (IBAction)stopLoading:(id)sender
6353{
6354#if PLATFORM(IOS)
6355    if (WebThreadNotCurrent()) {
6356        _private->isStopping = true;
6357        WebThreadSetShouldYield();
6358    }
6359    WebThreadRun(^{
6360        _private->isStopping = false;
6361#endif
6362    [[self mainFrame] stopLoading];
6363#if PLATFORM(IOS)
6364    });
6365#endif
6366}
6367
6368#if PLATFORM(IOS)
6369- (void)stopLoadingAndClear
6370{
6371    if (WebThreadNotCurrent() && !WebThreadIsLocked()) {
6372        _private->isStopping = true;
6373        WebThreadSetShouldYield();
6374    }
6375    WebThreadRun(^{
6376        _private->isStopping = false;
6377
6378        WebFrame *frame = [self mainFrame];
6379        [frame stopLoading];
6380        core(frame)->document()->loader()->writer().end(); // End to finish parsing and display immediately
6381
6382        WebFrameView *mainFrameView = [frame frameView];
6383        float scale = [[mainFrameView documentView] scale];
6384        WebPlainWhiteView *plainWhiteView = [[WebPlainWhiteView alloc] initWithFrame:NSZeroRect];
6385        [plainWhiteView setScale:scale];
6386        [plainWhiteView setFrame:[mainFrameView bounds]];
6387        [mainFrameView _setDocumentView:plainWhiteView];
6388        [plainWhiteView setNeedsDisplay:YES];
6389        [plainWhiteView release];
6390    });
6391}
6392#endif
6393
6394- (IBAction)reload:(id)sender
6395{
6396#if PLATFORM(IOS)
6397    WebThreadRun(^{
6398#endif
6399    [[self mainFrame] reload];
6400#if PLATFORM(IOS)
6401    });
6402#endif
6403}
6404
6405- (IBAction)reloadFromOrigin:(id)sender
6406{
6407    [[self mainFrame] reloadFromOrigin];
6408}
6409
6410// FIXME: This code should move into WebCore so that it is not duplicated in each WebKit.
6411// (This includes canMakeTextSmaller/Larger, makeTextSmaller/Larger, and canMakeTextStandardSize/makeTextStandardSize)
6412- (BOOL)canMakeTextSmaller
6413{
6414    return [self _canZoomOut:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
6415}
6416
6417- (IBAction)makeTextSmaller:(id)sender
6418{
6419    return [self _zoomOut:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
6420}
6421
6422- (BOOL)canMakeTextLarger
6423{
6424    return [self _canZoomIn:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
6425}
6426
6427- (IBAction)makeTextLarger:(id)sender
6428{
6429    return [self _zoomIn:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
6430}
6431
6432- (BOOL)canMakeTextStandardSize
6433{
6434    return [self _canResetZoom:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
6435}
6436
6437- (IBAction)makeTextStandardSize:(id)sender
6438{
6439   return [self _resetZoom:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
6440}
6441
6442#if !PLATFORM(IOS)
6443- (IBAction)toggleSmartInsertDelete:(id)sender
6444{
6445    [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
6446}
6447
6448- (IBAction)toggleContinuousSpellChecking:(id)sender
6449{
6450    [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
6451}
6452
6453- (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
6454{
6455    id responder = [self _responderForResponderOperations];
6456    if (responder != self && [responder respondsToSelector:[item action]]) {
6457        if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)])
6458            return [responder validateUserInterfaceItemWithoutDelegate:item];
6459        if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)])
6460            return [responder validateUserInterfaceItem:item];
6461        return YES;
6462    }
6463    return NO;
6464}
6465
6466#define VALIDATE(name) \
6467    else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
6468
6469- (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
6470{
6471    SEL action = [item action];
6472
6473    if (action == @selector(goBack:)) {
6474        return [self canGoBack];
6475    } else if (action == @selector(goForward:)) {
6476        return [self canGoForward];
6477    } else if (action == @selector(makeTextLarger:)) {
6478        return [self canMakeTextLarger];
6479    } else if (action == @selector(makeTextSmaller:)) {
6480        return [self canMakeTextSmaller];
6481    } else if (action == @selector(makeTextStandardSize:)) {
6482        return [self canMakeTextStandardSize];
6483    } else if (action == @selector(reload:)) {
6484        return [[self mainFrame] _dataSource] != nil;
6485    } else if (action == @selector(stopLoading:)) {
6486        return [self _isLoading];
6487    } else if (action == @selector(toggleContinuousSpellChecking:)) {
6488        BOOL checkMark = NO;
6489        BOOL retVal = NO;
6490        if ([self _continuousCheckingAllowed]) {
6491            checkMark = [self isContinuousSpellCheckingEnabled];
6492            retVal = YES;
6493        }
6494        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6495            NSMenuItem *menuItem = (NSMenuItem *)item;
6496            [menuItem setState:checkMark ? NSOnState : NSOffState];
6497        }
6498        return retVal;
6499    } else if (action == @selector(toggleSmartInsertDelete:)) {
6500        BOOL checkMark = [self smartInsertDeleteEnabled];
6501        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6502            NSMenuItem *menuItem = (NSMenuItem *)item;
6503            [menuItem setState:checkMark ? NSOnState : NSOffState];
6504        }
6505        return YES;
6506    } else if (action == @selector(toggleGrammarChecking:)) {
6507        BOOL checkMark = [self isGrammarCheckingEnabled];
6508        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6509            NSMenuItem *menuItem = (NSMenuItem *)item;
6510            [menuItem setState:checkMark ? NSOnState : NSOffState];
6511        }
6512        return YES;
6513    } else if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
6514        BOOL checkMark = [self isAutomaticQuoteSubstitutionEnabled];
6515        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6516            NSMenuItem *menuItem = (NSMenuItem *)item;
6517            [menuItem setState:checkMark ? NSOnState : NSOffState];
6518        }
6519        return YES;
6520    } else if (action == @selector(toggleAutomaticLinkDetection:)) {
6521        BOOL checkMark = [self isAutomaticLinkDetectionEnabled];
6522        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6523            NSMenuItem *menuItem = (NSMenuItem *)item;
6524            [menuItem setState:checkMark ? NSOnState : NSOffState];
6525        }
6526        return YES;
6527    } else if (action == @selector(toggleAutomaticDashSubstitution:)) {
6528        BOOL checkMark = [self isAutomaticDashSubstitutionEnabled];
6529        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6530            NSMenuItem *menuItem = (NSMenuItem *)item;
6531            [menuItem setState:checkMark ? NSOnState : NSOffState];
6532        }
6533        return YES;
6534    } else if (action == @selector(toggleAutomaticTextReplacement:)) {
6535        BOOL checkMark = [self isAutomaticTextReplacementEnabled];
6536        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6537            NSMenuItem *menuItem = (NSMenuItem *)item;
6538            [menuItem setState:checkMark ? NSOnState : NSOffState];
6539        }
6540        return YES;
6541    } else if (action == @selector(toggleAutomaticSpellingCorrection:)) {
6542        BOOL checkMark = [self isAutomaticSpellingCorrectionEnabled];
6543        if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
6544            NSMenuItem *menuItem = (NSMenuItem *)item;
6545            [menuItem setState:checkMark ? NSOnState : NSOffState];
6546        }
6547        return YES;
6548    }
6549    FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
6550
6551    return YES;
6552}
6553
6554- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
6555{
6556    BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
6557    return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
6558}
6559#endif // !PLATFORM(IOS)
6560
6561@end
6562
6563@implementation WebView (WebPendingPublic)
6564
6565#if !PLATFORM(IOS)
6566- (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode
6567{
6568#if USE(CFNETWORK)
6569    CFRunLoopRef schedulePairRunLoop = [runLoop getCFRunLoop];
6570#else
6571    NSRunLoop *schedulePairRunLoop = runLoop;
6572#endif
6573    if (runLoop && mode)
6574        core(self)->addSchedulePair(SchedulePair::create(schedulePairRunLoop, (CFStringRef)mode));
6575}
6576
6577- (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode
6578{
6579#if USE(CFNETWORK)
6580    CFRunLoopRef schedulePairRunLoop = [runLoop getCFRunLoop];
6581#else
6582    NSRunLoop *schedulePairRunLoop = runLoop;
6583#endif
6584    if (runLoop && mode)
6585        core(self)->removeSchedulePair(SchedulePair::create(schedulePairRunLoop, (CFStringRef)mode));
6586}
6587#endif
6588
6589static BOOL findString(NSView <WebDocumentSearching> *searchView, NSString *string, WebFindOptions options)
6590{
6591    if ([searchView conformsToProtocol:@protocol(WebDocumentOptionsSearching)])
6592        return [(NSView <WebDocumentOptionsSearching> *)searchView _findString:string options:options];
6593    if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
6594        return [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:!(options & WebFindOptionsBackwards) caseSensitive:!(options & WebFindOptionsCaseInsensitive) wrap:!!(options & WebFindOptionsWrapAround) startInSelection:!!(options & WebFindOptionsStartInSelection)];
6595    return [searchView searchFor:string direction:!(options & WebFindOptionsBackwards) caseSensitive:!(options & WebFindOptionsCaseInsensitive) wrap:!!(options & WebFindOptionsWrapAround)];
6596}
6597
6598- (BOOL)findString:(NSString *)string options:(WebFindOptions)options
6599{
6600    if (_private->closed)
6601        return NO;
6602
6603    // Get the frame holding the selection, or start with the main frame
6604    WebFrame *startFrame = [self _selectedOrMainFrame];
6605
6606    // Search the first frame, then all the other frames, in order
6607    NSView <WebDocumentSearching> *startSearchView = nil;
6608    WebFrame *frame = startFrame;
6609    do {
6610        WebFrame *nextFrame = incrementFrame(frame, options);
6611
6612        BOOL onlyOneFrame = (frame == nextFrame);
6613        ASSERT(!onlyOneFrame || frame == startFrame);
6614
6615        id <WebDocumentView> view = [[frame frameView] documentView];
6616        if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
6617            NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
6618
6619            if (frame == startFrame)
6620                startSearchView = searchView;
6621
6622            // In some cases we have to search some content twice; see comment later in this method.
6623            // We can avoid ever doing this in the common one-frame case by passing the wrap option through
6624            // here, and then bailing out before we get to the code that would search again in the
6625            // same content.
6626            WebFindOptions optionsForThisPass = onlyOneFrame ? options : (options & ~WebFindOptionsWrapAround);
6627
6628            if (findString(searchView, string, optionsForThisPass)) {
6629                if (frame != startFrame)
6630                    [startFrame _clearSelection];
6631                [[self window] makeFirstResponder:searchView];
6632                return YES;
6633            }
6634
6635            if (onlyOneFrame)
6636                return NO;
6637        }
6638        frame = nextFrame;
6639    } while (frame && frame != startFrame);
6640
6641    // 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
6642    // 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
6643    // way to make sure the entire frame is searched is to pass WebFindOptionsWrapAround. When there are no matches, this will search
6644    // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice.
6645    // To fix this, we'd need to add a mechanism to specify a range in which to search.
6646    if ((options & WebFindOptionsWrapAround) && startSearchView) {
6647        if (findString(startSearchView, string, options)) {
6648            [[self window] makeFirstResponder:startSearchView];
6649            return YES;
6650        }
6651    }
6652    return NO;
6653}
6654
6655- (DOMRange *)DOMRangeOfString:(NSString *)string relativeTo:(DOMRange *)previousRange options:(WebFindOptions)options
6656{
6657    if (!_private->page)
6658        return nil;
6659
6660    return kit(_private->page->rangeOfString(string, core(previousRange), coreOptions(options)).get());
6661}
6662
6663- (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady
6664{
6665    // by setting this to NO, calls to mainFrameDocument are forced to return nil
6666    // setting this to YES lets it return the actual DOMDocument value
6667    // we use this to tell NSTreeController to reset its observers and clear its state
6668    if (_private->mainFrameDocumentReady == mainFrameDocumentReady)
6669        return;
6670#if !PLATFORM(IOS)
6671    [self _willChangeValueForKey:_WebMainFrameDocumentKey];
6672    _private->mainFrameDocumentReady = mainFrameDocumentReady;
6673    [self _didChangeValueForKey:_WebMainFrameDocumentKey];
6674    // this will cause observers to call mainFrameDocument where this flag will be checked
6675#endif
6676}
6677
6678- (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements
6679{
6680    _private->tabKeyCyclesThroughElementsChanged = YES;
6681    if (_private->page)
6682        _private->page->setTabKeyCyclesThroughElements(cyclesElements);
6683}
6684
6685- (BOOL)tabKeyCyclesThroughElements
6686{
6687    return _private->page && _private->page->tabKeyCyclesThroughElements();
6688}
6689
6690- (void)setScriptDebugDelegate:(id)delegate
6691{
6692    _private->scriptDebugDelegate = delegate;
6693    [self _cacheScriptDebugDelegateImplementations];
6694
6695    if (delegate)
6696        [self _attachScriptDebuggerToAllFrames];
6697    else
6698        [self _detachScriptDebuggerFromAllFrames];
6699}
6700
6701- (id)scriptDebugDelegate
6702{
6703    return _private->scriptDebugDelegate;
6704}
6705
6706- (void)setHistoryDelegate:(id)delegate
6707{
6708    _private->historyDelegate = delegate;
6709    [self _cacheHistoryDelegateImplementations];
6710}
6711
6712- (id)historyDelegate
6713{
6714    return _private->historyDelegate;
6715}
6716
6717- (BOOL)shouldClose
6718{
6719    Frame* coreFrame = [self _mainCoreFrame];
6720    if (!coreFrame)
6721        return YES;
6722    return coreFrame->loader().shouldClose();
6723}
6724
6725#if !PLATFORM(IOS)
6726static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSC::JSValue jsValue)
6727{
6728    NSAppleEventDescriptor* aeDesc = 0;
6729    if (jsValue.isBoolean())
6730        return [NSAppleEventDescriptor descriptorWithBoolean:jsValue.asBoolean()];
6731    if (jsValue.isString())
6732        return [NSAppleEventDescriptor descriptorWithString:jsValue.getString(exec)];
6733    if (jsValue.isNumber()) {
6734        double value = jsValue.asNumber();
6735        int intValue = value;
6736        if (value == intValue)
6737            return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)];
6738        return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)];
6739    }
6740    if (jsValue.isObject()) {
6741        JSObject* object = jsValue.getObject();
6742        if (object->inherits(DateInstance::info())) {
6743            DateInstance* date = static_cast<DateInstance*>(object);
6744            double ms = date->internalNumber();
6745            if (!std::isnan(ms)) {
6746                CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970;
6747                LongDateTime ldt;
6748                if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt))
6749                    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)];
6750            }
6751        }
6752        else if (object->inherits(JSArray::info())) {
6753            DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<JSObject*>, visitedElems, ());
6754            if (!visitedElems.contains(object)) {
6755                visitedElems.add(object);
6756
6757                JSArray* array = static_cast<JSArray*>(object);
6758                aeDesc = [NSAppleEventDescriptor listDescriptor];
6759                unsigned numItems = array->length();
6760                for (unsigned i = 0; i < numItems; ++i)
6761                    [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->get(exec, i)) atIndex:0];
6762
6763                visitedElems.remove(object);
6764                return aeDesc;
6765            }
6766        }
6767        JSC::JSValue primitive = object->toPrimitive(exec);
6768        if (exec->hadException()) {
6769            exec->clearException();
6770            return [NSAppleEventDescriptor nullDescriptor];
6771        }
6772        return aeDescFromJSValue(exec, primitive);
6773    }
6774    if (jsValue.isUndefined())
6775        return [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue];
6776    ASSERT(jsValue.isNull());
6777    return [NSAppleEventDescriptor nullDescriptor];
6778}
6779
6780- (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
6781{
6782    Frame* coreFrame = [self _mainCoreFrame];
6783    if (!coreFrame)
6784        return nil;
6785    if (!coreFrame->document())
6786        return nil;
6787    JSC::JSValue result = coreFrame->script().executeScript(script, true).jsValue();
6788    if (!result) // FIXME: pass errors
6789        return 0;
6790    JSLockHolder lock(coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
6791    return aeDescFromJSValue(coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec(), result);
6792}
6793#endif
6794
6795- (BOOL)canMarkAllTextMatches
6796{
6797    if (_private->closed)
6798        return NO;
6799
6800    WebFrame *frame = [self mainFrame];
6801    do {
6802        id <WebDocumentView> view = [[frame frameView] documentView];
6803        if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)])
6804            return NO;
6805
6806        frame = incrementFrame(frame);
6807    } while (frame);
6808
6809    return YES;
6810}
6811
6812- (NSUInteger)countMatchesForText:(NSString *)string options:(WebFindOptions)options highlight:(BOOL)highlight limit:(NSUInteger)limit markMatches:(BOOL)markMatches
6813{
6814    return [self countMatchesForText:string inDOMRange:nil options:options highlight:highlight limit:limit markMatches:markMatches];
6815}
6816
6817- (NSUInteger)countMatchesForText:(NSString *)string inDOMRange:(DOMRange *)range options:(WebFindOptions)options highlight:(BOOL)highlight limit:(NSUInteger)limit markMatches:(BOOL)markMatches
6818{
6819    if (_private->closed)
6820        return 0;
6821
6822    WebFrame *frame = [self mainFrame];
6823    unsigned matchCount = 0;
6824    do {
6825        id <WebDocumentView> view = [[frame frameView] documentView];
6826        if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
6827            if (markMatches)
6828                [(NSView <WebMultipleTextMatches>*)view setMarkedTextMatchesAreHighlighted:highlight];
6829
6830            ASSERT(limit == 0 || matchCount < limit);
6831            matchCount += [(NSView <WebMultipleTextMatches>*)view countMatchesForText:string inDOMRange:range options:options limit:(limit == 0 ? 0 : limit - matchCount) markMatches:markMatches];
6832
6833            // Stop looking if we've reached the limit. A limit of 0 means no limit.
6834            if (limit > 0 && matchCount >= limit)
6835                break;
6836        }
6837
6838        frame = incrementFrame(frame);
6839    } while (frame);
6840
6841    return matchCount;
6842}
6843
6844- (void)unmarkAllTextMatches
6845{
6846    if (_private->closed)
6847        return;
6848
6849    WebFrame *frame = [self mainFrame];
6850    do {
6851        id <WebDocumentView> view = [[frame frameView] documentView];
6852        if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)])
6853            [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches];
6854
6855        frame = incrementFrame(frame);
6856    } while (frame);
6857}
6858
6859- (NSArray *)rectsForTextMatches
6860{
6861    if (_private->closed)
6862        return [NSArray array];
6863
6864    NSMutableArray *result = [NSMutableArray array];
6865    WebFrame *frame = [self mainFrame];
6866    do {
6867        id <WebDocumentView> view = [[frame frameView] documentView];
6868        if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
6869            NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view;
6870            NSRect documentViewVisibleRect = [documentView visibleRect];
6871            NSArray *originalRects = [documentView rectsForTextMatches];
6872            unsigned rectCount = [originalRects count];
6873            unsigned rectIndex;
6874            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6875            for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
6876                NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue];
6877                // Clip rect to document view's visible rect so rect is confined to subframe
6878                r = NSIntersectionRect(r, documentViewVisibleRect);
6879                if (NSIsEmptyRect(r))
6880                    continue;
6881
6882                // Convert rect to our coordinate system
6883                r = [documentView convertRect:r toView:self];
6884                [result addObject:[NSValue valueWithRect:r]];
6885                if (rectIndex % 10 == 0) {
6886                    [pool drain];
6887                    pool = [[NSAutoreleasePool alloc] init];
6888                }
6889            }
6890            [pool drain];
6891        }
6892
6893        frame = incrementFrame(frame);
6894    } while (frame);
6895
6896    return result;
6897}
6898
6899- (void)scrollDOMRangeToVisible:(DOMRange *)range
6900{
6901    [[[[range startContainer] ownerDocument] webFrame] _scrollDOMRangeToVisible:range];
6902}
6903
6904#if PLATFORM(IOS)
6905- (void)scrollDOMRangeToVisible:(DOMRange *)range withInset:(CGFloat)inset
6906{
6907    [[[[range startContainer] ownerDocument] webFrame] _scrollDOMRangeToVisible:range withInset:inset];
6908}
6909#endif
6910
6911- (BOOL)allowsUndo
6912{
6913    return _private->allowsUndo;
6914}
6915
6916- (void)setAllowsUndo:(BOOL)flag
6917{
6918    _private->allowsUndo = flag;
6919}
6920
6921- (void)setPageSizeMultiplier:(float)m
6922{
6923    [self _setZoomMultiplier:m isTextOnly:NO];
6924}
6925
6926- (float)pageSizeMultiplier
6927{
6928    return ![self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f;
6929}
6930
6931- (BOOL)canZoomPageIn
6932{
6933    return [self _canZoomIn:NO];
6934}
6935
6936- (IBAction)zoomPageIn:(id)sender
6937{
6938    return [self _zoomIn:sender isTextOnly:NO];
6939}
6940
6941- (BOOL)canZoomPageOut
6942{
6943    return [self _canZoomOut:NO];
6944}
6945
6946- (IBAction)zoomPageOut:(id)sender
6947{
6948    return [self _zoomOut:sender isTextOnly:NO];
6949}
6950
6951- (BOOL)canResetPageZoom
6952{
6953    return [self _canResetZoom:NO];
6954}
6955
6956- (IBAction)resetPageZoom:(id)sender
6957{
6958    return [self _resetZoom:sender isTextOnly:NO];
6959}
6960
6961- (void)setMediaVolume:(float)volume
6962{
6963    if (_private->page)
6964        _private->page->setMediaVolume(volume);
6965}
6966
6967- (float)mediaVolume
6968{
6969    if (!_private->page)
6970        return 0;
6971
6972    return _private->page->mediaVolume();
6973}
6974
6975- (void)addVisitedLinks:(NSArray *)visitedLinks
6976{
6977    PageGroup& group = core(self)->group();
6978
6979    NSEnumerator *enumerator = [visitedLinks objectEnumerator];
6980    while (NSString *url = [enumerator nextObject]) {
6981        size_t length = [url length];
6982        const UChar* characters = CFStringGetCharactersPtr(reinterpret_cast<CFStringRef>(url));
6983        if (characters)
6984            group.addVisitedLink(characters, length);
6985        else {
6986            Vector<UChar, 512> buffer(length);
6987            [url getCharacters:buffer.data()];
6988            group.addVisitedLink(buffer.data(), length);
6989        }
6990    }
6991}
6992
6993#if PLATFORM(IOS)
6994- (void)removeVisitedLink:(NSURL *)url
6995{
6996    core(self)->group().removeVisitedLink(url);
6997}
6998#endif
6999
7000@end
7001
7002#if !PLATFORM(IOS)
7003@implementation WebView (WebViewPrintingPrivate)
7004
7005- (float)_headerHeight
7006{
7007    return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:));
7008}
7009
7010- (float)_footerHeight
7011{
7012    return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:));
7013}
7014
7015- (void)_drawHeaderInRect:(NSRect)rect
7016{
7017#ifdef DEBUG_HEADER_AND_FOOTER
7018    NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
7019    [currentContext saveGraphicsState];
7020    [[NSColor yellowColor] set];
7021    NSRectFill(rect);
7022    [currentContext restoreGraphicsState];
7023#endif
7024
7025    SEL selector = @selector(webView:drawHeaderInRect:);
7026    if (![_private->UIDelegate respondsToSelector:selector])
7027        return;
7028
7029    NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
7030    [currentContext saveGraphicsState];
7031
7032    NSRectClip(rect);
7033    CallUIDelegate(self, selector, rect);
7034
7035    [currentContext restoreGraphicsState];
7036}
7037
7038- (void)_drawFooterInRect:(NSRect)rect
7039{
7040#ifdef DEBUG_HEADER_AND_FOOTER
7041    NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
7042    [currentContext saveGraphicsState];
7043    [[NSColor cyanColor] set];
7044    NSRectFill(rect);
7045    [currentContext restoreGraphicsState];
7046#endif
7047
7048    SEL selector = @selector(webView:drawFooterInRect:);
7049    if (![_private->UIDelegate respondsToSelector:selector])
7050        return;
7051
7052    NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
7053    [currentContext saveGraphicsState];
7054
7055    NSRectClip(rect);
7056    CallUIDelegate(self, selector, rect);
7057
7058    [currentContext restoreGraphicsState];
7059}
7060
7061- (void)_adjustPrintingMarginsForHeaderAndFooter
7062{
7063    NSPrintOperation *op = [NSPrintOperation currentOperation];
7064    NSPrintInfo *info = [op printInfo];
7065    NSMutableDictionary *infoDictionary = [info dictionary];
7066
7067    // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the
7068    // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087),
7069    // we stash away the unmodified top and bottom margins the first time this method is called, and we read from
7070    // those stashed-away values on subsequent calls.
7071    float originalTopMargin;
7072    float originalBottomMargin;
7073    NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey];
7074    if (!originalTopMarginNumber) {
7075        ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]);
7076        originalTopMargin = [info topMargin];
7077        originalBottomMargin = [info bottomMargin];
7078        [infoDictionary setObject:[NSNumber numberWithFloat:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey];
7079        [infoDictionary setObject:[NSNumber numberWithFloat:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey];
7080    } else {
7081        ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]);
7082        ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]);
7083        originalTopMargin = [originalTopMarginNumber floatValue];
7084        originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] floatValue];
7085    }
7086
7087    float scale = [op _web_pageSetupScaleFactor];
7088    [info setTopMargin:originalTopMargin + [self _headerHeight] * scale];
7089    [info setBottomMargin:originalBottomMargin + [self _footerHeight] * scale];
7090}
7091
7092- (void)_drawHeaderAndFooter
7093{
7094    // The header and footer rect height scales with the page, but the width is always
7095    // all the way across the printed page (inset by printing margins).
7096    NSPrintOperation *op = [NSPrintOperation currentOperation];
7097    float scale = [op _web_pageSetupScaleFactor];
7098    NSPrintInfo *printInfo = [op printInfo];
7099    NSSize paperSize = [printInfo paperSize];
7100    float headerFooterLeft = [printInfo leftMargin]/scale;
7101    float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
7102    NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] ,
7103                                   headerFooterWidth, [self _footerHeight]);
7104    NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale,
7105                                   headerFooterWidth, [self _headerHeight]);
7106
7107    [self _drawHeaderInRect:headerRect];
7108    [self _drawFooterInRect:footerRect];
7109}
7110@end
7111
7112@implementation WebView (WebDebugBinding)
7113
7114- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
7115{
7116    LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
7117    [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
7118}
7119
7120- (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
7121{
7122    LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
7123    [super removeObserver:anObserver forKeyPath:keyPath];
7124}
7125
7126@end
7127
7128#endif // !PLATFORM(IOS)
7129
7130//==========================================================================================
7131// Editing
7132
7133@implementation WebView (WebViewCSS)
7134
7135- (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
7136{
7137    // FIXME: is this the best level for this conversion?
7138    if (pseudoElement == nil)
7139        pseudoElement = @"";
7140
7141    return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement];
7142}
7143
7144@end
7145
7146@implementation WebView (WebViewEditing)
7147
7148- (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
7149{
7150    Page* page = core(self);
7151    if (!page)
7152        return nil;
7153    return kit(page->mainFrame().editor().rangeForPoint(IntPoint([self convertPoint:point toView:nil])).get());
7154}
7155
7156- (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag
7157{
7158#if !PLATFORM(IOS)
7159    // 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
7160    if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"])
7161        return YES;
7162#endif
7163    return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag];
7164}
7165
7166- (BOOL)maintainsInactiveSelection
7167{
7168    return NO;
7169}
7170
7171- (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
7172{
7173    Frame* coreFrame = core([self _selectedOrMainFrame]);
7174    if (!coreFrame)
7175        return;
7176
7177    if (range == nil)
7178        coreFrame->selection().clear();
7179    else {
7180        // Derive the frame to use from the range passed in.
7181        // Using _selectedOrMainFrame could give us a different document than
7182        // the one the range uses.
7183        coreFrame = core([range startContainer])->document().frame();
7184        if (!coreFrame)
7185            return;
7186
7187        coreFrame->selection().setSelectedRange(core(range), core(selectionAffinity), true);
7188    }
7189}
7190
7191- (DOMRange *)selectedDOMRange
7192{
7193    Frame* coreFrame = core([self _selectedOrMainFrame]);
7194    if (!coreFrame)
7195        return nil;
7196    return kit(coreFrame->selection().toNormalizedRange().get());
7197}
7198
7199- (NSSelectionAffinity)selectionAffinity
7200{
7201    Frame* coreFrame = core([self _selectedOrMainFrame]);
7202    if (!coreFrame)
7203        return NSSelectionAffinityDownstream;
7204    return kit(coreFrame->selection().selection().affinity());
7205}
7206
7207- (void)setEditable:(BOOL)flag
7208{
7209    if ([self isEditable] != flag && _private->page) {
7210        _private->page->setEditable(flag);
7211        if (!_private->tabKeyCyclesThroughElementsChanged)
7212            _private->page->setTabKeyCyclesThroughElements(!flag);
7213        Frame* mainFrame = [self _mainCoreFrame];
7214        if (mainFrame) {
7215            if (flag) {
7216                mainFrame->editor().applyEditingStyleToBodyElement();
7217                // If the WebView is made editable and the selection is empty, set it to something.
7218                if (![self selectedDOMRange])
7219                    mainFrame->selection().setSelectionFromNone();
7220            }
7221        }
7222    }
7223}
7224
7225- (BOOL)isEditable
7226{
7227    return _private->page && _private->page->isEditable();
7228}
7229
7230- (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
7231{
7232    // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
7233    // change the API to allow this.
7234    [[self _selectedOrMainFrame] _setTypingStyle:style withUndoAction:EditActionUnspecified];
7235}
7236
7237- (DOMCSSStyleDeclaration *)typingStyle
7238{
7239    return [[self _selectedOrMainFrame] _typingStyle];
7240}
7241
7242- (void)setSmartInsertDeleteEnabled:(BOOL)flag
7243{
7244    if (_private->page->settings().smartInsertDeleteEnabled() != flag) {
7245        _private->page->settings().setSmartInsertDeleteEnabled(flag);
7246        [[NSUserDefaults standardUserDefaults] setBool:_private->page->settings().smartInsertDeleteEnabled() forKey:WebSmartInsertDeleteEnabled];
7247        [self setSelectTrailingWhitespaceEnabled:!flag];
7248    }
7249}
7250
7251- (BOOL)smartInsertDeleteEnabled
7252{
7253    return _private->page->settings().smartInsertDeleteEnabled();
7254}
7255
7256- (void)setContinuousSpellCheckingEnabled:(BOOL)flag
7257{
7258    if (continuousSpellCheckingEnabled == flag)
7259        return;
7260
7261    continuousSpellCheckingEnabled = flag;
7262#if !PLATFORM(IOS)
7263    [[NSUserDefaults standardUserDefaults] setBool:continuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled];
7264#endif
7265    if ([self isContinuousSpellCheckingEnabled])
7266        [[self class] _preflightSpellChecker];
7267    else
7268        [[self mainFrame] _unmarkAllMisspellings];
7269}
7270
7271- (BOOL)isContinuousSpellCheckingEnabled
7272{
7273    return (continuousSpellCheckingEnabled && [self _continuousCheckingAllowed]);
7274}
7275
7276#if !PLATFORM(IOS)
7277- (NSInteger)spellCheckerDocumentTag
7278{
7279    if (!_private->hasSpellCheckerDocumentTag) {
7280        _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
7281        _private->hasSpellCheckerDocumentTag = YES;
7282    }
7283    return _private->spellCheckerDocumentTag;
7284}
7285#endif
7286
7287- (NSUndoManager *)undoManager
7288{
7289    if (!_private->allowsUndo)
7290        return nil;
7291
7292#if !PLATFORM(IOS)
7293    NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
7294    if (undoManager)
7295        return undoManager;
7296
7297    return [super undoManager];
7298#else
7299    return [[self _editingDelegateForwarder] undoManagerForWebView:self];
7300#endif
7301}
7302
7303- (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
7304{
7305    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
7306    if ([_private->editingDelegate respondsToSelector:selector])
7307        [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
7308}
7309
7310- (void)setEditingDelegate:(id)delegate
7311{
7312    if (_private->editingDelegate == delegate)
7313        return;
7314
7315    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
7316
7317    // remove notifications from current delegate
7318    [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
7319    [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
7320    [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
7321    [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
7322    [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
7323
7324    _private->editingDelegate = delegate;
7325    [_private->editingDelegateForwarder release];
7326    _private->editingDelegateForwarder = nil;
7327
7328    // add notifications for new delegate
7329    [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
7330    [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
7331    [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
7332    [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
7333    [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
7334}
7335
7336- (id)editingDelegate
7337{
7338    return _private->editingDelegate;
7339}
7340
7341- (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
7342{
7343    // FIXME: Should this really be attached to the document with the current selection?
7344    DOMCSSStyleDeclaration *decl = [[[self _selectedOrMainFrame] DOMDocument] createCSSStyleDeclaration];
7345    [decl setCssText:text];
7346    return decl;
7347}
7348
7349@end
7350
7351#if !PLATFORM(IOS)
7352@implementation WebView (WebViewGrammarChecking)
7353
7354// FIXME: This method should be merged into WebViewEditing when we're not in API freeze
7355- (BOOL)isGrammarCheckingEnabled
7356{
7357    return grammarCheckingEnabled;
7358}
7359
7360// FIXME: This method should be merged into WebViewEditing when we're not in API freeze
7361- (void)setGrammarCheckingEnabled:(BOOL)flag
7362{
7363    if (grammarCheckingEnabled == flag)
7364        return;
7365
7366    grammarCheckingEnabled = flag;
7367    [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled];
7368    [[NSSpellChecker sharedSpellChecker] updatePanels];
7369
7370    // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
7371    // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
7372
7373    if (![self isGrammarCheckingEnabled])
7374        [[self mainFrame] _unmarkAllBadGrammar];
7375}
7376
7377// FIXME: This method should be merged into WebIBActions when we're not in API freeze
7378- (void)toggleGrammarChecking:(id)sender
7379{
7380    [self setGrammarCheckingEnabled:![self isGrammarCheckingEnabled]];
7381}
7382
7383@end
7384#endif
7385
7386@implementation WebView (WebViewTextChecking)
7387
7388- (BOOL)isAutomaticQuoteSubstitutionEnabled
7389{
7390#if PLATFORM(IOS)
7391    return NO;
7392#else
7393    return automaticQuoteSubstitutionEnabled;
7394#endif
7395}
7396
7397- (BOOL)isAutomaticLinkDetectionEnabled
7398{
7399#if PLATFORM(IOS)
7400    return NO;
7401#else
7402    return automaticLinkDetectionEnabled;
7403#endif
7404}
7405
7406- (BOOL)isAutomaticDashSubstitutionEnabled
7407{
7408#if PLATFORM(IOS)
7409    return NO;
7410#else
7411    return automaticDashSubstitutionEnabled;
7412#endif
7413}
7414
7415- (BOOL)isAutomaticTextReplacementEnabled
7416{
7417#if PLATFORM(IOS)
7418    return NO;
7419#else
7420    return automaticTextReplacementEnabled;
7421#endif
7422}
7423
7424- (BOOL)isAutomaticSpellingCorrectionEnabled
7425{
7426#if PLATFORM(IOS)
7427    return NO;
7428#else
7429    return automaticSpellingCorrectionEnabled;
7430#endif
7431}
7432
7433#if !PLATFORM(IOS)
7434
7435- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag
7436{
7437    if (automaticQuoteSubstitutionEnabled == flag)
7438        return;
7439    automaticQuoteSubstitutionEnabled = flag;
7440    [[NSUserDefaults standardUserDefaults] setBool:automaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled];
7441    [[NSSpellChecker sharedSpellChecker] updatePanels];
7442}
7443
7444- (void)toggleAutomaticQuoteSubstitution:(id)sender
7445{
7446    [self setAutomaticQuoteSubstitutionEnabled:![self isAutomaticQuoteSubstitutionEnabled]];
7447}
7448
7449- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag
7450{
7451    if (automaticLinkDetectionEnabled == flag)
7452        return;
7453    automaticLinkDetectionEnabled = flag;
7454    [[NSUserDefaults standardUserDefaults] setBool:automaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled];
7455    [[NSSpellChecker sharedSpellChecker] updatePanels];
7456}
7457
7458- (void)toggleAutomaticLinkDetection:(id)sender
7459{
7460    [self setAutomaticLinkDetectionEnabled:![self isAutomaticLinkDetectionEnabled]];
7461}
7462
7463- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag
7464{
7465    if (automaticDashSubstitutionEnabled == flag)
7466        return;
7467    automaticDashSubstitutionEnabled = flag;
7468    [[NSUserDefaults standardUserDefaults] setBool:automaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled];
7469    [[NSSpellChecker sharedSpellChecker] updatePanels];
7470}
7471
7472- (void)toggleAutomaticDashSubstitution:(id)sender
7473{
7474    [self setAutomaticDashSubstitutionEnabled:![self isAutomaticDashSubstitutionEnabled]];
7475}
7476
7477- (void)setAutomaticTextReplacementEnabled:(BOOL)flag
7478{
7479    if (automaticTextReplacementEnabled == flag)
7480        return;
7481    automaticTextReplacementEnabled = flag;
7482    [[NSUserDefaults standardUserDefaults] setBool:automaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled];
7483    [[NSSpellChecker sharedSpellChecker] updatePanels];
7484}
7485
7486- (void)toggleAutomaticTextReplacement:(id)sender
7487{
7488    [self setAutomaticTextReplacementEnabled:![self isAutomaticTextReplacementEnabled]];
7489}
7490
7491- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag
7492{
7493    if (automaticSpellingCorrectionEnabled == flag)
7494        return;
7495    automaticSpellingCorrectionEnabled = flag;
7496    [[NSUserDefaults standardUserDefaults] setBool:automaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled];
7497    [[NSSpellChecker sharedSpellChecker] updatePanels];
7498}
7499
7500- (void)toggleAutomaticSpellingCorrection:(id)sender
7501{
7502    [self setAutomaticSpellingCorrectionEnabled:![self isAutomaticSpellingCorrectionEnabled]];
7503}
7504
7505#endif // !PLATFORM(IOS)
7506
7507@end
7508
7509@implementation WebView (WebViewUndoableEditing)
7510
7511- (void)replaceSelectionWithNode:(DOMNode *)node
7512{
7513    [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO];
7514}
7515
7516- (void)replaceSelectionWithText:(NSString *)text
7517{
7518    [[self _selectedOrMainFrame] _replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
7519}
7520
7521- (void)replaceSelectionWithMarkupString:(NSString *)markupString
7522{
7523    [[self _selectedOrMainFrame] _replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
7524}
7525
7526- (void)replaceSelectionWithArchive:(WebArchive *)archive
7527{
7528    [[[self _selectedOrMainFrame] _dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
7529}
7530
7531- (void)deleteSelection
7532{
7533    WebFrame *webFrame = [self _selectedOrMainFrame];
7534    Frame* coreFrame = core(webFrame);
7535    if (coreFrame)
7536        coreFrame->editor().deleteSelectionWithSmartDelete([(WebHTMLView *)[[webFrame frameView] documentView] _canSmartCopyOrDelete]);
7537}
7538
7539- (void)applyStyle:(DOMCSSStyleDeclaration *)style
7540{
7541    // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
7542    // change the API to allow this.
7543    WebFrame *webFrame = [self _selectedOrMainFrame];
7544    if (Frame* coreFrame = core(webFrame)) {
7545        // FIXME: We shouldn't have to make a copy here.
7546        Ref<MutableStyleProperties> properties(core(style)->copyProperties());
7547        coreFrame->editor().applyStyle(&properties.get());
7548    }
7549}
7550
7551@end
7552
7553@implementation WebView (WebViewEditingActions)
7554
7555- (void)_performResponderOperation:(SEL)selector with:(id)parameter
7556{
7557    static BOOL reentered = NO;
7558    if (reentered) {
7559        [[self nextResponder] tryToPerform:selector with:parameter];
7560        return;
7561    }
7562
7563    // There are two possibilities here.
7564    //
7565    // One is that WebView has been called in its role as part of the responder chain.
7566    // In that case, it's fine to call the first responder and end up calling down the
7567    // responder chain again. Later we will return here with reentered = YES and continue
7568    // past the WebView.
7569    //
7570    // The other is that we are being called directly, in which case we want to pass the
7571    // selector down to the view inside us that can handle it, and continue down the
7572    // responder chain as usual.
7573
7574    // Pass this selector down to the first responder.
7575    NSResponder *responder = [self _responderForResponderOperations];
7576    reentered = YES;
7577    [responder tryToPerform:selector with:parameter];
7578    reentered = NO;
7579}
7580
7581#define FORWARD(name) \
7582    - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
7583
7584FOR_EACH_RESPONDER_SELECTOR(FORWARD)
7585
7586#if PLATFORM(IOS)
7587FORWARD(clearText)
7588FORWARD(toggleBold)
7589FORWARD(toggleItalic)
7590FORWARD(toggleUnderline)
7591
7592- (void)insertDictationPhrases:(NSArray *)dictationPhrases metadata:(id)metadata
7593{
7594    Frame* coreFrame = core([self _selectedOrMainFrame]);
7595    if (!coreFrame)
7596        return;
7597
7598    coreFrame->editor().insertDictationPhrases(vectorForDictationPhrasesArray(dictationPhrases), metadata);
7599}
7600#endif
7601
7602- (void)insertText:(NSString *)text
7603{
7604    [self _performResponderOperation:_cmd with:text];
7605}
7606
7607- (NSDictionary *)typingAttributes
7608{
7609    Frame* coreFrame = core([self _selectedOrMainFrame]);
7610    if (coreFrame)
7611        return coreFrame->editor().fontAttributesForSelectionStart();
7612
7613    return nil;
7614}
7615
7616
7617@end
7618
7619@implementation WebView (WebViewEditingInMail)
7620
7621- (void)_insertNewlineInQuotedContent
7622{
7623    [[self _selectedOrMainFrame] _insertParagraphSeparatorInQuotedContent];
7624}
7625
7626- (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle
7627{
7628    [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle];
7629}
7630
7631- (BOOL)_selectionIsCaret
7632{
7633    Frame* coreFrame = core([self _selectedOrMainFrame]);
7634    if (!coreFrame)
7635        return NO;
7636    return coreFrame->selection().isCaret();
7637}
7638
7639- (BOOL)_selectionIsAll
7640{
7641    Frame* coreFrame = core([self _selectedOrMainFrame]);
7642    if (!coreFrame)
7643        return NO;
7644    return coreFrame->selection().isAll(CanCrossEditingBoundary);
7645}
7646
7647- (void)_simplifyMarkup:(DOMNode *)startNode endNode:(DOMNode *)endNode
7648{
7649    Frame* coreFrame = core([self mainFrame]);
7650    if (!coreFrame || !startNode)
7651        return;
7652    Node* coreStartNode= core(startNode);
7653    if (&coreStartNode->document() != coreFrame->document())
7654        return;
7655    return coreFrame->editor().simplifyMarkup(coreStartNode, core(endNode));
7656}
7657
7658@end
7659
7660static WebFrameView *containingFrameView(NSView *view)
7661{
7662    while (view && ![view isKindOfClass:[WebFrameView class]])
7663        view = [view superview];
7664    return (WebFrameView *)view;
7665}
7666
7667@implementation WebView (WebFileInternal)
7668
7669#if !PLATFORM(IOS)
7670- (float)_deviceScaleFactor
7671{
7672    if (_private->customDeviceScaleFactor != 0)
7673        return _private->customDeviceScaleFactor;
7674
7675    NSWindow *window = [self window];
7676    NSWindow *hostWindow = [self hostWindow];
7677    if (window)
7678        return [window backingScaleFactor];
7679    if (hostWindow)
7680        return [hostWindow backingScaleFactor];
7681    return [[NSScreen mainScreen] backingScaleFactor];
7682}
7683#endif
7684
7685static inline uint64_t roundUpToPowerOf2(uint64_t num)
7686{
7687    return powf(2.0, ceilf(log2f(num)));
7688}
7689
7690+ (void)_setCacheModel:(WebCacheModel)cacheModel
7691{
7692    if (s_didSetCacheModel && cacheModel == s_cacheModel)
7693        return;
7694
7695    NSString *nsurlCacheDirectory = CFBridgingRelease(WKCopyFoundationCacheDirectory());
7696    if (!nsurlCacheDirectory)
7697        nsurlCacheDirectory = NSHomeDirectory();
7698
7699    static uint64_t memSize = roundUpToPowerOf2(WebMemorySize() / 1024 / 1024);
7700    unsigned long long diskFreeSize = WebVolumeFreeSize(nsurlCacheDirectory) / 1024 / 1000;
7701    NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
7702
7703    unsigned cacheTotalCapacity = 0;
7704    unsigned cacheMinDeadCapacity = 0;
7705    unsigned cacheMaxDeadCapacity = 0;
7706    auto deadDecodedDataDeletionInterval = std::chrono::seconds { 0 };
7707
7708    unsigned pageCacheCapacity = 0;
7709
7710    NSUInteger nsurlCacheMemoryCapacity = 0;
7711    NSUInteger nsurlCacheDiskCapacity = 0;
7712#if PLATFORM(IOS)
7713    unsigned tileLayerPoolCapacity = 0;
7714#endif
7715
7716    switch (cacheModel) {
7717    case WebCacheModelDocumentViewer: {
7718        // Page cache capacity (in pages)
7719        pageCacheCapacity = 0;
7720
7721        // Object cache capacities (in bytes)
7722        if (memSize >= 4096)
7723            cacheTotalCapacity = 128 * 1024 * 1024;
7724        else if (memSize >= 2048)
7725            cacheTotalCapacity = 96 * 1024 * 1024;
7726        else if (memSize >= 1024)
7727            cacheTotalCapacity = 32 * 1024 * 1024;
7728        else if (memSize >= 512)
7729            cacheTotalCapacity = 16 * 1024 * 1024;
7730#if PLATFORM(IOS)
7731        else
7732            cacheTotalCapacity = 4 * 1024 * 1024;
7733#endif
7734
7735        cacheMinDeadCapacity = 0;
7736        cacheMaxDeadCapacity = 0;
7737
7738        // Foundation memory cache capacity (in bytes)
7739        nsurlCacheMemoryCapacity = 0;
7740
7741        // Foundation disk cache capacity (in bytes)
7742        nsurlCacheDiskCapacity = [nsurlCache diskCapacity];
7743
7744#if PLATFORM(IOS)
7745        // TileCache layer pool capacity, in bytes.
7746        if (memSize >= 1024)
7747            tileLayerPoolCapacity = 24 * 1024 * 1024;
7748        else
7749            tileLayerPoolCapacity = 12 * 1024 * 1024;
7750#endif
7751        break;
7752    }
7753    case WebCacheModelDocumentBrowser: {
7754        // Page cache capacity (in pages)
7755        if (memSize >= 1024)
7756            pageCacheCapacity = 3;
7757        else if (memSize >= 512)
7758            pageCacheCapacity = 2;
7759        else if (memSize >= 256)
7760            pageCacheCapacity = 1;
7761        else
7762            pageCacheCapacity = 0;
7763
7764        // Object cache capacities (in bytes)
7765        if (memSize >= 4096)
7766            cacheTotalCapacity = 128 * 1024 * 1024;
7767        else if (memSize >= 2048)
7768            cacheTotalCapacity = 96 * 1024 * 1024;
7769        else if (memSize >= 1024)
7770            cacheTotalCapacity = 32 * 1024 * 1024;
7771        else if (memSize >= 512)
7772            cacheTotalCapacity = 16 * 1024 * 1024;
7773
7774        cacheMinDeadCapacity = cacheTotalCapacity / 8;
7775        cacheMaxDeadCapacity = cacheTotalCapacity / 4;
7776
7777        // Foundation memory cache capacity (in bytes)
7778        if (memSize >= 2048)
7779            nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
7780        else if (memSize >= 1024)
7781            nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
7782        else if (memSize >= 512)
7783            nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
7784        else
7785            nsurlCacheMemoryCapacity =      512 * 1024;
7786
7787        // Foundation disk cache capacity (in bytes)
7788        if (diskFreeSize >= 16384)
7789            nsurlCacheDiskCapacity = 50 * 1024 * 1024;
7790        else if (diskFreeSize >= 8192)
7791            nsurlCacheDiskCapacity = 40 * 1024 * 1024;
7792        else if (diskFreeSize >= 4096)
7793            nsurlCacheDiskCapacity = 30 * 1024 * 1024;
7794        else
7795            nsurlCacheDiskCapacity = 20 * 1024 * 1024;
7796
7797#if PLATFORM(IOS)
7798        // TileCache layer pool capacity, in bytes.
7799        if (memSize >= 1024)
7800            tileLayerPoolCapacity = 24 * 1024 * 1024;
7801        else
7802            tileLayerPoolCapacity = 12 * 1024 * 1024;
7803#endif
7804        break;
7805    }
7806    case WebCacheModelPrimaryWebBrowser: {
7807        // Page cache capacity (in pages)
7808        // (Research indicates that value / page drops substantially after 3 pages.)
7809        if (memSize >= 2048)
7810            pageCacheCapacity = 5;
7811        else if (memSize >= 1024)
7812            pageCacheCapacity = 4;
7813        else if (memSize >= 512)
7814            pageCacheCapacity = 3;
7815        else if (memSize >= 256)
7816            pageCacheCapacity = 2;
7817        else
7818            pageCacheCapacity = 1;
7819
7820#if PLATFORM(IOS)
7821        // Cache page less aggressively in iOS to reduce the chance of being jettisoned.
7822        // FIXME (<rdar://problem/11779846>): Avoiding jettisoning should not have to require reducing the page cache capacity.
7823        // Reducing the capacity by 1 reduces overall back-forward performance.
7824        if (pageCacheCapacity > 0)
7825            pageCacheCapacity -= 1;
7826#endif
7827
7828        // Object cache capacities (in bytes)
7829        // (Testing indicates that value / MB depends heavily on content and
7830        // browsing pattern. Even growth above 128MB can have substantial
7831        // value / MB for some content / browsing patterns.)
7832        if (memSize >= 4096)
7833            cacheTotalCapacity = 192 * 1024 * 1024;
7834        else if (memSize >= 2048)
7835            cacheTotalCapacity = 128 * 1024 * 1024;
7836        else if (memSize >= 1024)
7837            cacheTotalCapacity = 64 * 1024 * 1024;
7838        else if (memSize >= 512)
7839            cacheTotalCapacity = 32 * 1024 * 1024;
7840
7841        cacheMinDeadCapacity = cacheTotalCapacity / 4;
7842        cacheMaxDeadCapacity = cacheTotalCapacity / 2;
7843
7844        // This code is here to avoid a PLT regression. We can remove it if we
7845        // can prove that the overall system gain would justify the regression.
7846        cacheMaxDeadCapacity = std::max<unsigned>(24, cacheMaxDeadCapacity);
7847
7848        deadDecodedDataDeletionInterval = std::chrono::seconds { 60 };
7849
7850#if PLATFORM(IOS)
7851        if (memSize >= 1024)
7852            nsurlCacheMemoryCapacity = 16 * 1024 * 1024;
7853        else
7854            nsurlCacheMemoryCapacity = 8 * 1024 * 1024;
7855#else
7856        // Foundation memory cache capacity (in bytes)
7857        // (These values are small because WebCore does most caching itself.)
7858        if (memSize >= 1024)
7859            nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
7860        else if (memSize >= 512)
7861            nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
7862        else if (memSize >= 256)
7863            nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
7864        else
7865            nsurlCacheMemoryCapacity =      512 * 1024;
7866#endif
7867
7868        // Foundation disk cache capacity (in bytes)
7869        if (diskFreeSize >= 16384)
7870            nsurlCacheDiskCapacity = 175 * 1024 * 1024;
7871        else if (diskFreeSize >= 8192)
7872            nsurlCacheDiskCapacity = 150 * 1024 * 1024;
7873        else if (diskFreeSize >= 4096)
7874            nsurlCacheDiskCapacity = 125 * 1024 * 1024;
7875        else if (diskFreeSize >= 2048)
7876            nsurlCacheDiskCapacity = 100 * 1024 * 1024;
7877        else if (diskFreeSize >= 1024)
7878            nsurlCacheDiskCapacity = 75 * 1024 * 1024;
7879        else
7880            nsurlCacheDiskCapacity = 50 * 1024 * 1024;
7881
7882#if PLATFORM(IOS)
7883        // TileCache layer pool capacity, in bytes.
7884        if (memSize >= 1024)
7885            tileLayerPoolCapacity = 48 * 1024 * 1024;
7886        else
7887            tileLayerPoolCapacity = 24 * 1024 * 1024;
7888#endif
7889        break;
7890    }
7891    default:
7892        ASSERT_NOT_REACHED();
7893    };
7894
7895
7896    // Don't shrink a big disk cache, since that would cause churn.
7897    nsurlCacheDiskCapacity = std::max(nsurlCacheDiskCapacity, [nsurlCache diskCapacity]);
7898
7899    memoryCache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
7900    memoryCache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval);
7901    pageCache()->setCapacity(pageCacheCapacity);
7902#if PLATFORM(IOS)
7903    pageCache()->setShouldClearBackingStores(true);
7904    nsurlCacheMemoryCapacity = std::max(nsurlCacheMemoryCapacity, [nsurlCache memoryCapacity]);
7905    CFURLCacheRef cfCache;
7906    if ([nsurlCache respondsToSelector:@selector(_CFURLCache)] && (cfCache = [nsurlCache _CFURLCache]))
7907        CFURLCacheSetMemoryCapacity(cfCache, nsurlCacheMemoryCapacity);
7908    else
7909        [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity];
7910#else
7911    [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity];
7912#endif
7913    [nsurlCache setDiskCapacity:nsurlCacheDiskCapacity];
7914
7915#if PLATFORM(IOS)
7916    [WebView _setTileCacheLayerPoolCapacity:tileLayerPoolCapacity];
7917#endif
7918
7919    s_cacheModel = cacheModel;
7920    s_didSetCacheModel = YES;
7921}
7922
7923+ (WebCacheModel)_cacheModel
7924{
7925    return s_cacheModel;
7926}
7927
7928+ (BOOL)_didSetCacheModel
7929{
7930    return s_didSetCacheModel;
7931}
7932
7933+ (WebCacheModel)_maxCacheModelInAnyInstance
7934{
7935    WebCacheModel cacheModel = WebCacheModelDocumentViewer;
7936    NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator];
7937    while (WebPreferences *preferences = [[enumerator nextObject] preferences])
7938        cacheModel = std::max(cacheModel, [preferences cacheModel]);
7939    return cacheModel;
7940}
7941
7942+ (void)_cacheModelChangedNotification:(NSNotification *)notification
7943{
7944#if PLATFORM(IOS)
7945    // This needs to happen on the Web Thread
7946    WebThreadRun(^{
7947#endif
7948    WebPreferences *preferences = (WebPreferences *)[notification object];
7949    ASSERT([preferences isKindOfClass:[WebPreferences class]]);
7950
7951    WebCacheModel cacheModel = [preferences cacheModel];
7952    if (![self _didSetCacheModel] || cacheModel > [self _cacheModel])
7953        [self _setCacheModel:cacheModel];
7954    else if (cacheModel < [self _cacheModel])
7955        [self _setCacheModel:std::max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])];
7956#if PLATFORM(IOS)
7957    });
7958#endif
7959}
7960
7961+ (void)_preferencesRemovedNotification:(NSNotification *)notification
7962{
7963    WebPreferences *preferences = (WebPreferences *)[notification object];
7964    ASSERT([preferences isKindOfClass:[WebPreferences class]]);
7965
7966    if ([preferences cacheModel] == [self _cacheModel])
7967        [self _setCacheModel:std::max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])];
7968}
7969
7970- (WebFrame *)_focusedFrame
7971{
7972    NSResponder *resp = [[self window] firstResponder];
7973    if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) {
7974        WebFrameView *frameView = containingFrameView((NSView *)resp);
7975        ASSERT(frameView != nil);
7976        return [frameView webFrame];
7977    }
7978
7979    return nil;
7980}
7981
7982- (BOOL)_isLoading
7983{
7984    WebFrame *mainFrame = [self mainFrame];
7985    return [[mainFrame _dataSource] isLoading]
7986        || [[mainFrame provisionalDataSource] isLoading];
7987}
7988
7989- (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point
7990{
7991    if (_private->closed)
7992        return nil;
7993#if !PLATFORM(IOS)
7994    NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]];
7995#else
7996    //[WebView superview] on iOS is nil, don't do a convertPoint
7997    NSView *view = [self hitTest:point];
7998#endif
7999    if (![view isDescendantOf:[[self mainFrame] frameView]])
8000        return nil;
8001    WebFrameView *frameView = containingFrameView(view);
8002    ASSERT(frameView);
8003    return frameView;
8004}
8005
8006+ (void)_preflightSpellCheckerNow:(id)sender
8007{
8008#if !PLATFORM(IOS)
8009    [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
8010#endif
8011}
8012
8013+ (void)_preflightSpellChecker
8014{
8015#if !PLATFORM(IOS)
8016    // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
8017    if ([NSSpellChecker sharedSpellCheckerExists]) {
8018        [self _preflightSpellCheckerNow:self];
8019    } else {
8020        [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0];
8021    }
8022#endif
8023}
8024
8025- (BOOL)_continuousCheckingAllowed
8026{
8027    static BOOL allowContinuousSpellChecking = YES;
8028    static BOOL readAllowContinuousSpellCheckingDefault = NO;
8029    if (!readAllowContinuousSpellCheckingDefault) {
8030        if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) {
8031            allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
8032        }
8033        readAllowContinuousSpellCheckingDefault = YES;
8034    }
8035    return allowContinuousSpellChecking;
8036}
8037
8038- (NSResponder *)_responderForResponderOperations
8039{
8040    NSResponder *responder = [[self window] firstResponder];
8041    WebFrameView *mainFrameView = [[self mainFrame] frameView];
8042
8043    // If the current responder is outside of the webview, use our main frameView or its
8044    // document view. We also do this for subviews of self that are siblings of the main
8045    // frameView since clients might insert non-webview-related views there (see 4552713).
8046    if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) {
8047        responder = [mainFrameView documentView];
8048        if (!responder)
8049            responder = mainFrameView;
8050    }
8051    return responder;
8052}
8053
8054#if !PLATFORM(IOS)
8055- (void)_openFrameInNewWindowFromMenu:(NSMenuItem *)sender
8056{
8057    ASSERT_ARG(sender, [sender isKindOfClass:[NSMenuItem class]]);
8058
8059    NSDictionary *element = [sender representedObject];
8060    ASSERT([element isKindOfClass:[NSDictionary class]]);
8061
8062    WebDataSource *dataSource = [(WebFrame *)[element objectForKey:WebElementFrameKey] dataSource];
8063    NSURLRequest *request = [[dataSource request] copy];
8064    ASSERT(request);
8065
8066    [self _openNewWindowWithRequest:request];
8067    [request release];
8068}
8069
8070- (void)_searchWithGoogleFromMenu:(id)sender
8071{
8072    id documentView = [[[self selectedFrame] frameView] documentView];
8073    if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
8074        return;
8075    }
8076
8077    NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
8078    if ([selectedString length] == 0) {
8079        return;
8080    }
8081
8082    NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
8083    [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
8084    NSMutableString *s = [selectedString mutableCopy];
8085    const unichar nonBreakingSpaceCharacter = 0xA0;
8086    NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1];
8087    [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
8088    [pasteboard setString:s forType:NSStringPboardType];
8089    [s release];
8090
8091    // FIXME: seems fragile to use the service by name, but this is what AppKit does
8092    NSPerformService(@"Search With Google", pasteboard);
8093}
8094
8095- (void)_searchWithSpotlightFromMenu:(id)sender
8096{
8097    id documentView = [[[self selectedFrame] frameView] documentView];
8098    if (![documentView conformsToProtocol:@protocol(WebDocumentText)])
8099        return;
8100
8101    NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
8102    if (![selectedString length])
8103        return;
8104
8105    [[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:selectedString];
8106}
8107#endif // !PLATFORM(IOS)
8108
8109#if USE(GLIB)
8110- (void)_clearGlibLoopObserver
8111{
8112    if (!_private->glibRunLoopObserver)
8113        return;
8114
8115    CFRunLoopObserverInvalidate(_private->glibRunLoopObserver);
8116    CFRelease(_private->glibRunLoopObserver);
8117    _private->glibRunLoopObserver = 0;
8118}
8119#endif
8120@end
8121
8122@implementation WebView (WebViewInternal)
8123
8124+ (BOOL)shouldIncludeInWebKitStatistics
8125{
8126    return NO;
8127}
8128
8129- (BOOL)_becomingFirstResponderFromOutside
8130{
8131    return _private->becomingFirstResponderFromOutside;
8132}
8133
8134#if ENABLE(ICONDATABASE)
8135- (void)_receivedIconChangedNotification:(NSNotification *)notification
8136{
8137    // Get the URL for this notification
8138    NSDictionary *userInfo = [notification userInfo];
8139    ASSERT([userInfo isKindOfClass:[NSDictionary class]]);
8140    NSString *urlString = [userInfo objectForKey:WebIconNotificationUserInfoURLKey];
8141    ASSERT([urlString isKindOfClass:[NSString class]]);
8142
8143    // If that URL matches the current main frame, dispatch the delegate call, which will also unregister
8144    // us for this notification
8145    if ([[self mainFrameURL] isEqualTo:urlString])
8146        [self _dispatchDidReceiveIconFromWebFrame:[self mainFrame]];
8147}
8148
8149- (void)_registerForIconNotification:(BOOL)listen
8150{
8151    if (listen)
8152        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_receivedIconChangedNotification:) name:WebIconDatabaseDidAddIconNotification object:nil];
8153    else
8154        [[NSNotificationCenter defaultCenter] removeObserver:self name:WebIconDatabaseDidAddIconNotification object:nil];
8155}
8156
8157- (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame
8158{
8159    // FIXME: This willChangeValueForKey call is too late, because the icon has already changed by now.
8160    [self _willChangeValueForKey:_WebMainFrameIconKey];
8161
8162    // 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
8163    // notification any longer
8164    [self _registerForIconNotification:NO];
8165
8166    WebFrameLoadDelegateImplementationCache* cache = &_private->frameLoadDelegateImplementations;
8167    if (cache->didReceiveIconForFrameFunc) {
8168        Image* image = iconDatabase().synchronousIconForPageURL(core(webFrame)->document()->url().string(), IntSize(16, 16));
8169        if (NSImage *icon = webGetNSImage(image, NSMakeSize(16, 16)))
8170            CallFrameLoadDelegate(cache->didReceiveIconForFrameFunc, self, @selector(webView:didReceiveIcon:forFrame:), icon, webFrame);
8171    }
8172
8173    [self _didChangeValueForKey:_WebMainFrameIconKey];
8174}
8175#endif // ENABLE(ICONDATABASE)
8176
8177- (void)_addObject:(id)object forIdentifier:(unsigned long)identifier
8178{
8179    ASSERT(!_private->identifierMap.contains(identifier));
8180
8181    // If the identifier map is initially empty it means we're starting a load
8182    // of something. The semantic is that the web view should be around as long
8183    // as something is loading. Because of that we retain the web view.
8184    if (_private->identifierMap.isEmpty())
8185        CFRetain(self);
8186
8187    _private->identifierMap.set(identifier, object);
8188}
8189
8190- (id)_objectForIdentifier:(unsigned long)identifier
8191{
8192    return _private->identifierMap.get(identifier).get();
8193}
8194
8195- (void)_removeObjectForIdentifier:(unsigned long)identifier
8196{
8197    ASSERT(_private->identifierMap.contains(identifier));
8198    _private->identifierMap.remove(identifier);
8199
8200    // If the identifier map is now empty it means we're no longer loading anything
8201    // and we should release the web view. Autorelease rather than release in order to
8202    // avoid re-entering this method beneath -dealloc with the same identifier. <rdar://problem/10523721>
8203    if (_private->identifierMap.isEmpty())
8204        [self autorelease];
8205}
8206
8207- (void)_retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification
8208{
8209    CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
8210
8211    Boolean keyExistsAndHasValidFormat;
8212    int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
8213
8214    // The keyboard access mode has two bits:
8215    // Bit 0 is set if user can set the focus to menus, the dock, and various windows using the keyboard.
8216    // Bit 1 is set if controls other than text fields are included in the tab order (WebKit also always includes lists).
8217    _private->_keyboardUIMode = (mode & 0x2) ? KeyboardAccessFull : KeyboardAccessDefault;
8218#if !PLATFORM(IOS)
8219    // check for tabbing to links
8220    if ([_private->preferences tabsToLinks])
8221        _private->_keyboardUIMode = (KeyboardUIMode)(_private->_keyboardUIMode | KeyboardAccessTabsToLinks);
8222#endif
8223}
8224
8225- (KeyboardUIMode)_keyboardUIMode
8226{
8227    if (!_private->_keyboardUIModeAccessed) {
8228        _private->_keyboardUIModeAccessed = YES;
8229
8230        [self _retrieveKeyboardUIModeFromPreferences:nil];
8231
8232#if !PLATFORM(IOS)
8233        [[NSDistributedNotificationCenter defaultCenter]
8234            addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:)
8235            name:KeyboardUIModeDidChangeNotification object:nil];
8236#endif
8237
8238        [[NSNotificationCenter defaultCenter]
8239            addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:)
8240            name:WebPreferencesChangedInternalNotification object:nil];
8241    }
8242    return _private->_keyboardUIMode;
8243}
8244
8245#if !PLATFORM(IOS)
8246- (void)_setInsertionPasteboard:(NSPasteboard *)pasteboard
8247{
8248    _private->insertionPasteboard = pasteboard;
8249}
8250#endif
8251
8252- (Frame*)_mainCoreFrame
8253{
8254    return (_private && _private->page) ? &_private->page->mainFrame() : 0;
8255}
8256
8257- (WebFrame *)_selectedOrMainFrame
8258{
8259    WebFrame *result = [self selectedFrame];
8260    if (result == nil)
8261        result = [self mainFrame];
8262    return result;
8263}
8264
8265- (BOOL)_needsOneShotDrawingSynchronization
8266{
8267    return _private->needsOneShotDrawingSynchronization;
8268}
8269
8270- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization
8271{
8272    _private->needsOneShotDrawingSynchronization = needsSynchronization;
8273}
8274
8275/*
8276    The order of events with compositing updates is this:
8277
8278   Start of runloop                                        End of runloop
8279        |                                                       |
8280      --|-------------------------------------------------------|--
8281           ^         ^                                        ^
8282           |         |                                        |
8283    NSWindow update, |                                     CA commit
8284     NSView drawing  |
8285        flush        |
8286                layerSyncRunLoopObserverCallBack
8287
8288    To avoid flashing, we have to ensure that compositing changes (rendered via
8289    the CoreAnimation rendering display link) appear on screen at the same time
8290    as content painted into the window via the normal WebCore rendering path.
8291
8292    CoreAnimation will commit any layer changes at the end of the runloop via
8293    its "CA commit" observer. Those changes can then appear onscreen at any time
8294    when the display link fires, which can result in unsynchronized rendering.
8295
8296    To fix this, the GraphicsLayerCA code in WebCore does not change the CA
8297    layer tree during style changes and layout; it stores up all changes and
8298    commits them via flushCompositingState(). There are then two situations in
8299    which we can call flushCompositingState():
8300
8301    1. When painting. FrameView::paintContents() makes a call to flushCompositingState().
8302
8303    2. When style changes/layout have made changes to the layer tree which do not
8304       result in painting. In this case we need a run loop observer to do a
8305       flushCompositingState() at an appropriate time. The observer will keep firing
8306       until the time is right (essentially when there are no more pending layouts).
8307
8308*/
8309bool LayerFlushController::flushLayers()
8310{
8311#if PLATFORM(IOS)
8312    WebThreadLock();
8313#endif
8314#if !PLATFORM(IOS)
8315    NSWindow *window = [m_webView window];
8316
8317    // An NSWindow may not display in the next runloop cycle after dirtying due to delayed window display logic,
8318    // in which case this observer can fire first. So if the window is due for a display, don't commit
8319    // layer changes, otherwise they'll show on screen before the view drawing.
8320    bool viewsNeedDisplay;
8321#ifndef __LP64__
8322    if (window && [window _wrapsCarbonWindow])
8323        viewsNeedDisplay = HIViewGetNeedsDisplay(HIViewGetRoot(static_cast<WindowRef>([window windowRef])));
8324    else
8325#endif
8326        viewsNeedDisplay = [window viewsNeedDisplay];
8327
8328    if (viewsNeedDisplay)
8329        return false;
8330#endif
8331
8332#if PLATFORM(IOS)
8333    // Ensure fixed positions layers are where they should be.
8334    [m_webView _synchronizeCustomFixedPositionLayoutRect];
8335#endif
8336
8337    [m_webView _viewWillDrawInternal];
8338
8339    if ([m_webView _flushCompositingChanges]) {
8340#if !PLATFORM(IOS)
8341        // AppKit may have disabled screen updates, thinking an upcoming window flush will re-enable them.
8342        // In case setNeedsDisplayInRect() has prevented the window from needing to be flushed, re-enable screen
8343        // updates here.
8344        if (![window isFlushWindowDisabled])
8345            [window _enableScreenUpdatesIfNeeded];
8346#endif
8347
8348        return true;
8349    }
8350
8351    return false;
8352}
8353
8354- (void)_scheduleCompositingLayerFlush
8355{
8356#if PLATFORM(IOS)
8357    if (_private->closing)
8358        return;
8359#endif
8360
8361    if (!_private->layerFlushController)
8362        _private->layerFlushController = LayerFlushController::create(self);
8363    _private->layerFlushController->scheduleLayerFlush();
8364}
8365
8366- (BOOL)_flushCompositingChanges
8367{
8368    Frame* frame = [self _mainCoreFrame];
8369    if (frame && frame->view())
8370        return frame->view()->flushCompositingStateIncludingSubframes();
8371
8372    return YES;
8373}
8374
8375#if PLATFORM(IOS)
8376- (void)_scheduleLayerFlushForPendingTileCacheRepaint
8377{
8378    Frame* coreFrame = [self _mainCoreFrame];
8379    if (FrameView* view = coreFrame->view())
8380        view->scheduleLayerFlushAllowingThrottling();
8381}
8382#endif
8383
8384#if ENABLE(VIDEO)
8385- (void)_enterFullscreenForNode:(WebCore::Node*)node
8386{
8387    ASSERT(isHTMLVideoElement(node));
8388    HTMLMediaElement* videoElement = toHTMLMediaElement(node);
8389
8390    if (_private->fullscreenController) {
8391        if ([_private->fullscreenController mediaElement] == videoElement) {
8392            // The backend may just warn us that the underlaying plaftormMovie()
8393            // has changed. Just force an update.
8394            [_private->fullscreenController setMediaElement:videoElement];
8395            return; // No more to do.
8396        }
8397
8398        // First exit Fullscreen for the old mediaElement.
8399        [_private->fullscreenController mediaElement]->exitFullscreen();
8400        // This previous call has to trigger _exitFullscreen,
8401        // which has to clear _private->fullscreenController.
8402        ASSERT(!_private->fullscreenController);
8403    }
8404    if (!_private->fullscreenController) {
8405        _private->fullscreenController = [[WebVideoFullscreenController alloc] init];
8406        [_private->fullscreenController setMediaElement:videoElement];
8407#if PLATFORM(IOS)
8408        [_private->fullscreenController enterFullscreen:(UIView *)[[[self window] hostLayer] delegate]];
8409#else
8410        [_private->fullscreenController enterFullscreen:[[self window] screen]];
8411#endif
8412    }
8413    else
8414        [_private->fullscreenController setMediaElement:videoElement];
8415}
8416
8417- (void)_exitFullscreen
8418{
8419    if (!_private->fullscreenController)
8420        return;
8421    [_private->fullscreenController exitFullscreen];
8422    [_private->fullscreenController release];
8423    _private->fullscreenController = nil;
8424}
8425
8426#endif // ENABLE(VIDEO) && !PLATFORM(IOS)
8427
8428#if ENABLE(FULLSCREEN_API) && !PLATFORM(IOS)
8429- (BOOL)_supportsFullScreenForElement:(const WebCore::Element*)element withKeyboard:(BOOL)withKeyboard
8430{
8431    if (![[WebPreferences standardPreferences] fullScreenEnabled])
8432        return NO;
8433
8434    return !withKeyboard;
8435}
8436
8437- (void)_enterFullScreenForElement:(WebCore::Element*)element
8438{
8439    if (!_private->newFullscreenController)
8440        _private->newFullscreenController = [[WebFullScreenController alloc] init];
8441
8442    [_private->newFullscreenController setElement:element];
8443    [_private->newFullscreenController setWebView:self];
8444    [_private->newFullscreenController enterFullScreen:[[self window] screen]];
8445}
8446
8447- (void)_exitFullScreenForElement:(WebCore::Element*)element
8448{
8449    if (!_private->newFullscreenController)
8450        return;
8451    [_private->newFullscreenController exitFullScreen];
8452}
8453#endif
8454
8455#if USE(GLIB)
8456
8457static void glibContextIterationCallback(CFRunLoopObserverRef, CFRunLoopActivity, void*)
8458{
8459    g_main_context_iteration(0, FALSE);
8460}
8461
8462- (void)_scheduleGlibContextIterations
8463{
8464    if (_private->glibRunLoopObserver)
8465        return;
8466
8467    NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
8468
8469    // Create a run loop observer and attach it to the run loop.
8470    CFRunLoopObserverContext context = {0, self, 0, 0, 0};
8471    _private->glibRunLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, YES, 0, &glibContextIterationCallback, &context);
8472
8473    if (_private->glibRunLoopObserver) {
8474        CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop];
8475        CFRunLoopAddObserver(cfLoop, _private->glibRunLoopObserver, kCFRunLoopDefaultMode);
8476    }
8477
8478}
8479#endif
8480
8481#if USE(AUTOCORRECTION_PANEL)
8482- (void)handleAcceptedAlternativeText:(NSString*)text
8483{
8484    WebFrame *webFrame = [self _selectedOrMainFrame];
8485    Frame* coreFrame = core(webFrame);
8486    if (coreFrame)
8487        coreFrame->editor().handleAlternativeTextUIResult(text);
8488}
8489#endif
8490
8491#if USE(DICTATION_ALTERNATIVES)
8492- (void)_getWebCoreDictationAlternatives:(Vector<DictationAlternative>&)alternatives fromTextAlternatives:(const Vector<TextAlternativeWithRange>&)alternativesWithRange
8493{
8494    for (size_t i = 0; i < alternativesWithRange.size(); ++i) {
8495        const TextAlternativeWithRange& alternativeWithRange = alternativesWithRange[i];
8496        uint64_t dictationContext = _private->m_alternativeTextUIController->addAlternatives(alternativeWithRange.alternatives);
8497        if (dictationContext)
8498            alternatives.append(DictationAlternative(alternativeWithRange.range.location, alternativeWithRange.range.length, dictationContext));
8499    }
8500}
8501
8502- (void)_showDictationAlternativeUI:(const WebCore::FloatRect&)boundingBoxOfDictatedText forDictationContext:(uint64_t)dictationContext
8503{
8504    _private->m_alternativeTextUIController->showAlternatives(self, [self _convertRectFromRootView:boundingBoxOfDictatedText], dictationContext, ^(NSString* acceptedAlternative) {
8505        [self handleAcceptedAlternativeText:acceptedAlternative];
8506    });
8507}
8508
8509- (void)_removeDictationAlternatives:(uint64_t)dictationContext
8510{
8511    _private->m_alternativeTextUIController->removeAlternatives(dictationContext);
8512}
8513
8514- (Vector<String>)_dictationAlternatives:(uint64_t)dictationContext
8515{
8516    return _private->m_alternativeTextUIController->alternativesForContext(dictationContext);
8517}
8518#endif
8519
8520- (NSPoint)_convertPointFromRootView:(NSPoint)point
8521{
8522    return NSMakePoint(point.x, [self bounds].size.height - point.y);
8523}
8524
8525- (NSRect)_convertRectFromRootView:(NSRect)rect
8526{
8527    return NSMakeRect(rect.origin.x, [self bounds].size.height - rect.origin.y - rect.size.height, rect.size.width, rect.size.height);
8528}
8529
8530@end
8531
8532@implementation WebView (WebViewDeviceOrientation)
8533
8534- (void)_setDeviceOrientationProvider:(id<WebDeviceOrientationProvider>)deviceOrientationProvider
8535{
8536    if (_private)
8537        _private->m_deviceOrientationProvider = deviceOrientationProvider;
8538}
8539
8540- (id<WebDeviceOrientationProvider>)_deviceOrientationProvider
8541{
8542    if (_private)
8543        return _private->m_deviceOrientationProvider;
8544    return nil;
8545}
8546
8547@end
8548
8549#if ENABLE(MEDIA_STREAM)
8550@implementation WebView (WebViewUserMedia)
8551
8552- (void)_setUserMediaClient:(id<WebUserMediaClient>)userMediaClient
8553{
8554    if (_private)
8555        _private->m_userMediaClient = userMediaClient;
8556}
8557
8558- (id<WebUserMediaClient>)_userMediaClient
8559{
8560    if (_private)
8561        return _private->m_userMediaClient;
8562    return nil;
8563}
8564@end
8565#endif
8566
8567@implementation WebView (WebViewGeolocation)
8568
8569- (void)_setGeolocationProvider:(id<WebGeolocationProvider>)geolocationProvider
8570{
8571    if (_private)
8572        _private->_geolocationProvider = geolocationProvider;
8573}
8574
8575- (id<WebGeolocationProvider>)_geolocationProvider
8576{
8577    if (_private)
8578        return _private->_geolocationProvider;
8579    return nil;
8580}
8581
8582- (void)_geolocationDidChangePosition:(WebGeolocationPosition *)position
8583{
8584#if ENABLE(GEOLOCATION)
8585    if (_private && _private->page)
8586        WebCore::GeolocationController::from(_private->page)->positionChanged(core(position));
8587#endif // ENABLE(GEOLOCATION)
8588}
8589
8590- (void)_geolocationDidFailWithMessage:(NSString *)errorMessage
8591{
8592#if ENABLE(GEOLOCATION)
8593    if (_private && _private->page) {
8594        RefPtr<GeolocationError> geolocatioError = GeolocationError::create(GeolocationError::PositionUnavailable, errorMessage);
8595        WebCore::GeolocationController::from(_private->page)->errorOccurred(geolocatioError.get());
8596    }
8597#endif // ENABLE(GEOLOCATION)
8598}
8599
8600#if PLATFORM(IOS)
8601- (void)_resetAllGeolocationPermission
8602{
8603#if ENABLE(GEOLOCATION)
8604    Frame* frame = [self _mainCoreFrame];
8605    if (frame)
8606        frame->resetAllGeolocationPermission();
8607#endif
8608}
8609#endif
8610
8611@end
8612
8613@implementation WebView (WebViewNotification)
8614- (void)_setNotificationProvider:(id<WebNotificationProvider>)notificationProvider
8615{
8616    if (_private && !_private->_notificationProvider) {
8617        _private->_notificationProvider = notificationProvider;
8618        [_private->_notificationProvider registerWebView:self];
8619    }
8620}
8621
8622- (id<WebNotificationProvider>)_notificationProvider
8623{
8624    if (_private)
8625        return _private->_notificationProvider;
8626    return nil;
8627}
8628
8629- (void)_notificationDidShow:(uint64_t)notificationID
8630{
8631    [[self _notificationProvider] webView:self didShowNotification:notificationID];
8632}
8633
8634- (void)_notificationDidClick:(uint64_t)notificationID
8635{
8636    [[self _notificationProvider] webView:self didClickNotification:notificationID];
8637}
8638
8639- (void)_notificationsDidClose:(NSArray *)notificationIDs
8640{
8641    [[self _notificationProvider] webView:self didCloseNotifications:notificationIDs];
8642}
8643
8644- (uint64_t)_notificationIDForTesting:(JSValueRef)jsNotification
8645{
8646#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
8647    JSContextRef context = [[self mainFrame] globalContext];
8648    WebCore::Notification* notification = toNotification(toJS(toJS(context), jsNotification));
8649    return static_cast<WebNotificationClient*>(NotificationController::clientFrom(_private->page))->notificationIDForTesting(notification);
8650#else
8651    return 0;
8652#endif
8653}
8654@end
8655
8656#if PLATFORM(IOS)
8657@implementation WebView (WebViewIOSPDF)
8658
8659+ (Class)_getPDFRepresentationClass
8660{
8661    if (s_pdfRepresentationClass)
8662        return s_pdfRepresentationClass;
8663    return [WebPDFView class]; // This is WebPDFRepresentation for PLATFORM(MAC).
8664}
8665
8666+ (void)_setPDFRepresentationClass:(Class)pdfRepresentationClass
8667{
8668    s_pdfRepresentationClass = pdfRepresentationClass;
8669}
8670
8671+ (Class)_getPDFViewClass
8672{
8673    if (s_pdfViewClass)
8674        return s_pdfViewClass;
8675    return [WebPDFView class];
8676}
8677
8678+ (void)_setPDFViewClass:(Class)pdfViewClass
8679{
8680    s_pdfViewClass = pdfViewClass;
8681}
8682
8683@end
8684#endif
8685
8686@implementation WebView (WebViewFullScreen)
8687
8688- (NSView*)fullScreenPlaceholderView
8689{
8690#if ENABLE(FULLSCREEN_API)
8691    if (_private->newFullscreenController && [_private->newFullscreenController isFullScreen])
8692        return [_private->newFullscreenController webViewPlaceholder];
8693#endif
8694    return nil;
8695}
8696
8697@end
8698
8699void WebInstallMemoryPressureHandler(void)
8700{
8701    memoryPressureHandler().install();
8702}
8703