OSDN Git Service

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