985cb53b7b5b0efbb2323a7725c2b23f8b9bca74
[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 "WebPluginDatabase.h"
90 #import "WebPluginHalterClient.h"
91 #import "WebPolicyDelegate.h"
92 #import "WebPreferenceKeysPrivate.h"
93 #import "WebPreferencesPrivate.h"
94 #import "WebScriptDebugDelegate.h"
95 #import "WebScriptWorldInternal.h"
96 #import "WebSystemInterface.h"
97 #import "WebTextCompletionController.h"
98 #import "WebTextIterator.h"
99 #import "WebUIDelegate.h"
100 #import "WebUIDelegatePrivate.h"
101 #import "WebVideoFullscreenController.h"
102 #import <CoreFoundation/CFSet.h>
103 #import <Foundation/NSURLConnection.h>
104 #import <JavaScriptCore/APICast.h>
105 #import <JavaScriptCore/JSValueRef.h>
106 #import <WebCore/ApplicationCacheStorage.h>
107 #import <WebCore/BackForwardList.h>
108 #import <WebCore/Cache.h>
109 #import <WebCore/ColorMac.h>
110 #import <WebCore/CSSComputedStyleDeclaration.h>
111 #import <WebCore/Cursor.h>
112 #import <WebCore/Database.h>
113 #import <WebCore/Document.h>
114 #import <WebCore/DocumentLoader.h>
115 #import <WebCore/DragController.h>
116 #import <WebCore/DragData.h>
117 #import <WebCore/Editor.h>
118 #import <WebCore/EventHandler.h>
119 #import <WebCore/ExceptionHandlers.h>
120 #import <WebCore/FocusController.h>
121 #import <WebCore/Frame.h>
122 #import <WebCore/FrameLoader.h>
123 #import <WebCore/FrameTree.h>
124 #import <WebCore/FrameView.h>
125 #import <WebCore/GCController.h>
126 #import <WebCore/HTMLMediaElement.h>
127 #import <WebCore/HTMLNames.h>
128 #import <WebCore/HistoryItem.h>
129 #import <WebCore/IconDatabase.h>
130 #import <WebCore/JSCSSStyleDeclaration.h>
131 #import <WebCore/JSElement.h>
132 #import <WebCore/Logging.h>
133 #import <WebCore/MIMETypeRegistry.h>
134 #import <WebCore/Page.h>
135 #import <WebCore/PageCache.h>
136 #import <WebCore/PageGroup.h>
137 #import <WebCore/PlatformMouseEvent.h>
138 #import <WebCore/ProgressTracker.h>
139 #import <WebCore/RenderWidget.h>
140 #import <WebCore/ResourceHandle.h>
141 #import <WebCore/RuntimeApplicationChecks.h>
142 #import <WebCore/ScriptController.h>
143 #import <WebCore/ScriptValue.h>
144 #import <WebCore/SecurityOrigin.h>
145 #import <WebCore/SelectionController.h>
146 #import <WebCore/Settings.h>
147 #import <WebCore/TextResourceDecoder.h>
148 #import <WebCore/ThreadCheck.h>
149 #import <WebCore/WebCoreObjCExtras.h>
150 #import <WebCore/WebCoreView.h>
151 #import <WebCore/Widget.h>
152 #import <WebKit/DOM.h>
153 #import <WebKit/DOMExtensions.h>
154 #import <WebKit/DOMPrivate.h>
155 #import <WebKitSystemInterface.h>
156 #import <mach-o/dyld.h>
157 #import <objc/objc-auto.h>
158 #import <objc/objc-runtime.h>
159 #import <runtime/ArrayPrototype.h>
160 #import <runtime/DateInstance.h>
161 #import <runtime/InitializeThreading.h>
162 #import <runtime/JSLock.h>
163 #import <runtime/JSValue.h>
164 #import <wtf/Assertions.h>
165 #import <wtf/HashTraits.h>
166 #import <wtf/RefCountedLeakCounter.h>
167 #import <wtf/RefPtr.h>
168 #import <wtf/StdLibExtras.h>
169 #import <wtf/Threading.h>
170
171 #if ENABLE(DASHBOARD_SUPPORT)
172 #import <WebKit/WebDashboardRegion.h>
173 #endif
174
175 #if ENABLE(CLIENT_BASED_GEOLOCATION)
176 #import <WebCore/GeolocationController.h>
177 #import <WebCore/GeolocationError.h>
178 #endif
179
180 @interface NSSpellChecker (WebNSSpellCheckerDetails)
181 - (void)_preflightChosenSpellServer;
182 @end
183
184 @interface NSView (WebNSViewDetails)
185 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
186 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
187 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
188 @end
189
190 @interface NSWindow (WebNSWindowDetails) 
191 - (id)_oldFirstResponderBeforeBecoming;
192 - (void)_enableScreenUpdatesIfNeeded;
193 @end
194
195 using namespace WebCore;
196 using namespace JSC;
197
198 #if defined(__ppc__) || defined(__ppc64__)
199 #define PROCESSOR "PPC"
200 #elif defined(__i386__) || defined(__x86_64__)
201 #define PROCESSOR "Intel"
202 #else
203 #error Unknown architecture
204 #endif
205
206 #define FOR_EACH_RESPONDER_SELECTOR(macro) \
207 macro(alignCenter) \
208 macro(alignJustified) \
209 macro(alignLeft) \
210 macro(alignRight) \
211 macro(capitalizeWord) \
212 macro(centerSelectionInVisibleArea) \
213 macro(changeAttributes) \
214 macro(changeBaseWritingDirection) \
215 macro(changeBaseWritingDirectionToLTR) \
216 macro(changeBaseWritingDirectionToRTL) \
217 macro(changeColor) \
218 macro(changeDocumentBackgroundColor) \
219 macro(changeFont) \
220 macro(changeSpelling) \
221 macro(checkSpelling) \
222 macro(complete) \
223 macro(copy) \
224 macro(copyFont) \
225 macro(cut) \
226 macro(delete) \
227 macro(deleteBackward) \
228 macro(deleteBackwardByDecomposingPreviousCharacter) \
229 macro(deleteForward) \
230 macro(deleteToBeginningOfLine) \
231 macro(deleteToBeginningOfParagraph) \
232 macro(deleteToEndOfLine) \
233 macro(deleteToEndOfParagraph) \
234 macro(deleteToMark) \
235 macro(deleteWordBackward) \
236 macro(deleteWordForward) \
237 macro(ignoreSpelling) \
238 macro(indent) \
239 macro(insertBacktab) \
240 macro(insertLineBreak) \
241 macro(insertNewline) \
242 macro(insertNewlineIgnoringFieldEditor) \
243 macro(insertParagraphSeparator) \
244 macro(insertTab) \
245 macro(insertTabIgnoringFieldEditor) \
246 macro(lowercaseWord) \
247 macro(makeBaseWritingDirectionLeftToRight) \
248 macro(makeBaseWritingDirectionRightToLeft) \
249 macro(makeTextWritingDirectionLeftToRight) \
250 macro(makeTextWritingDirectionNatural) \
251 macro(makeTextWritingDirectionRightToLeft) \
252 macro(moveBackward) \
253 macro(moveBackwardAndModifySelection) \
254 macro(moveDown) \
255 macro(moveDownAndModifySelection) \
256 macro(moveForward) \
257 macro(moveForwardAndModifySelection) \
258 macro(moveLeft) \
259 macro(moveLeftAndModifySelection) \
260 macro(moveParagraphBackwardAndModifySelection) \
261 macro(moveParagraphForwardAndModifySelection) \
262 macro(moveRight) \
263 macro(moveRightAndModifySelection) \
264 macro(moveToBeginningOfDocument) \
265 macro(moveToBeginningOfDocumentAndModifySelection) \
266 macro(moveToBeginningOfLine) \
267 macro(moveToBeginningOfLineAndModifySelection) \
268 macro(moveToBeginningOfParagraph) \
269 macro(moveToBeginningOfParagraphAndModifySelection) \
270 macro(moveToBeginningOfSentence) \
271 macro(moveToBeginningOfSentenceAndModifySelection) \
272 macro(moveToEndOfDocument) \
273 macro(moveToEndOfDocumentAndModifySelection) \
274 macro(moveToEndOfLine) \
275 macro(moveToEndOfLineAndModifySelection) \
276 macro(moveToEndOfParagraph) \
277 macro(moveToEndOfParagraphAndModifySelection) \
278 macro(moveToEndOfSentence) \
279 macro(moveToEndOfSentenceAndModifySelection) \
280 macro(moveToLeftEndOfLine) \
281 macro(moveToLeftEndOfLineAndModifySelection) \
282 macro(moveToRightEndOfLine) \
283 macro(moveToRightEndOfLineAndModifySelection) \
284 macro(moveUp) \
285 macro(moveUpAndModifySelection) \
286 macro(moveWordBackward) \
287 macro(moveWordBackwardAndModifySelection) \
288 macro(moveWordForward) \
289 macro(moveWordForwardAndModifySelection) \
290 macro(moveWordLeft) \
291 macro(moveWordLeftAndModifySelection) \
292 macro(moveWordRight) \
293 macro(moveWordRightAndModifySelection) \
294 macro(outdent) \
295 macro(orderFrontSubstitutionsPanel) \
296 macro(pageDown) \
297 macro(pageDownAndModifySelection) \
298 macro(pageUp) \
299 macro(pageUpAndModifySelection) \
300 macro(paste) \
301 macro(pasteAsPlainText) \
302 macro(pasteAsRichText) \
303 macro(pasteFont) \
304 macro(performFindPanelAction) \
305 macro(scrollLineDown) \
306 macro(scrollLineUp) \
307 macro(scrollPageDown) \
308 macro(scrollPageUp) \
309 macro(scrollToBeginningOfDocument) \
310 macro(scrollToEndOfDocument) \
311 macro(selectAll) \
312 macro(selectLine) \
313 macro(selectParagraph) \
314 macro(selectSentence) \
315 macro(selectToMark) \
316 macro(selectWord) \
317 macro(setMark) \
318 macro(showGuessPanel) \
319 macro(startSpeaking) \
320 macro(stopSpeaking) \
321 macro(subscript) \
322 macro(superscript) \
323 macro(swapWithMark) \
324 macro(takeFindStringFromSelection) \
325 macro(toggleBaseWritingDirection) \
326 macro(transpose) \
327 macro(underline) \
328 macro(unscript) \
329 macro(uppercaseWord) \
330 macro(yank) \
331 macro(yankAndSelect) \
332
333 #define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin"
334 #define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin"
335
336 #define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange"
337 #define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode")
338 #define UniversalAccessDomain CFSTR("com.apple.universalaccess")
339
340 static BOOL s_didSetCacheModel;
341 static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
342
343 #ifndef NDEBUG
344 static const char webViewIsOpen[] = "At least one WebView is still open.";
345 #endif
346
347 @interface NSObject (WebValidateWithoutDelegate)
348 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item;
349 @end
350
351 @interface _WebSafeForwarder : NSObject
352 {
353     id target; // Non-retained. Don't retain delegates.
354     id defaultTarget;
355     BOOL catchExceptions;
356 }
357 - (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions;
358 @end
359
360 @interface WebView (WebFileInternal)
361 - (BOOL)_isLoading;
362 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point;
363 - (WebFrame *)_focusedFrame;
364 + (void)_preflightSpellChecker;
365 - (BOOL)_continuousCheckingAllowed;
366 - (NSResponder *)_responderForResponderOperations;
367 #if USE(ACCELERATED_COMPOSITING)
368 - (void)_clearLayerSyncLoopObserver;
369 #endif
370 @end
371
372 static void patchMailRemoveAttributesMethod();
373
374 NSString *WebElementDOMNodeKey =            @"WebElementDOMNode";
375 NSString *WebElementFrameKey =              @"WebElementFrame";
376 NSString *WebElementImageKey =              @"WebElementImage";
377 NSString *WebElementImageAltStringKey =     @"WebElementImageAltString";
378 NSString *WebElementImageRectKey =          @"WebElementImageRect";
379 NSString *WebElementImageURLKey =           @"WebElementImageURL";
380 NSString *WebElementIsSelectedKey =         @"WebElementIsSelected";
381 NSString *WebElementLinkLabelKey =          @"WebElementLinkLabel";
382 NSString *WebElementLinkTargetFrameKey =    @"WebElementTargetFrame";
383 NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
384 NSString *WebElementLinkURLKey =            @"WebElementLinkURL";
385 NSString *WebElementSpellingToolTipKey =    @"WebElementSpellingToolTip";
386 NSString *WebElementTitleKey =              @"WebElementTitle";
387 NSString *WebElementLinkIsLiveKey =         @"WebElementLinkIsLive";
388 NSString *WebElementIsInScrollBarKey =      @"WebElementIsInScrollBar";
389 NSString *WebElementIsContentEditableKey =  @"WebElementIsContentEditableKey";
390
391 NSString *WebViewProgressStartedNotification =          @"WebProgressStartedNotification";
392 NSString *WebViewProgressEstimateChangedNotification =  @"WebProgressEstimateChangedNotification";
393 NSString *WebViewProgressFinishedNotification =         @"WebProgressFinishedNotification";
394
395 NSString * const WebViewDidBeginEditingNotification =         @"WebViewDidBeginEditingNotification";
396 NSString * const WebViewDidChangeNotification =               @"WebViewDidChangeNotification";
397 NSString * const WebViewDidEndEditingNotification =           @"WebViewDidEndEditingNotification";
398 NSString * const WebViewDidChangeTypingStyleNotification =    @"WebViewDidChangeTypingStyleNotification";
399 NSString * const WebViewDidChangeSelectionNotification =      @"WebViewDidChangeSelectionNotification";
400
401 enum { WebViewVersion = 4 };
402
403 #define timedLayoutSize 4096
404
405 static NSMutableSet *schemesWithRepresentationsSet;
406
407 NSString *_WebCanGoBackKey =            @"canGoBack";
408 NSString *_WebCanGoForwardKey =         @"canGoForward";
409 NSString *_WebEstimatedProgressKey =    @"estimatedProgress";
410 NSString *_WebIsLoadingKey =            @"isLoading";
411 NSString *_WebMainFrameIconKey =        @"mainFrameIcon";
412 NSString *_WebMainFrameTitleKey =       @"mainFrameTitle";
413 NSString *_WebMainFrameURLKey =         @"mainFrameURL";
414 NSString *_WebMainFrameDocumentKey =    @"mainFrameDocument";
415
416 NSString *_WebViewDidStartAcceleratedCompositingNotification = @"_WebViewDidStartAcceleratedCompositing";
417
418 @interface WebProgressItem : NSObject
419 {
420 @public
421     long long bytesReceived;
422     long long estimatedLength;
423 }
424 @end
425
426 @implementation WebProgressItem
427 @end
428
429 static BOOL continuousSpellCheckingEnabled;
430 #ifndef BUILDING_ON_TIGER
431 static BOOL grammarCheckingEnabled;
432 #endif
433 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
434 static BOOL automaticQuoteSubstitutionEnabled;
435 static BOOL automaticLinkDetectionEnabled;
436 static BOOL automaticDashSubstitutionEnabled;
437 static BOOL automaticTextReplacementEnabled;
438 static BOOL automaticSpellingCorrectionEnabled;
439 #endif
440
441 @implementation WebView (AllWebViews)
442
443 static CFSetCallBacks NonRetainingSetCallbacks = {
444     0,
445     NULL,
446     NULL,
447     CFCopyDescription,
448     CFEqual,
449     CFHash
450 };
451
452 static CFMutableSetRef allWebViewsSet;
453
454 + (void)_makeAllWebViewsPerformSelector:(SEL)selector
455 {
456     if (!allWebViewsSet)
457         return;
458
459     [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector];
460 }
461
462 - (void)_removeFromAllWebViewsSet
463 {
464     if (allWebViewsSet)
465         CFSetRemoveValue(allWebViewsSet, self);
466 }
467
468 - (void)_addToAllWebViewsSet
469 {
470     if (!allWebViewsSet)
471         allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks);
472
473     CFSetSetValue(allWebViewsSet, self);
474 }
475
476 @end
477
478 @implementation WebView (WebPrivate)
479
480 static inline int callGestalt(OSType selector)
481 {
482     SInt32 value = 0;
483     Gestalt(selector, &value);
484     return value;
485 }
486
487 // Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4.
488 static NSString *createMacOSXVersionString()
489 {
490     // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want.
491     int major = callGestalt(gestaltSystemVersionMajor);
492     ASSERT(major);
493
494     int minor = callGestalt(gestaltSystemVersionMinor);
495     int bugFix = callGestalt(gestaltSystemVersionBugFix);
496     if (bugFix)
497         return [[NSString alloc] initWithFormat:@"%d_%d_%d", major, minor, bugFix];
498     if (minor)
499         return [[NSString alloc] initWithFormat:@"%d_%d", major, minor];
500     return [[NSString alloc] initWithFormat:@"%d", major];
501 }
502
503 static NSString *createUserVisibleWebKitVersionString()
504 {
505     // If the version is 4 digits long or longer, then the first digit represents
506     // the version of the OS. Our user agent string should not include this first digit,
507     // so strip it off and report the rest as the version. <rdar://problem/4997547>
508     NSString *fullVersion = [[NSBundle bundleForClass:[WebView class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
509     NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
510     if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4)
511         return [[fullVersion substringFromIndex:1] copy];
512     if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4)
513         return [[fullVersion substringFromIndex:1] copy];
514     return [fullVersion copy];
515 }
516
517 + (NSString *)_standardUserAgentWithApplicationName:(NSString *)applicationName
518 {
519     // Note: Do *not* move the initialization of osVersion nor webKitVersion into the declaration.
520     // Garbage collection won't correctly mark the global variable in that case <rdar://problem/5733674>.
521     static NSString *osVersion;
522     static NSString *webKitVersion;
523     if (!osVersion)
524         osVersion = createMacOSXVersionString();
525     if (!webKitVersion)
526         webKitVersion = createUserVisibleWebKitVersionString();
527     NSString *language = [NSUserDefaults _webkit_preferredLanguageCode];
528     if ([applicationName length])
529         return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko) %@", osVersion, language, webKitVersion, applicationName];
530     return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko)", osVersion, language, webKitVersion];
531 }
532
533 static void WebKitInitializeApplicationCachePathIfNecessary()
534 {
535 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
536     static BOOL initialized = NO;
537     if (initialized)
538         return;
539
540     NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
541     if (!appName)
542         appName = [[NSProcessInfo processInfo] processName];
543     
544     ASSERT(appName);
545
546     NSString* cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:appName];
547
548     cacheStorage().setCacheDirectory(cacheDir);
549     initialized = YES;
550 #endif
551 }
552
553 static bool runningLeopardMail()
554 {
555 #ifdef BUILDING_ON_LEOPARD
556     return applicationIsAppleMail();
557 #endif
558     return NO;
559 }
560
561 static bool runningTigerMail()
562 {
563 #ifdef BUILDING_ON_TIGER
564     return applicationIsAppleMail();
565 #endif
566     return NO;    
567 }
568
569 static bool coreVideoHas7228836Fix()
570 {
571 #ifdef BUILDING_ON_LEOPARD
572     NSBundle* coreVideoFrameworkBundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/CoreVideo.framework"];
573     double version = [[coreVideoFrameworkBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] doubleValue];
574     return (version >= 48);
575 #endif
576     return true;
577 }
578
579 static bool shouldEnableLoadDeferring()
580 {
581     return !applicationIsAdobeInstaller();
582 }
583
584 - (void)_dispatchPendingLoadRequests
585 {
586     cache()->loader()->servePendingRequests();
587 }
588
589 - (void)_registerDraggedTypes
590 {
591     NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
592     NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
593     NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
594     [types addObjectsFromArray:URLTypes];
595     [self registerForDraggedTypes:[types allObjects]];
596     [types release];
597 }
598
599 - (BOOL)_usesDocumentViews
600 {
601     return _private->usesDocumentViews;
602 }
603
604 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews
605 {
606     WebCoreThreadViolationCheckRoundTwo();
607
608 #ifndef NDEBUG
609     WTF::RefCountedLeakCounter::suppressMessages(webViewIsOpen);
610 #endif
611     
612     WebPreferences *standardPreferences = [WebPreferences standardPreferences];
613     [standardPreferences willAddToWebView];
614
615     _private->preferences = [standardPreferences retain];
616     _private->catchesDelegateExceptions = YES;
617     _private->mainFrameDocumentReady = NO;
618     _private->drawsBackground = YES;
619     _private->backgroundColor = [[NSColor colorWithDeviceWhite:1 alpha:1] retain];
620     _private->usesDocumentViews = usesDocumentViews;
621     _private->includesFlattenedCompositingLayersWhenDrawingToBitmap = YES;
622
623     WebFrameView *frameView = nil;
624     if (_private->usesDocumentViews) {
625         NSRect f = [self frame];
626         frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
627         [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
628         [self addSubview:frameView];
629         [frameView release];
630     }
631
632     static bool didOneTimeInitialization = false;
633     if (!didOneTimeInitialization) {
634         WebKitInitializeLoggingChannelsIfNecessary();
635         WebCore::InitializeLoggingChannelsIfNecessary();
636         [WebHistoryItem initWindowWatcherIfNecessary];
637 #if ENABLE(DATABASE)
638         WebKitInitializeDatabasesIfNecessary();
639 #endif
640         WebKitInitializeApplicationCachePathIfNecessary();
641         patchMailRemoveAttributesMethod();
642         didOneTimeInitialization = true;
643     }
644
645 #if ENABLE(CLIENT_BASED_GEOLOCATION)
646     WebGeolocationControllerClient* geolocationControllerClient = new WebGeolocationControllerClient(self);
647 #else
648     WebGeolocationControllerClient* geolocationControllerClient = 0;
649 #endif
650     _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self), new WebPluginHalterClient(self), geolocationControllerClient);
651
652     _private->page->setCanStartMedia([self window]);
653     _private->page->settings()->setLocalStorageDatabasePath([[self preferences] _localStorageDatabasePath]);
654
655     [WebFrame _createMainFrameWithPage:_private->page frameName:frameName frameView:frameView];
656
657 #ifndef BUILDING_ON_TIGER
658     NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
659 #else
660     NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
661 #endif
662
663     if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOADING_DURING_COMMON_RUNLOOP_MODES))
664         [self scheduleInRunLoop:runLoop forMode:(NSString *)kCFRunLoopCommonModes];
665     else
666         [self scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode];
667
668     [self _addToAllWebViewsSet];
669     [self setGroupName:groupName];
670     
671     // If there's already a next key view (e.g., from a nib), wire it up to our
672     // contained frame view. In any case, wire our next key view up to the our
673     // contained frame view. This works together with our becomeFirstResponder 
674     // and setNextKeyView overrides.
675     NSView *nextKeyView = [self nextKeyView];
676     if (nextKeyView && nextKeyView != frameView)
677         [frameView setNextKeyView:nextKeyView];
678     [super setNextKeyView:frameView];
679
680     if ([[self class] shouldIncludeInWebKitStatistics])
681         ++WebViewCount;
682
683     [self _registerDraggedTypes];
684
685     WebPreferences *prefs = [self preferences];
686     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
687                                                  name:WebPreferencesChangedNotification object:prefs];
688
689     // Post a notification so the WebCore settings update.
690     [[self preferences] _postPreferencesChangesNotification];
691
692     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION)) {
693         // Originally, we allowed all local loads.
694         SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll);
695     } else if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MORE_STRICT_LOCAL_RESOURCE_SECURITY_RESTRICTION)) {
696         // Later, we allowed local loads for local URLs and documents loaded
697         // with substitute data.
698         SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
699     }
700
701     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_CONTENT_SNIFFING_FOR_FILE_URLS))
702         ResourceHandle::forceContentSniffing();
703 }
704
705 - (id)_initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews
706 {
707     self = [super initWithFrame:f];
708     if (!self)
709         return nil;
710
711 #ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
712     // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
713     // may not work with other WebKit applications.  Unsetting DYLD_FRAMEWORK_PATH removes the
714     // need for Safari to unset it to prevent it from being passed to applications it launches.
715     // Unsetting it when a WebView is first created is as good a place as any.
716     // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details.
717     if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
718         unsetenv("DYLD_FRAMEWORK_PATH");
719         unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
720     }
721 #endif
722
723     _private = [[WebViewPrivate alloc] init];
724     [self _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:usesDocumentViews];
725     [self setMaintainsBackForwardList: YES];
726     return self;
727 }
728
729 - (BOOL)_mustDrawUnionedRect:(NSRect)rect singleRects:(const NSRect *)rects count:(NSInteger)count
730 {
731     // If count == 0 here, use the rect passed in for drawing. This is a workaround for:
732     // <rdar://problem/3908282> REGRESSION (Mail): No drag image dragging selected text in Blot and Mail
733     // The reason for the workaround is that this method is called explicitly from the code
734     // to generate a drag image, and at that time, getRectsBeingDrawn:count: will return a zero count.
735     const int cRectThreshold = 10;
736     const float cWastedSpaceThreshold = 0.75f;
737     BOOL useUnionedRect = (count <= 1) || (count > cRectThreshold);
738     if (!useUnionedRect) {
739         // Attempt to guess whether or not we should use the unioned rect or the individual rects.
740         // We do this by computing the percentage of "wasted space" in the union.  If that wasted space
741         // is too large, then we will do individual rect painting instead.
742         float unionPixels = (rect.size.width * rect.size.height);
743         float singlePixels = 0;
744         for (int i = 0; i < count; ++i)
745             singlePixels += rects[i].size.width * rects[i].size.height;
746         float wastedSpace = 1 - (singlePixels / unionPixels);
747         if (wastedSpace <= cWastedSpaceThreshold)
748             useUnionedRect = YES;
749     }
750     return useUnionedRect;
751 }
752
753 - (void)drawSingleRect:(NSRect)rect
754 {
755     ASSERT(!_private->usesDocumentViews);
756     
757     [NSGraphicsContext saveGraphicsState];
758     NSRectClip(rect);
759
760     @try {
761         [[self mainFrame] _drawRect:rect contentsOnly:NO];
762
763         [[self _UIDelegateForwarder] webView:self didDrawRect:rect];
764
765         if (WebNodeHighlight *currentHighlight = [self currentNodeHighlight])
766             [currentHighlight setNeedsUpdateInTargetViewRect:rect];
767
768         [NSGraphicsContext restoreGraphicsState];
769     } @catch (NSException *localException) {
770         [NSGraphicsContext restoreGraphicsState];
771         LOG_ERROR("Exception caught while drawing: %@", localException);
772         [localException raise];
773     }
774 }
775
776 - (BOOL)isFlipped 
777 {
778     return _private && !_private->usesDocumentViews;
779 }
780
781 - (void)setFrameSize:(NSSize)size
782 {
783     if (!_private->usesDocumentViews && !NSEqualSizes(_private->lastLayoutSize, size)) {
784         Frame* frame = [self _mainCoreFrame];
785         // FIXME: Viewless WebKit is broken with Safari banners (e.g., the Find banner).  We'll have to figure out a way for
786         // Safari to communicate that this space is being consumed.  For WebKit with document views, there's no
787         // need to do an explicit resize, since WebFrameViews have auto resizing turned on and will handle changing
788         // their bounds automatically. See <rdar://problem/6835573> for details.
789         frame->view()->resize(IntSize(size));
790         frame->view()->setNeedsLayout();
791         [self setNeedsDisplay:YES];
792         _private->lastLayoutSize = size;
793     }
794
795     [super setFrameSize:size];
796 }
797
798 #if USE(ACCELERATED_COMPOSITING) || !defined(BUILDING_ON_TIGER)
799
800 - (void)_viewWillDrawInternal
801 {
802     Frame* frame = [self _mainCoreFrame];
803     if (frame && frame->view())
804         frame->view()->layoutIfNeededRecursive();
805 }
806
807 #endif
808
809 #ifndef BUILDING_ON_TIGER
810
811 - (void)viewWillDraw
812 {
813     if (!_private->usesDocumentViews)
814         [self _viewWillDrawInternal];
815     [super viewWillDraw];
816 }
817
818 #endif
819
820
821 - (void)drawRect:(NSRect)rect
822 {
823     if (_private->usesDocumentViews)
824         return [super drawRect:rect];
825     
826     ASSERT_MAIN_THREAD();
827
828     const NSRect *rects;
829     NSInteger count;
830     [self getRectsBeingDrawn:&rects count:&count];
831
832     
833     if ([self _mustDrawUnionedRect:rect singleRects:rects count:count])
834         [self drawSingleRect:rect];
835     else
836         for (int i = 0; i < count; ++i)
837             [self drawSingleRect:rects[i]];
838 }
839
840 + (NSArray *)_supportedMIMETypes
841 {
842     // Load the plug-in DB allowing plug-ins to install types.
843     [WebPluginDatabase sharedDatabase];
844     return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
845 }
846
847 + (NSArray *)_supportedFileExtensions
848 {
849     NSMutableSet *extensions = [[NSMutableSet alloc] init];
850     NSArray *MIMETypes = [self _supportedMIMETypes];
851     NSEnumerator *enumerator = [MIMETypes objectEnumerator];
852     NSString *MIMEType;
853     while ((MIMEType = [enumerator nextObject]) != nil) {
854         NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType);
855         if (extensionsForType) {
856             [extensions addObjectsFromArray:extensionsForType];
857         }
858     }
859     NSArray *uniqueExtensions = [extensions allObjects];
860     [extensions release];
861     return uniqueExtensions;
862 }
863
864 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
865 {
866     MIMEType = [MIMEType lowercaseString];
867     Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
868     Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
869
870     if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) {
871         // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed.
872
873         if (allowPlugins) {
874             // Load the plug-in DB allowing plug-ins to install types.
875             [WebPluginDatabase sharedDatabase];
876         }
877
878         // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
879         viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
880         repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
881     }
882     
883     if (viewClass && repClass) {
884         // Special-case WebHTMLView for text types that shouldn't be shown.
885         if (viewClass == [WebHTMLView class] &&
886             repClass == [WebHTMLRepresentation class] &&
887             [[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) {
888             return NO;
889         }
890         if (vClass)
891             *vClass = viewClass;
892         if (rClass)
893             *rClass = repClass;
894         return YES;
895     }
896     
897     return NO;
898 }
899
900 - (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType
901 {
902     if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType allowingPlugins:[_private->preferences arePlugInsEnabled]])
903         return YES;
904
905     if (_private->pluginDatabase) {
906         WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType];
907         if (pluginPackage) {
908             if (vClass)
909                 *vClass = [WebHTMLView class];
910             if (rClass)
911                 *rClass = [WebHTMLRepresentation class];
912             return YES;
913         }
914     }
915     
916     return NO;
917 }
918
919 + (void)_setAlwaysUseATSU:(BOOL)f
920 {
921     [self _setAlwaysUsesComplexTextCodePath:f];
922 }
923
924 + (void)_setAlwaysUsesComplexTextCodePath:(BOOL)f
925 {
926     Font::setCodePath(f ? Font::Complex : Font::Auto);
927 }
928
929 + (BOOL)canCloseAllWebViews
930 {
931     return DOMWindow::dispatchAllPendingBeforeUnloadEvents();
932 }
933
934 + (void)closeAllWebViews
935 {
936     DOMWindow::dispatchAllPendingUnloadEvents();
937
938     // This will close the WebViews in a random order. Change this if close order is important.
939     // Make a new set to avoid mutating the set we are enumerating.
940     NSSet *webViewsToClose = [NSSet setWithSet:(NSSet *)allWebViewsSet]; 
941     NSEnumerator *enumerator = [webViewsToClose objectEnumerator];
942     while (WebView *webView = [enumerator nextObject])
943         [webView close];
944 }
945
946 + (BOOL)canShowFile:(NSString *)path
947 {
948     return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
949 }
950
951 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
952 {
953     return WKGetPreferredExtensionForMIMEType(type);
954 }
955
956 - (BOOL)_isClosed
957 {
958     return !_private || _private->closed;
959 }
960
961 - (void)_closePluginDatabases
962 {
963     pluginDatabaseClientCount--;
964
965     // Close both sets of plug-in databases because plug-ins need an opportunity to clean up files, etc.
966
967     // Unload the WebView local plug-in database. 
968     if (_private->pluginDatabase) {
969         [_private->pluginDatabase destroyAllPluginInstanceViews];
970         [_private->pluginDatabase close];
971         [_private->pluginDatabase release];
972         _private->pluginDatabase = nil;
973     }
974     
975     // Keep the global plug-in database active until the app terminates to avoid having to reload plug-in bundles.
976     if (!pluginDatabaseClientCount && applicationIsTerminating)
977         [WebPluginDatabase closeSharedDatabase];
978 }
979
980 - (void)_closeWithFastTeardown 
981 {
982 #ifndef NDEBUG
983     WTF::RefCountedLeakCounter::suppressMessages("At least one WebView was closed with fast teardown.");
984 #endif
985
986     [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
987     [[NSNotificationCenter defaultCenter] removeObserver:self];
988
989     [self _closePluginDatabases];
990 }
991
992 static bool fastDocumentTeardownEnabled()
993 {
994 #ifdef NDEBUG
995     static bool enabled = ![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableFullDocumentTeardownPreferenceKey];
996 #else
997     static bool initialized = false;
998     static bool enabled = false;
999     if (!initialized) {
1000         // This allows debug builds to default to not have fast teardown, so leak checking still works.
1001         // But still allow the WebKitEnableFullDocumentTeardown default to override it if present.
1002         NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitEnableFullDocumentTeardownPreferenceKey];
1003         if (setting)
1004             enabled = ![setting boolValue];
1005         initialized = true;
1006     }
1007 #endif
1008     return enabled;
1009 }
1010
1011 // _close is here only for backward compatibility; clients and subclasses should use
1012 // public method -close instead.
1013 - (void)_close
1014 {
1015     if (!_private || _private->closed)
1016         return;
1017
1018     _private->closed = YES;
1019     [self _removeFromAllWebViewsSet];
1020
1021     [self _closingEventHandling];
1022
1023 #ifndef NDEBUG
1024     WTF::RefCountedLeakCounter::cancelMessageSuppression(webViewIsOpen);
1025 #endif
1026
1027     // To quit the apps fast we skip document teardown, except plugins
1028     // need to be destroyed and unloaded.
1029     if (applicationIsTerminating && fastDocumentTeardownEnabled()) {
1030         [self _closeWithFastTeardown];
1031         return;
1032     }
1033
1034 #if ENABLE(VIDEO)
1035     [self _exitFullscreen];
1036 #endif
1037
1038     if (Frame* mainFrame = [self _mainCoreFrame])
1039         mainFrame->loader()->detachFromParent();
1040
1041     [self setHostWindow:nil];
1042
1043     [self setDownloadDelegate:nil];
1044     [self setEditingDelegate:nil];
1045     [self setFrameLoadDelegate:nil];
1046     [self setPolicyDelegate:nil];
1047     [self setResourceLoadDelegate:nil];
1048     [self setScriptDebugDelegate:nil];
1049     [self setUIDelegate:nil];
1050
1051     [_private->inspector webViewClosed];
1052
1053     // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
1054     [self removeDragCaret];
1055
1056     // Deleteing the WebCore::Page will clear the page cache so we call destroy on 
1057     // all the plug-ins in the page cache to break any retain cycles.
1058     // See comment in HistoryItem::releaseAllPendingPageCaches() for more information.
1059     delete _private->page;
1060     _private->page = 0;
1061
1062     if (_private->hasSpellCheckerDocumentTag) {
1063         [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
1064         _private->hasSpellCheckerDocumentTag = NO;
1065     }
1066
1067 #if USE(ACCELERATED_COMPOSITING)
1068     [self _clearLayerSyncLoopObserver];
1069 #endif
1070     
1071     [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
1072     [[NSNotificationCenter defaultCenter] removeObserver:self];
1073
1074     [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]];
1075
1076     WebPreferences *preferences = _private->preferences;
1077     _private->preferences = nil;
1078     [preferences didRemoveFromWebView];
1079     [preferences release];
1080
1081     [self _closePluginDatabases];
1082
1083 #ifndef NDEBUG
1084     // Need this to make leak messages accurate.
1085     if (applicationIsTerminating) {
1086         gcController().garbageCollectNow();
1087         [WebCache setDisabled:YES];
1088     }
1089 #endif
1090 }
1091
1092 // Indicates if the WebView is in the midst of a user gesture.
1093 - (BOOL)_isProcessingUserGesture
1094 {
1095     WebFrame *frame = [self mainFrame];
1096     return core(frame)->loader()->isProcessingUserGesture();
1097 }
1098
1099 + (NSString *)_MIMETypeForFile:(NSString *)path
1100 {
1101     NSString *extension = [path pathExtension];
1102     NSString *MIMEType = nil;
1103
1104     // Get the MIME type from the extension.
1105     if ([extension length] != 0) {
1106         MIMEType = WKGetMIMETypeForExtension(extension);
1107     }
1108
1109     // If we can't get a known MIME type from the extension, sniff.
1110     if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
1111         NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
1112         NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
1113         [handle closeFile];
1114         if ([data length] != 0) {
1115             MIMEType = [data _webkit_guessedMIMEType];
1116         }
1117         if ([MIMEType length] == 0) {
1118             MIMEType = @"application/octet-stream";
1119         }
1120     }
1121
1122     return MIMEType;
1123 }
1124
1125 - (WebDownload *)_downloadURL:(NSURL *)URL
1126 {
1127     ASSERT(URL);
1128     
1129     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
1130     WebDownload *download = [WebDownload _downloadWithRequest:request
1131                                                      delegate:_private->downloadDelegate
1132                                                     directory:nil];
1133     [request release];
1134     
1135     return download;
1136 }
1137
1138 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
1139 {
1140     NSDictionary *features = [[NSDictionary alloc] init];
1141     WebView *newWindowWebView = [[self _UIDelegateForwarder] webView:self
1142                                             createWebViewWithRequest:nil
1143                                                       windowFeatures:features];
1144     [features release];
1145     if (!newWindowWebView)
1146         return nil;
1147
1148     CallUIDelegate(newWindowWebView, @selector(webViewShow:));
1149     return newWindowWebView;
1150 }
1151
1152 - (WebInspector *)inspector
1153 {
1154     if (!_private->inspector)
1155         _private->inspector = [[WebInspector alloc] initWithWebView:self];
1156     return _private->inspector;
1157 }
1158
1159 - (WebCore::Page*)page
1160 {
1161     return _private->page;
1162 }
1163
1164 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items
1165 {
1166     NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate] webView:self contextMenuItemsForElement:element defaultMenuItems:items];
1167
1168     NSArray *menuItems = CallUIDelegate(self, @selector(webView:contextMenuItemsForElement:defaultMenuItems:), element, defaultMenuItems);
1169     if (!menuItems)
1170         return nil;
1171
1172     unsigned count = [menuItems count];
1173     if (!count)
1174         return nil;
1175
1176     NSMenu *menu = [[NSMenu alloc] init];
1177     for (unsigned i = 0; i < count; i++)
1178         [menu addItem:[menuItems objectAtIndex:i]];
1179
1180     return [menu autorelease];
1181 }
1182
1183 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(NSUInteger)modifierFlags
1184 {
1185     // We originally intended to call this delegate method sometimes with a nil dictionary, but due to
1186     // a bug dating back to WebKit 1.0 this delegate was never called with nil! Unfortunately we can't
1187     // start calling this with nil since it will break Adobe Help Viewer, and possibly other clients.
1188     if (!dictionary)
1189         return;
1190     CallUIDelegate(self, @selector(webView:mouseDidMoveOverElement:modifierFlags:), dictionary, modifierFlags);
1191 }
1192
1193 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
1194 {
1195     if (!_private->page)
1196         return;
1197     
1198     if (!otherView->_private->page)
1199         return;
1200     
1201     // It turns out the right combination of behavior is done with the back/forward load
1202     // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
1203     // in the back forward list, and go to the current one.
1204
1205     BackForwardList* backForwardList = _private->page->backForwardList();
1206     ASSERT(!backForwardList->currentItem()); // destination list should be empty
1207
1208     BackForwardList* otherBackForwardList = otherView->_private->page->backForwardList();
1209     if (!otherBackForwardList->currentItem())
1210         return; // empty back forward list, bail
1211     
1212     HistoryItem* newItemToGoTo = 0;
1213
1214     int lastItemIndex = otherBackForwardList->forwardListCount();
1215     for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) {
1216         if (i == 0) {
1217             // If this item is showing , save away its current scroll and form state,
1218             // since that might have changed since loading and it is normally not saved
1219             // until we leave that page.
1220             otherView->_private->page->mainFrame()->loader()->history()->saveDocumentAndScrollState();
1221         }
1222         RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy();
1223         if (i == 0) 
1224             newItemToGoTo = newItem.get();
1225         backForwardList->addItem(newItem.release());
1226     }
1227     
1228     ASSERT(newItemToGoTo);
1229     _private->page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward);
1230 }
1231
1232 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
1233 {
1234     _private->formDelegate = delegate;
1235 }
1236
1237 - (id<WebFormDelegate>)_formDelegate
1238 {
1239     return _private->formDelegate;
1240 }
1241
1242 - (BOOL)_needsAdobeFrameReloadingQuirk
1243 {
1244     static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0)
1245         || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0)
1246         || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0)
1247         || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0)
1248         || WKAppVersionCheckLessThan(@"com.adobe.Contribute", -1, 4.2)
1249         || WKAppVersionCheckLessThan(@"com.adobe.dreamweaver-9.0", -1, 9.1)
1250         || WKAppVersionCheckLessThan(@"com.macromedia.fireworks", -1, 9.1)
1251         || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1)
1252         || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1)
1253         || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2);
1254
1255     return needsQuirk;
1256 }
1257
1258 - (BOOL)_needsLinkElementTextCSSQuirk
1259 {
1260     static BOOL needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LINK_ELEMENT_TEXT_CSS_QUIRK)
1261         && WKAppVersionCheckLessThan(@"com.e-frontier.shade10", -1, 10.6);
1262     return needsQuirk;
1263 }
1264
1265 - (BOOL)_needsKeyboardEventDisambiguationQuirks
1266 {
1267     static BOOL needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) && !applicationIsSafari();
1268     return needsQuirks;
1269 }
1270
1271 - (BOOL)_needsFrameLoadDelegateRetainQuirk
1272 {
1273     static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.equinux.iSale5", -1, 5.6);    
1274     return needsQuirk;
1275 }
1276
1277 - (void)_preferencesChangedNotification:(NSNotification *)notification
1278 {
1279     WebPreferences *preferences = (WebPreferences *)[notification object];
1280     ASSERT(preferences == [self preferences]);
1281     
1282     if (!_private->userAgentOverridden)
1283         _private->userAgent = String();
1284
1285     // Cache this value so we don't have to read NSUserDefaults on each page load
1286     _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing];
1287
1288     // Update corresponding WebCore Settings object.
1289     if (!_private->page)
1290         return;
1291     
1292     Settings* settings = _private->page->settings();
1293     
1294     settings->setCursiveFontFamily([preferences cursiveFontFamily]);
1295     settings->setDefaultFixedFontSize([preferences defaultFixedFontSize]);
1296     settings->setDefaultFontSize([preferences defaultFontSize]);
1297     settings->setDefaultTextEncodingName([preferences defaultTextEncodingName]);
1298     settings->setUsesEncodingDetector([preferences usesEncodingDetector]);
1299     settings->setFantasyFontFamily([preferences fantasyFontFamily]);
1300     settings->setFixedFontFamily([preferences fixedFontFamily]);
1301     settings->setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]);
1302     settings->setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]);
1303     settings->setLocalStorageDatabasePath([preferences _localStorageDatabasePath]);
1304     settings->setJavaEnabled([preferences isJavaEnabled]);
1305     settings->setJavaScriptEnabled([preferences isJavaScriptEnabled]);
1306     settings->setWebSecurityEnabled([preferences isWebSecurityEnabled]);
1307     settings->setAllowUniversalAccessFromFileURLs([preferences allowUniversalAccessFromFileURLs]);
1308     settings->setAllowFileAccessFromFileURLs([preferences allowFileAccessFromFileURLs]);
1309     settings->setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]);
1310     settings->setMinimumFontSize([preferences minimumFontSize]);
1311     settings->setMinimumLogicalFontSize([preferences minimumLogicalFontSize]);
1312     settings->setPluginsEnabled([preferences arePlugInsEnabled]);
1313 #if ENABLE(DATABASE)
1314     Database::setIsAvailable([preferences databasesEnabled]);
1315 #endif
1316     settings->setLocalStorageEnabled([preferences localStorageEnabled]);
1317     settings->setExperimentalNotificationsEnabled([preferences experimentalNotificationsEnabled]);
1318     settings->setPrivateBrowsingEnabled([preferences privateBrowsingEnabled]);
1319     settings->setSansSerifFontFamily([preferences sansSerifFontFamily]);
1320     settings->setSerifFontFamily([preferences serifFontFamily]);
1321     settings->setStandardFontFamily([preferences standardFontFamily]);
1322     settings->setLoadsImagesAutomatically([preferences loadsImagesAutomatically]);
1323     settings->setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]);
1324     settings->setTextAreasAreResizable([preferences textAreasAreResizable]);
1325     settings->setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]);
1326     settings->setEditableLinkBehavior(core([preferences editableLinkBehavior]));
1327     settings->setTextDirectionSubmenuInclusionBehavior(core([preferences textDirectionSubmenuInclusionBehavior]));
1328     settings->setDOMPasteAllowed([preferences isDOMPasteAllowed]);
1329     settings->setUsesPageCache([self usesPageCache]);
1330     settings->setShowsURLsInToolTips([preferences showsURLsInToolTips]);
1331     settings->setDeveloperExtrasEnabled([preferences developerExtrasEnabled]);
1332     settings->setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]);
1333     settings->setApplicationChromeMode([preferences applicationChromeModeEnabled]);
1334     if ([preferences userStyleSheetEnabled]) {
1335         NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString];
1336         if ([location isEqualToString:@"apple-dashboard://stylesheet"])
1337             location = @"file:///System/Library/PrivateFrameworks/DashboardClient.framework/Resources/widget.css";
1338         settings->setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]);
1339     } else
1340         settings->setUserStyleSheetLocation([NSURL URLWithString:@""]);
1341     settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]);
1342     settings->setTreatsAnyTextCSSLinkAsStylesheet([self _needsLinkElementTextCSSQuirk]);
1343     settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]);
1344     settings->setNeedsLeopardMailQuirks(runningLeopardMail());
1345     settings->setNeedsTigerMailQuirks(runningTigerMail());
1346     settings->setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing);
1347     settings->setWebArchiveDebugModeEnabled([preferences webArchiveDebugModeEnabled]);
1348     settings->setLocalFileContentSniffingEnabled([preferences localFileContentSniffingEnabled]);
1349     settings->setOfflineWebApplicationCacheEnabled([preferences offlineWebApplicationCacheEnabled]);
1350     settings->setZoomMode([preferences zoomsTextOnly] ? ZoomTextOnly : ZoomPage);
1351     settings->setJavaScriptCanAccessClipboard([preferences javaScriptCanAccessClipboard]);
1352     settings->setXSSAuditorEnabled([preferences isXSSAuditorEnabled]);
1353     settings->setEnforceCSSMIMETypeInStrictMode(!WKAppVersionCheckLessThan(@"com.apple.iWeb", -1, 2.1));
1354     
1355     // FIXME: Enabling accelerated compositing when WebGL is enabled causes tests to fail on Leopard which expect HW compositing to be disabled.
1356     // Until we fix that, I will comment out the test (CFM)
1357     settings->setAcceleratedCompositingEnabled((coreVideoHas7228836Fix() || [preferences webGLEnabled]) && [preferences acceleratedCompositingEnabled]);
1358     settings->setShowDebugBorders([preferences showDebugBorders]);
1359     settings->setShowRepaintCounter([preferences showRepaintCounter]);
1360     settings->setPluginAllowedRunTime([preferences pluginAllowedRunTime]);
1361     settings->setWebGLEnabled([preferences webGLEnabled]);
1362     settings->setLoadDeferringEnabled(shouldEnableLoadDeferring());
1363     settings->setFrameFlatteningEnabled([preferences isFrameFlatteningEnabled]);
1364 }
1365
1366 static inline IMP getMethod(id o, SEL s)
1367 {
1368     return [o respondsToSelector:s] ? [o methodForSelector:s] : 0;
1369 }
1370
1371 - (void)_cacheResourceLoadDelegateImplementations
1372 {
1373     WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
1374     id delegate = _private->resourceProgressDelegate;
1375
1376     if (!delegate) {
1377         bzero(cache, sizeof(WebResourceDelegateImplementationCache));
1378         return;
1379     }
1380
1381     cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
1382     cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:));
1383     cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:));
1384     cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:));
1385     cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
1386 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
1387     cache->canAuthenticateAgainstProtectionSpaceFunc = getMethod(delegate, @selector(webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource:));
1388 #endif
1389     cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:));
1390     cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:));
1391     cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:));
1392     cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:));
1393     cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:));
1394     cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:));
1395     cache->shouldUseCredentialStorageFunc = getMethod(delegate, @selector(webView:resource:shouldUseCredentialStorageForDataSource:));
1396 }
1397
1398 - (void)_cacheFrameLoadDelegateImplementations
1399 {
1400     WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations;
1401     id delegate = _private->frameLoadDelegate;
1402
1403     if (!delegate) {
1404         bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache));
1405         return;
1406     }
1407
1408     cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:));
1409     cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:));
1410     cache->didPushStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPushStateWithinPageForFrame:));
1411     cache->didReplaceStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didReplaceStateWithinPageForFrame:));
1412     cache->didPopStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPopStateWithinPageForFrame:));
1413     cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:));
1414     cache->didClearWindowObjectForFrameInScriptWorldFunc = getMethod(delegate, @selector(webView:didClearWindowObjectForFrame:inScriptWorld:));
1415     cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:));
1416     cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:));
1417     cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:));
1418     cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:));
1419     cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:));
1420     cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:));
1421     cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:));
1422     cache->didFirstVisuallyNonEmptyLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:));
1423     cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:));
1424     cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:));
1425     cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:));
1426     cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:));
1427     cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:));
1428     cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:));
1429     cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:));
1430     cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:));
1431     cache->didDisplayInsecureContentFunc = getMethod(delegate, @selector(webViewDidDisplayInsecureContent:));
1432     cache->didRunInsecureContentFunc = getMethod(delegate, @selector(webView:didRunInsecureContent:));
1433 }
1434
1435 - (void)_cacheScriptDebugDelegateImplementations
1436 {
1437     WebScriptDebugDelegateImplementationCache *cache = &_private->scriptDebugDelegateImplementations;
1438     id delegate = _private->scriptDebugDelegate;
1439
1440     if (!delegate) {
1441         bzero(cache, sizeof(WebScriptDebugDelegateImplementationCache));
1442         return;
1443     }
1444
1445     cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:));
1446     if (cache->didParseSourceFunc)
1447         cache->didParseSourceExpectsBaseLineNumber = YES;
1448     else
1449         cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:));
1450
1451     cache->failedToParseSourceFunc = getMethod(delegate, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:));
1452     cache->didEnterCallFrameFunc = getMethod(delegate, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:));
1453     cache->willExecuteStatementFunc = getMethod(delegate, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:));
1454     cache->willLeaveCallFrameFunc = getMethod(delegate, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:));
1455     cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:));
1456 }
1457
1458 - (void)_cacheHistoryDelegateImplementations
1459 {
1460     WebHistoryDelegateImplementationCache *cache = &_private->historyDelegateImplementations;
1461     id delegate = _private->historyDelegate;
1462
1463     if (!delegate) {
1464         bzero(cache, sizeof(WebHistoryDelegateImplementationCache));
1465         return;
1466     }
1467
1468     cache->navigatedFunc = getMethod(delegate, @selector(webView:didNavigateWithNavigationData:inFrame:));
1469     cache->clientRedirectFunc = getMethod(delegate, @selector(webView:didPerformClientRedirectFromURL:toURL:inFrame:));
1470     cache->serverRedirectFunc = getMethod(delegate, @selector(webView:didPerformServerRedirectFromURL:toURL:inFrame:));
1471     cache->setTitleFunc = getMethod(delegate, @selector(webView:updateHistoryTitle:forURL:));
1472     cache->populateVisitedLinksFunc = getMethod(delegate, @selector(populateVisitedLinksForWebView:));
1473 }
1474
1475 - (id)_policyDelegateForwarder
1476 {
1477     if (!_private->policyDelegateForwarder)
1478         _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate] catchExceptions:_private->catchesDelegateExceptions];
1479     return _private->policyDelegateForwarder;
1480 }
1481
1482 - (id)_UIDelegateForwarder
1483 {
1484     if (!_private->UIDelegateForwarder)
1485         _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate] catchExceptions:_private->catchesDelegateExceptions];
1486     return _private->UIDelegateForwarder;
1487 }
1488
1489 - (id)_editingDelegateForwarder
1490 {
1491     // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
1492     // Not sure if that is a bug or not.
1493     if (!_private)
1494         return nil;
1495
1496     if (!_private->editingDelegateForwarder)
1497         _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate] catchExceptions:_private->catchesDelegateExceptions];
1498     return _private->editingDelegateForwarder;
1499 }
1500
1501 - (void)_closeWindow
1502 {
1503     [[self _UIDelegateForwarder] webViewClose:self];
1504 }
1505
1506 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType
1507 {
1508     [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
1509     [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
1510     
1511     // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
1512     // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
1513     // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
1514     MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType);
1515 }
1516
1517 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme
1518 {
1519     NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
1520     [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
1521
1522     // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
1523     // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
1524     // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
1525     if ([viewClass class] == [WebHTMLView class])
1526         MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
1527     
1528     // This is used to make _representationExistsForURLScheme faster.
1529     // Without this set, we'd have to create the MIME type each time.
1530     if (schemesWithRepresentationsSet == nil) {
1531         schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
1532     }
1533     [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
1534 }
1535
1536 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1537 {
1538     return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
1539 }
1540
1541 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1542 {
1543     return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
1544 }
1545
1546 + (BOOL)_canHandleRequest:(NSURLRequest *)request forMainFrame:(BOOL)forMainFrame
1547 {
1548     // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed.
1549     if (!request)
1550         return NO;
1551
1552     if ([NSURLConnection canHandleRequest:request])
1553         return YES;
1554
1555     NSString *scheme = [[request URL] scheme];
1556
1557     // Representations for URL schemes work at the top level.
1558     if (forMainFrame && [self _representationExistsForURLScheme:scheme])
1559         return YES;
1560         
1561     return [scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"];
1562 }
1563
1564 + (BOOL)_canHandleRequest:(NSURLRequest *)request
1565 {
1566     return [self _canHandleRequest:request forMainFrame:YES];
1567 }
1568
1569 + (NSString *)_decodeData:(NSData *)data
1570 {
1571     HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet
1572     RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/html"); // bookmark files are HTML
1573     String result = decoder->decode(static_cast<const char*>([data bytes]), [data length]);
1574     result += decoder->flush();
1575     return result;
1576 }
1577
1578 - (void)_pushPerformingProgrammaticFocus
1579 {
1580     _private->programmaticFocusCount++;
1581 }
1582
1583 - (void)_popPerformingProgrammaticFocus
1584 {
1585     _private->programmaticFocusCount--;
1586 }
1587
1588 - (BOOL)_isPerformingProgrammaticFocus
1589 {
1590     return _private->programmaticFocusCount != 0;
1591 }
1592
1593 - (void)_didChangeValueForKey: (NSString *)key
1594 {
1595     LOG (Bindings, "calling didChangeValueForKey: %@", key);
1596     [self didChangeValueForKey: key];
1597 }
1598
1599 - (void)_willChangeValueForKey: (NSString *)key
1600 {
1601     LOG (Bindings, "calling willChangeValueForKey: %@", key);
1602     [self willChangeValueForKey: key];
1603 }
1604
1605 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1606     static NSSet *manualNotifyKeys = nil;
1607     if (!manualNotifyKeys)
1608         manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
1609             _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey,
1610             nil];
1611     if ([manualNotifyKeys containsObject:key])
1612         return NO;
1613     return YES;
1614 }
1615
1616 - (NSArray *)_declaredKeys {
1617     static NSArray *declaredKeys = nil;
1618     if (!declaredKeys)
1619         declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
1620             _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1621     return declaredKeys;
1622 }
1623
1624 - (void)setObservationInfo:(void *)info
1625 {
1626     _private->observationInfo = info;
1627 }
1628
1629 - (void *)observationInfo
1630 {
1631     return _private->observationInfo;
1632 }
1633
1634 - (void)_willChangeBackForwardKeys
1635 {
1636     [self _willChangeValueForKey: _WebCanGoBackKey];
1637     [self _willChangeValueForKey: _WebCanGoForwardKey];
1638 }
1639
1640 - (void)_didChangeBackForwardKeys
1641 {
1642     [self _didChangeValueForKey: _WebCanGoBackKey];
1643     [self _didChangeValueForKey: _WebCanGoForwardKey];
1644 }
1645
1646 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1647 {
1648     [self _willChangeBackForwardKeys];
1649     if (frame == [self mainFrame]){
1650         // Force an observer update by sending a will/did.
1651         [self _willChangeValueForKey: _WebIsLoadingKey];
1652         [self _didChangeValueForKey: _WebIsLoadingKey];
1653
1654         [self _willChangeValueForKey: _WebMainFrameURLKey];
1655     }
1656
1657     [NSApp setWindowsNeedUpdate:YES];
1658 }
1659
1660 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1661 {
1662     if (frame == [self mainFrame])
1663         [self _didChangeValueForKey: _WebMainFrameURLKey];
1664     [NSApp setWindowsNeedUpdate:YES];
1665 }
1666
1667 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1668 {
1669     [self _didChangeBackForwardKeys];
1670     if (frame == [self mainFrame]){
1671         // Force an observer update by sending a will/did.
1672         [self _willChangeValueForKey: _WebIsLoadingKey];
1673         [self _didChangeValueForKey: _WebIsLoadingKey];
1674     }
1675     [NSApp setWindowsNeedUpdate:YES];
1676 }
1677
1678 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1679 {
1680     [self _didChangeBackForwardKeys];
1681     if (frame == [self mainFrame]){
1682         // Force an observer update by sending a will/did.
1683         [self _willChangeValueForKey: _WebIsLoadingKey];
1684         [self _didChangeValueForKey: _WebIsLoadingKey];
1685     }
1686     [NSApp setWindowsNeedUpdate:YES];
1687 }
1688
1689 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1690 {
1691     [self _didChangeBackForwardKeys];
1692     if (frame == [self mainFrame]){
1693         // Force an observer update by sending a will/did.
1694         [self _willChangeValueForKey: _WebIsLoadingKey];
1695         [self _didChangeValueForKey: _WebIsLoadingKey];
1696         
1697         [self _didChangeValueForKey: _WebMainFrameURLKey];
1698     }
1699     [NSApp setWindowsNeedUpdate:YES];
1700 }
1701
1702 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1703 {
1704     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1705     [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1706     NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1707     [request release];
1708     return cachedResponse;
1709 }
1710
1711 - (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1712 {
1713     NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1714     DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey];
1715     [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey])
1716                         element:domElement
1717                             URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
1718                           title:[element objectForKey:WebElementImageAltStringKey] 
1719                         archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1720                           types:types
1721                          source:nil];
1722 }
1723
1724 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1725 {
1726     [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1727                      andTitle:[element objectForKey:WebElementLinkLabelKey]
1728                         types:types];
1729 }
1730
1731 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1732 {
1733     if (!_private->page)
1734         return;
1735     _private->page->dragController()->setDidInitiateDrag(initiatedDrag);
1736 }
1737
1738 #if ENABLE(DASHBOARD_SUPPORT)
1739
1740 #define DASHBOARD_CONTROL_LABEL @"control"
1741
1742 - (void)_addControlRect:(NSRect)bounds clip:(NSRect)clip fromView:(NSView *)view toDashboardRegions:(NSMutableDictionary *)regions
1743 {
1744     NSRect adjustedBounds = bounds;
1745     adjustedBounds.origin = [self convertPoint:bounds.origin fromView:view];
1746     adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1747     adjustedBounds.size = bounds.size;
1748
1749     NSRect adjustedClip;
1750     adjustedClip.origin = [self convertPoint:clip.origin fromView:view];
1751     adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1752     adjustedClip.size = clip.size;
1753
1754     WebDashboardRegion *region = [[WebDashboardRegion alloc] initWithRect:adjustedBounds 
1755         clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle];
1756     NSMutableArray *scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1757     if (!scrollerRegions) {
1758         scrollerRegions = [[NSMutableArray alloc] init];
1759         [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1760         [scrollerRegions release];
1761     }
1762     [scrollerRegions addObject:region];
1763     [region release];
1764 }
1765
1766 - (void)_addScrollerDashboardRegionsForFrameView:(FrameView*)frameView dashboardRegions:(NSMutableDictionary *)regions
1767 {    
1768     NSView *documentView = [[kit(frameView->frame()) frameView] documentView];
1769
1770     const HashSet<RefPtr<Widget> >* children = frameView->children();
1771     HashSet<RefPtr<Widget> >::const_iterator end = children->end();
1772     for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
1773         Widget* widget = (*it).get();
1774         if (widget->isFrameView()) {
1775             [self _addScrollerDashboardRegionsForFrameView:static_cast<FrameView*>(widget) dashboardRegions:regions];
1776             continue;
1777         }
1778
1779         if (!widget->isScrollbar())
1780             continue;
1781
1782         // FIXME: This should really pass an appropriate clip, but our first try got it wrong, and
1783         // it's not common to need this to be correct in Dashboard widgets.
1784         NSRect bounds = widget->frameRect();
1785         [self _addControlRect:bounds clip:bounds fromView:documentView toDashboardRegions:regions];
1786     }
1787 }
1788
1789 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1790 {
1791     // Add scroller regions for NSScroller and WebCore scrollbars
1792     NSUInteger count = [views count];
1793     for (NSUInteger i = 0; i < count; i++) {
1794         NSView *view = [views objectAtIndex:i];
1795         
1796         if ([view isKindOfClass:[WebHTMLView class]]) {
1797             if (Frame* coreFrame = core([(WebHTMLView*)view _frame])) {
1798                 if (FrameView* coreView = coreFrame->view())
1799                     [self _addScrollerDashboardRegionsForFrameView:coreView dashboardRegions:regions];
1800             }
1801         } else if ([view isKindOfClass:[NSScroller class]]) {
1802             // AppKit places absent scrollers at -100,-100
1803             if ([view frame].origin.y < 0)
1804                 continue;
1805             [self _addControlRect:[view bounds] clip:[view visibleRect] fromView:view toDashboardRegions:regions];
1806         }
1807         [self _addScrollerDashboardRegions:regions from:[view subviews]];
1808     }
1809 }
1810
1811 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1812 {
1813     [self _addScrollerDashboardRegions:regions from:[self subviews]];
1814 }
1815
1816 - (NSDictionary *)_dashboardRegions
1817 {
1818     // Only return regions from main frame.
1819     Frame* mainFrame = [self _mainCoreFrame];
1820     if (!mainFrame)
1821         return nil;
1822     NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary();
1823     [self _addScrollerDashboardRegions:regions];
1824     return regions;
1825 }
1826
1827 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag
1828 {
1829     // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement 
1830     // specific support for the backward compatibility mode flag.
1831     if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page)
1832         _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(true);
1833     
1834     switch (behavior) {
1835         case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1836             _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1837             break;
1838         }
1839         case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1840             _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1841             break;
1842         }
1843         case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1844             _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1845             break;
1846         }
1847         case WebDashboardBehaviorAllowWheelScrolling: {
1848             _private->dashboardBehaviorAllowWheelScrolling = flag;
1849             break;
1850         }
1851         case WebDashboardBehaviorUseBackwardCompatibilityMode: {
1852             if (_private->page)
1853                 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(flag);
1854             break;
1855         }
1856     }
1857 }
1858
1859 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1860 {
1861     switch (behavior) {
1862         case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1863             return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1864         }
1865         case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1866             return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1867         }
1868         case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1869             return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1870         }
1871         case WebDashboardBehaviorAllowWheelScrolling: {
1872             return _private->dashboardBehaviorAllowWheelScrolling;
1873         }
1874         case WebDashboardBehaviorUseBackwardCompatibilityMode: {
1875             return _private->page && _private->page->settings()->usesDashboardBackwardCompatibilityMode();
1876         }
1877     }
1878     return NO;
1879 }
1880
1881 #endif /* ENABLE(DASHBOARD_SUPPORT) */
1882
1883 + (void)_setShouldUseFontSmoothing:(BOOL)f
1884 {
1885     Font::setShouldUseSmoothing(f);
1886 }
1887
1888 + (BOOL)_shouldUseFontSmoothing
1889 {
1890     return Font::shouldUseSmoothing();
1891 }
1892
1893 + (void)_setUsesTestModeFocusRingColor:(BOOL)f
1894 {
1895     setUsesTestModeFocusRingColor(f);
1896 }
1897
1898 + (BOOL)_usesTestModeFocusRingColor
1899 {
1900     return usesTestModeFocusRingColor();
1901 }
1902
1903 - (void)setAlwaysShowVerticalScroller:(BOOL)flag
1904 {
1905     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1906     if (flag) {
1907         [scrollview setVerticalScrollingMode:ScrollbarAlwaysOn andLock:YES];
1908     } else {
1909         [scrollview setVerticalScrollingModeLocked:NO];
1910         [scrollview setVerticalScrollingMode:ScrollbarAuto andLock:NO];
1911     }
1912 }
1913
1914 - (BOOL)alwaysShowVerticalScroller
1915 {
1916     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1917     return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == ScrollbarAlwaysOn;
1918 }
1919
1920 - (void)setAlwaysShowHorizontalScroller:(BOOL)flag
1921 {
1922     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1923     if (flag) {
1924         [scrollview setHorizontalScrollingMode:ScrollbarAlwaysOn andLock:YES];
1925     } else {
1926         [scrollview setHorizontalScrollingModeLocked:NO];
1927         [scrollview setHorizontalScrollingMode:ScrollbarAuto andLock:NO];
1928     }
1929 }
1930
1931 - (void)setProhibitsMainFrameScrolling:(BOOL)prohibits
1932 {
1933     if (Frame* mainFrame = [self _mainCoreFrame])
1934         mainFrame->view()->setProhibitsScrolling(prohibits);
1935 }
1936
1937 - (BOOL)alwaysShowHorizontalScroller
1938 {
1939     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1940     return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == ScrollbarAlwaysOn;
1941 }
1942
1943 - (void)_setInViewSourceMode:(BOOL)flag
1944 {
1945     if (Frame* mainFrame = [self _mainCoreFrame])
1946         mainFrame->setInViewSourceMode(flag);
1947 }
1948
1949 - (BOOL)_inViewSourceMode
1950 {
1951     Frame* mainFrame = [self _mainCoreFrame];
1952     return mainFrame && mainFrame->inViewSourceMode();
1953 }
1954
1955 - (void)_setUseFastImageScalingMode:(BOOL)flag
1956 {
1957     if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) {
1958         _private->page->setInLowQualityImageInterpolationMode(flag);
1959         [self setNeedsDisplay:YES];
1960     }
1961 }
1962
1963 - (BOOL)_inFastImageScalingMode
1964 {
1965     if (_private->page)
1966         return _private->page->inLowQualityImageInterpolationMode();
1967     return NO;
1968 }
1969
1970 - (BOOL)_cookieEnabled
1971 {
1972     if (_private->page)
1973         return _private->page->cookieEnabled();
1974     return YES;
1975 }
1976
1977 - (void)_setCookieEnabled:(BOOL)enable
1978 {
1979     if (_private->page)
1980         _private->page->setCookieEnabled(enable);
1981 }
1982
1983 - (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
1984 {
1985     if (!_private->pluginDatabase)
1986         _private->pluginDatabase = [[WebPluginDatabase alloc] init];
1987         
1988     [_private->pluginDatabase setPlugInPaths:newPaths];
1989     [_private->pluginDatabase refresh];
1990 }
1991
1992 - (void)_attachScriptDebuggerToAllFrames
1993 {
1994     for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext())
1995         [kit(frame) _attachScriptDebugger];
1996 }
1997
1998 - (void)_detachScriptDebuggerFromAllFrames
1999 {
2000     for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext())
2001         [kit(frame) _detachScriptDebugger];
2002 }
2003
2004 - (void)setBackgroundColor:(NSColor *)backgroundColor
2005 {
2006     if ([_private->backgroundColor isEqual:backgroundColor])
2007         return;
2008
2009     id old = _private->backgroundColor;
2010     _private->backgroundColor = [backgroundColor retain];
2011     [old release];
2012
2013     [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
2014 }
2015
2016 - (NSColor *)backgroundColor
2017 {
2018     return _private->backgroundColor;
2019 }
2020
2021 - (BOOL)defersCallbacks
2022 {
2023     if (!_private->page)
2024         return NO;
2025     return _private->page->defersLoading();
2026 }
2027
2028 - (void)setDefersCallbacks:(BOOL)defer
2029 {
2030     if (!_private->page)
2031         return;
2032     return _private->page->setDefersLoading(defer);
2033 }
2034
2035 // For backwards compatibility with the WebBackForwardList API, we honor both
2036 // a per-WebView and a per-preferences setting for whether to use the page cache.
2037
2038 - (BOOL)usesPageCache
2039 {
2040     return _private->usesPageCache && [[self preferences] usesPageCache];
2041 }
2042
2043 - (void)setUsesPageCache:(BOOL)usesPageCache
2044 {
2045     _private->usesPageCache = usesPageCache;
2046
2047     // Post a notification so the WebCore settings update.
2048     [[self preferences] _postPreferencesChangesNotification];
2049 }
2050
2051 - (WebHistoryItem *)_globalHistoryItem
2052 {
2053     if (!_private->page)
2054         return nil;
2055     return kit(_private->page->globalHistoryItem());
2056 }
2057
2058 - (WebTextIterator *)textIteratorForRect:(NSRect)rect
2059 {
2060     IntPoint rectStart(rect.origin.x, rect.origin.y);
2061     IntPoint rectEnd(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
2062     
2063     Frame* coreFrame = [self _mainCoreFrame];
2064     if (!coreFrame)
2065         return nil;
2066     
2067     VisibleSelection selectionInsideRect(coreFrame->visiblePositionForPoint(rectStart), coreFrame->visiblePositionForPoint(rectEnd));
2068     
2069     return [[[WebTextIterator alloc] initWithRange:kit(selectionInsideRect.toNormalizedRange().get())] autorelease];
2070 }
2071
2072 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource 
2073 {
2074     NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window]; 
2075     [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window]; 
2076
2077
2078 - (void)_clearUndoRedoOperations
2079 {
2080     if (!_private->page)
2081         return;
2082     _private->page->clearUndoRedoOperations();
2083 }
2084
2085 - (void)_setCatchesDelegateExceptions:(BOOL)f
2086 {
2087     _private->catchesDelegateExceptions = f;
2088 }
2089
2090 - (BOOL)_catchesDelegateExceptions
2091 {
2092     return _private->catchesDelegateExceptions;
2093 }
2094
2095 - (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value
2096 {
2097     Frame* coreFrame = [self _mainCoreFrame];
2098     if (!coreFrame)
2099         return;
2100     coreFrame->editor()->command(name).execute(value);
2101 }
2102
2103 - (void)_setCustomHTMLTokenizerTimeDelay:(double)timeDelay
2104 {
2105     if (!_private->page)
2106         return;
2107     return _private->page->setCustomHTMLTokenizerTimeDelay(timeDelay);
2108 }
2109
2110 - (void)_setCustomHTMLTokenizerChunkSize:(int)chunkSize
2111 {
2112     if (!_private->page)
2113         return;
2114     return _private->page->setCustomHTMLTokenizerChunkSize(chunkSize);
2115 }
2116
2117 - (void)_clearMainFrameName
2118 {
2119     _private->page->mainFrame()->tree()->clearName();
2120 }
2121
2122 - (void)setSelectTrailingWhitespaceEnabled:(BOOL)flag
2123 {
2124     _private->selectTrailingWhitespaceEnabled = flag;
2125     if (flag)
2126         [self setSmartInsertDeleteEnabled:false];
2127 }
2128
2129 - (BOOL)isSelectTrailingWhitespaceEnabled
2130 {
2131     return _private->selectTrailingWhitespaceEnabled;
2132 }
2133
2134 - (void)setMemoryCacheDelegateCallsEnabled:(BOOL)enabled
2135 {
2136     _private->page->setMemoryCacheClientCallsEnabled(enabled);
2137 }
2138
2139 - (BOOL)areMemoryCacheDelegateCallsEnabled
2140 {
2141     return _private->page->areMemoryCacheClientCallsEnabled();
2142 }
2143
2144 - (void)_setJavaScriptURLsAreAllowed:(BOOL)areAllowed
2145 {
2146     _private->page->setJavaScriptURLsAreAllowed(areAllowed);
2147 }
2148
2149 + (NSCursor *)_pointingHandCursor
2150 {
2151     return handCursor().impl();
2152 }
2153
2154 - (BOOL)_postsAcceleratedCompositingNotifications
2155 {
2156 #if USE(ACCELERATED_COMPOSITING)
2157     return _private->postsAcceleratedCompositingNotifications;
2158 #else
2159     return NO;
2160 #endif
2161
2162 }
2163 - (void)_setPostsAcceleratedCompositingNotifications:(BOOL)flag
2164 {
2165 #if USE(ACCELERATED_COMPOSITING)
2166     _private->postsAcceleratedCompositingNotifications = flag;
2167 #endif
2168 }
2169
2170 - (BOOL)_isUsingAcceleratedCompositing
2171 {
2172 #if USE(ACCELERATED_COMPOSITING)
2173     if (_private->usesDocumentViews) {
2174         Frame* coreFrame = [self _mainCoreFrame];
2175         for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
2176             NSView *documentView = [[kit(frame) frameView] documentView];
2177             if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _isUsingAcceleratedCompositing])
2178                 return YES;
2179         }
2180     }
2181 #endif
2182     return NO;
2183 }
2184
2185 - (BOOL)_isSoftwareRenderable
2186 {
2187 #if USE(ACCELERATED_COMPOSITING)
2188     if (_private->usesDocumentViews) {
2189         Frame* coreFrame = [self _mainCoreFrame];
2190         for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
2191             if (FrameView* view = frame->view()) {
2192                 if (!view->isSoftwareRenderable())
2193                     return NO;
2194             }
2195         }
2196     }
2197 #endif
2198     return YES;
2199 }
2200
2201 - (void)_setIncludesFlattenedCompositingLayersWhenDrawingToBitmap:(BOOL)flag
2202 {
2203     _private->includesFlattenedCompositingLayersWhenDrawingToBitmap = flag;
2204 }
2205
2206 - (BOOL)_includesFlattenedCompositingLayersWhenDrawingToBitmap
2207 {
2208     return _private->includesFlattenedCompositingLayersWhenDrawingToBitmap;
2209 }
2210
2211 static WebBaseNetscapePluginView *_pluginViewForNode(DOMNode *node)
2212 {
2213     if (!node)
2214         return nil;
2215     
2216     Node* coreNode = core(node);
2217     if (!coreNode)
2218         return nil;
2219     
2220     RenderObject* renderer = coreNode->renderer();
2221     if (!renderer || !renderer->isWidget())
2222         return nil;
2223     
2224     Widget* widget = toRenderWidget(renderer)->widget();
2225     if (!widget || !widget->platformWidget())
2226         return nil;
2227     
2228     NSView *view = widget->platformWidget();
2229     if (![view isKindOfClass:[WebBaseNetscapePluginView class]])
2230         return nil;
2231     
2232     return (WebBaseNetscapePluginView *)view;
2233 }
2234
2235 + (BOOL)_isNodeHaltedPlugin:(DOMNode *)node
2236 {
2237     return [_pluginViewForNode(node) isHalted];
2238 }
2239
2240 + (BOOL)_hasPluginForNodeBeenHalted:(DOMNode *)node
2241 {
2242     return [_pluginViewForNode(node) hasBeenHalted];
2243 }
2244 + (void)_restartHaltedPluginForNode:(DOMNode *)node
2245 {
2246     if (!node)
2247         return;
2248     
2249     [_pluginViewForNode(node) resumeFromHalt];
2250 }
2251
2252 - (NSPasteboard *)_insertionPasteboard
2253 {
2254     return _private ? _private->insertionPasteboard : nil;
2255 }
2256
2257 + (void)_addOriginAccessWhitelistEntryWithSourceOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains
2258 {
2259     SecurityOrigin::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
2260 }
2261
2262 + (void)_removeOriginAccessWhitelistEntryWithSourceOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains
2263 {
2264     SecurityOrigin::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
2265 }
2266
2267 +(void)_resetOriginAccessWhitelists
2268 {
2269     SecurityOrigin::resetOriginAccessWhitelists();
2270 }
2271
2272 - (void)_updateActiveState
2273 {
2274     if (_private && _private->page)
2275         _private->page->focusController()->setActive([[self window] isKeyWindow]);
2276 }
2277
2278 static PassOwnPtr<Vector<String> > toStringVector(NSArray* patterns)
2279 {
2280     // Convert the patterns into Vectors.
2281     NSUInteger count = [patterns count];
2282     if (count == 0)
2283         return 0;
2284     Vector<String>* patternsVector = new Vector<String>;
2285     for (NSUInteger i = 0; i < count; ++i) {
2286         id entry = [patterns objectAtIndex:i];
2287         if ([entry isKindOfClass:[NSString class]])
2288             patternsVector->append(String((NSString*)entry));
2289     }
2290     return patternsVector;
2291 }
2292
2293 + (void)_addUserScriptToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url
2294                     whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist injectionTime:(WebUserScriptInjectionTime)injectionTime
2295 {
2296     String group(groupName);
2297     if (group.isEmpty())
2298         return;
2299     
2300     PageGroup* pageGroup = PageGroup::pageGroup(group);
2301     if (!pageGroup)
2302         return;
2303     
2304     pageGroup->addUserScriptToWorld(core(world), source, url, toStringVector(whitelist), toStringVector(blacklist), 
2305                                     injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd);
2306 }
2307
2308 + (void)_addUserStyleSheetToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url
2309                         whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist
2310 {
2311     String group(groupName);
2312     if (group.isEmpty())
2313         return;
2314     
2315     PageGroup* pageGroup = PageGroup::pageGroup(group);
2316     if (!pageGroup)
2317         return;
2318
2319     pageGroup->addUserStyleSheetToWorld(core(world), source, url, toStringVector(whitelist), toStringVector(blacklist));
2320 }
2321
2322 + (void)_removeUserScriptFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url
2323 {
2324     String group(groupName);
2325     if (group.isEmpty())
2326         return;
2327     
2328     PageGroup* pageGroup = PageGroup::pageGroup(group);
2329     if (!pageGroup)
2330         return;
2331
2332     pageGroup->removeUserScriptFromWorld(core(world), url);
2333 }
2334
2335 + (void)_removeUserStyleSheetFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url
2336 {
2337     String group(groupName);
2338     if (group.isEmpty())
2339         return;
2340     
2341     PageGroup* pageGroup = PageGroup::pageGroup(group);
2342     if (!pageGroup)
2343         return;
2344
2345     pageGroup->removeUserStyleSheetFromWorld(core(world), url);
2346 }
2347
2348 + (void)_removeUserScriptsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world
2349 {
2350     String group(groupName);
2351     if (group.isEmpty())
2352         return;
2353     
2354     PageGroup* pageGroup = PageGroup::pageGroup(group);
2355     if (!pageGroup)
2356         return;
2357
2358     pageGroup->removeUserScriptsFromWorld(core(world));
2359 }
2360
2361 + (void)_removeUserStyleSheetsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world
2362 {
2363     String group(groupName);
2364     if (group.isEmpty())
2365         return;
2366     
2367     PageGroup* pageGroup = PageGroup::pageGroup(group);
2368     if (!pageGroup)
2369         return;
2370
2371     pageGroup->removeUserStyleSheetsFromWorld(core(world));
2372 }
2373
2374 + (void)_removeAllUserContentFromGroup:(NSString *)groupName
2375 {
2376     String group(groupName);
2377     if (group.isEmpty())
2378         return;
2379     
2380     PageGroup* pageGroup = PageGroup::pageGroup(group);
2381     if (!pageGroup)
2382         return;
2383     
2384     pageGroup->removeAllUserContent();
2385 }
2386
2387 - (BOOL)cssAnimationsSuspended
2388 {
2389     return _private->cssAnimationsSuspended;
2390 }
2391
2392 - (void)setCSSAnimationsSuspended:(BOOL)suspended
2393 {
2394     if (suspended == _private->cssAnimationsSuspended)
2395         return;
2396         
2397     _private->cssAnimationsSuspended = suspended;
2398     
2399     Frame* frame = core([self mainFrame]);
2400     if (suspended)
2401         frame->animation()->suspendAnimations(frame->document());
2402     else
2403         frame->animation()->resumeAnimations(frame->document());
2404 }
2405
2406 + (void)_setDomainRelaxationForbidden:(BOOL)forbidden forURLScheme:(NSString *)scheme
2407 {
2408     SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
2409 }
2410
2411 + (void)_registerURLSchemeAsSecure:(NSString *)scheme
2412 {
2413     SecurityOrigin::registerURLSchemeAsSecure(scheme);
2414 }
2415
2416 @end
2417
2418 @implementation _WebSafeForwarder
2419
2420 // Used to send messages to delegates that implement informal protocols.
2421
2422 - (id)initWithTarget:(id)t defaultTarget:(id)dt catchExceptions:(BOOL)c
2423 {
2424     self = [super init];
2425     if (!self)
2426         return nil;
2427     target = t; // Non retained.
2428     defaultTarget = dt;
2429     catchExceptions = c;
2430     return self;
2431 }
2432
2433 - (void)forwardInvocation:(NSInvocation *)invocation
2434 {
2435     if ([target respondsToSelector:[invocation selector]]) {
2436         if (catchExceptions) {
2437             @try {
2438                 [invocation invokeWithTarget:target];
2439             } @catch(id exception) {
2440                 ReportDiscardedDelegateException([invocation selector], exception);
2441             }
2442         } else
2443             [invocation invokeWithTarget:target];
2444         return;
2445     }
2446
2447     if ([defaultTarget respondsToSelector:[invocation selector]])
2448         [invocation invokeWithTarget:defaultTarget];
2449
2450     // Do nothing quietly if method not implemented.
2451 }
2452
2453 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
2454 {
2455     return [defaultTarget methodSignatureForSelector:aSelector];
2456 }
2457
2458 @end
2459
2460 @implementation WebView
2461
2462 + (void)initialize
2463 {
2464     static BOOL initialized = NO;
2465     if (initialized)
2466         return;
2467     initialized = YES;
2468
2469     InitWebCoreSystemInterface();
2470     JSC::initializeThreading();
2471     WTF::initializeMainThreadToProcessMainThread();
2472
2473     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp];
2474     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil];
2475     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil];    
2476
2477     continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled];
2478 #ifndef BUILDING_ON_TIGER
2479     grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled];
2480 #endif
2481
2482 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2483     automaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled];
2484     automaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled];
2485     automaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled];
2486     automaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled];
2487     automaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled];
2488 #endif
2489 }
2490
2491 + (void)_applicationWillTerminate
2492 {   
2493     applicationIsTerminating = YES;
2494
2495     if (fastDocumentTeardownEnabled())
2496         [self closeAllWebViews];
2497
2498     if (!pluginDatabaseClientCount)
2499         [WebPluginDatabase closeSharedDatabase];
2500
2501     PageGroup::closeLocalStorage();
2502 }
2503
2504 + (BOOL)_canShowMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
2505 {
2506     return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins];
2507 }
2508
2509 + (BOOL)canShowMIMEType:(NSString *)MIMEType
2510 {
2511     return [self _canShowMIMEType:MIMEType allowingPlugins:YES];
2512 }
2513
2514 - (BOOL)_canShowMIMEType:(NSString *)MIMEType
2515 {
2516     return [[self class] _canShowMIMEType:MIMEType allowingPlugins:[_private->preferences arePlugInsEnabled]];
2517 }
2518
2519 - (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
2520 {
2521     if (![_private->preferences arePlugInsEnabled])
2522         return nil;
2523
2524     WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType];
2525     if (pluginPackage)
2526         return pluginPackage;
2527     
2528     if (_private->pluginDatabase)
2529         return [_private->pluginDatabase pluginForMIMEType:MIMEType];
2530     
2531     return nil;
2532 }
2533
2534 - (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
2535 {
2536     if (![_private->preferences arePlugInsEnabled])
2537         return nil;
2538
2539     WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension];
2540     if (pluginPackage)
2541         return pluginPackage;
2542     
2543     if (_private->pluginDatabase)
2544         return [_private->pluginDatabase pluginForExtension:extension];
2545     
2546     return nil;
2547 }
2548
2549 - (void)addPluginInstanceView:(NSView *)view
2550 {
2551     if (!_private->pluginDatabase)
2552         _private->pluginDatabase = [[WebPluginDatabase alloc] init];
2553     [_private->pluginDatabase addPluginInstanceView:view];
2554 }
2555
2556 - (void)removePluginInstanceView:(NSView *)view
2557 {
2558     if (_private->pluginDatabase)
2559         [_private->pluginDatabase removePluginInstanceView:view];    
2560 }
2561
2562 - (void)removePluginInstanceViewsFor:(WebFrame*)webFrame 
2563 {
2564     if (_private->pluginDatabase)
2565         [_private->pluginDatabase removePluginInstanceViewsFor:webFrame];    
2566 }
2567
2568 - (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
2569 {
2570     if (![_private->preferences arePlugInsEnabled])
2571         return NO;
2572
2573     if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType])
2574         return YES;
2575         
2576     if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
2577         return YES;
2578     
2579     return NO;
2580 }
2581
2582 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
2583 {
2584     return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
2585 }
2586
2587 + (NSArray *)MIMETypesShownAsHTML
2588 {
2589     NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
2590     NSEnumerator *enumerator = [viewTypes keyEnumerator];
2591     id key;
2592     NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
2593     
2594     while ((key = [enumerator nextObject])) {
2595         if ([viewTypes objectForKey:key] == [WebHTMLView class])
2596             [array addObject:key];
2597     }
2598     
2599     return array;
2600 }
2601
2602 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
2603 {
2604     NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy];
2605     NSEnumerator *enumerator = [viewTypes keyEnumerator];
2606     id key;
2607     while ((key = [enumerator nextObject])) {
2608         if ([viewTypes objectForKey:key] == [WebHTMLView class])
2609             [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
2610     }
2611     
2612     int i, count = [MIMETypes count];
2613     for (i = 0; i < count; i++) {
2614         [WebView registerViewClass:[WebHTMLView class] 
2615                 representationClass:[WebHTMLRepresentation class] 
2616                 forMIMEType:[MIMETypes objectAtIndex:i]];
2617     }
2618     [viewTypes release];
2619 }
2620
2621 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
2622 {
2623     return [pasteboard _web_bestURL];
2624 }
2625
2626 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
2627 {
2628     return [pasteboard stringForType:WebURLNamePboardType];
2629 }
2630
2631 + (void)registerURLSchemeAsLocal:(NSString *)protocol
2632 {
2633     SecurityOrigin::registerURLSchemeAsLocal(protocol);
2634 }
2635
2636 - (id)_initWithArguments:(NSDictionary *) arguments
2637 {
2638     NSCoder *decoder = [arguments objectForKey:@"decoder"];
2639     if (decoder) {
2640         self = [self initWithCoder:decoder];
2641     } else {
2642         ASSERT([arguments objectForKey:@"frame"]);
2643         NSValue *frameValue = [arguments objectForKey:@"frame"];
2644         NSRect frame = (frameValue ? [frameValue rectValue] : NSZeroRect);
2645         NSString *frameName = [arguments objectForKey:@"frameName"];
2646         NSString *groupName = [arguments objectForKey:@"groupName"];
2647         self = [self initWithFrame:frame frameName:frameName groupName:groupName];
2648     }
2649
2650     return self;
2651 }
2652
2653 static bool clientNeedsWebViewInitThreadWorkaround()
2654 {
2655     if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND))
2656         return false;
2657
2658     NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
2659
2660     // Installer.
2661     if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.installer"])
2662         return true;
2663
2664     // Automator.
2665     if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Automator"])
2666         return true;
2667
2668     // Automator Runner.
2669     if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.AutomatorRunner"])
2670         return true;
2671
2672     // Automator workflows.
2673     if ([bundleIdentifier _webkit_hasCaseInsensitivePrefix:@"com.apple.Automator."])
2674         return true;
2675
2676 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
2677     // Mail.
2678     if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Mail"])
2679         return true;
2680 #endif
2681
2682     return false;
2683 }
2684
2685 static bool needsWebViewInitThreadWorkaround()
2686 {
2687     static bool isOldClient = clientNeedsWebViewInitThreadWorkaround();
2688     return isOldClient && !pthread_main_np();
2689 }
2690
2691 - (id)initWithFrame:(NSRect)f
2692 {
2693     return [self initWithFrame:f frameName:nil groupName:nil];
2694 }
2695
2696 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName
2697 {
2698     if (needsWebViewInitThreadWorkaround())
2699         return [[self _webkit_invokeOnMainThread] initWithFrame:f frameName:frameName groupName:groupName];
2700
2701     WebCoreThreadViolationCheckRoundTwo();
2702     return [self _initWithFrame:f frameName:frameName groupName:groupName usesDocumentViews:YES];
2703 }
2704
2705 - (id)initWithCoder:(NSCoder *)decoder
2706 {
2707     if (needsWebViewInitThreadWorkaround())
2708         return [[self _webkit_invokeOnMainThread] initWithCoder:decoder];
2709
2710     WebCoreThreadViolationCheckRoundTwo();
2711     WebView *result = nil;
2712
2713     @try {
2714         NSString *frameName;
2715         NSString *groupName;
2716         WebPreferences *preferences;
2717         BOOL useBackForwardList = NO;
2718         BOOL allowsUndo = YES;
2719         
2720         result = [super initWithCoder:decoder];
2721         result->_private = [[WebViewPrivate alloc] init];
2722
2723         // We don't want any of the archived subviews. The subviews will always
2724         // be created in _commonInitializationFrameName:groupName:.
2725         [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
2726
2727         if ([decoder allowsKeyedCoding]) {
2728             frameName = [decoder decodeObjectForKey:@"FrameName"];
2729             groupName = [decoder decodeObjectForKey:@"GroupName"];
2730             preferences = [decoder decodeObjectForKey:@"Preferences"];
2731             useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
2732             if ([decoder containsValueForKey:@"AllowsUndo"])
2733                 allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"];
2734         } else {
2735             int version;
2736             [decoder decodeValueOfObjCType:@encode(int) at:&version];
2737             frameName = [decoder decodeObject];
2738             groupName = [decoder decodeObject];
2739             preferences = [decoder decodeObject];
2740             if (version > 1)
2741                 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList];
2742             // The allowsUndo field is no longer written out in encodeWithCoder, but since there are
2743             // version 3 NIBs that have this field encoded, we still need to read it in.
2744             if (version == 3)
2745                 [decoder decodeValuesOfObjCTypes:"c", &allowsUndo];
2746         }
2747
2748         if (![frameName isKindOfClass:[NSString class]])
2749             frameName = nil;
2750         if (![groupName isKindOfClass:[NSString class]])
2751             groupName = nil;
2752         if (![preferences isKindOfClass:[WebPreferences class]])
2753             preferences = nil;
2754
2755         LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList);
2756         [result _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:YES];
2757         [result page]->backForwardList()->setEnabled(useBackForwardList);
2758         result->_private->allowsUndo = allowsUndo;
2759         if (preferences)
2760             [result setPreferences:preferences];
2761     } @catch (NSException *localException) {
2762         result = nil;
2763         [self release];
2764     }
2765
2766     return result;
2767 }
2768
2769 - (void)encodeWithCoder:(NSCoder *)encoder
2770 {
2771     // Set asside the subviews before we archive. We don't want to archive any subviews.
2772     // The subviews will always be created in _commonInitializationFrameName:groupName:.
2773     id originalSubviews = _subviews;
2774     _subviews = nil;
2775
2776     [super encodeWithCoder:encoder];
2777
2778     // Restore the subviews we set aside.
2779     _subviews = originalSubviews;
2780
2781     BOOL useBackForwardList = _private->page && _private->page->backForwardList()->enabled();
2782     if ([encoder allowsKeyedCoding]) {
2783         [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
2784         [encoder encodeObject:[self groupName] forKey:@"GroupName"];
2785         [encoder encodeObject:[self preferences] forKey:@"Preferences"];
2786         [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"];
2787         [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"];
2788     } else {
2789         int version = WebViewVersion;
2790         [encoder encodeValueOfObjCType:@encode(int) at:&version];
2791         [encoder encodeObject:[[self mainFrame] name]];
2792         [encoder encodeObject:[self groupName]];
2793         [encoder encodeObject:[self preferences]];
2794         [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList];
2795         // DO NOT encode any new fields here, doing so will break older WebKit releases.
2796     }
2797
2798     LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList);
2799 }
2800
2801 - (void)dealloc
2802 {
2803     if (WebCoreObjCScheduleDeallocateOnMainThread([WebView class], self))
2804         return;
2805
2806     // call close to ensure we tear-down completely
2807     // this maintains our old behavior for existing applications
2808     [self close];
2809
2810     if ([[self class] shouldIncludeInWebKitStatistics])
2811         --WebViewCount;
2812
2813     if ([self _needsFrameLoadDelegateRetainQuirk])
2814         [_private->frameLoadDelegate release];
2815         
2816     [_private release];
2817     // [super dealloc] can end up dispatching against _private (3466082)
2818     _private = nil;
2819
2820     [super dealloc];
2821 }
2822
2823 - (void)finalize
2824 {
2825     ASSERT(_private->closed);
2826
2827     --WebViewCount;
2828
2829     [super finalize];
2830 }
2831
2832 - (void)close
2833 {
2834     // _close existed first, and some clients might be calling or overriding it, so call through.
2835     [self _close];
2836 }
2837
2838 - (void)setShouldCloseWithWindow:(BOOL)close
2839 {
2840     _private->shouldCloseWithWindow = close;
2841 }
2842
2843 - (BOOL)shouldCloseWithWindow
2844 {
2845     return _private->shouldCloseWithWindow;
2846 }
2847
2848 - (void)addWindowObserversForWindow:(NSWindow *)window
2849 {
2850     if (window) {
2851         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:)
2852             name:NSWindowDidBecomeKeyNotification object:nil];
2853         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:)
2854             name:NSWindowDidResignKeyNotification object:nil];
2855         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOnScreen:)
2856             name:WKWindowWillOrderOnScreenNotification() object:window];
2857     }
2858 }
2859
2860 - (void)removeWindowObservers
2861 {
2862     NSWindow *window = [self window];
2863     if (window) {
2864         [[NSNotificationCenter defaultCenter] removeObserver:self
2865             name:NSWindowDidBecomeKeyNotification object:nil];
2866         [[NSNotificationCenter defaultCenter] removeObserver:self
2867             name:NSWindowDidResignKeyNotification object:nil];
2868         [[NSNotificationCenter defaultCenter] removeObserver:self
2869             name:WKWindowWillOrderOnScreenNotification() object:window];
2870     }
2871 }
2872
2873 - (void)viewWillMoveToWindow:(NSWindow *)window
2874 {
2875     // Don't do anything if the WebView isn't initialized.
2876     // This happens when decoding a WebView in a nib.
2877     // FIXME: What sets up the observer of NSWindowWillCloseNotification in this case?
2878     if (!_private || _private->closed)
2879         return;
2880     
2881     if ([self window] && [self window] != [self hostWindow])
2882         [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]];
2883
2884     if (window) {
2885         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window];
2886          
2887         // Ensure that we will receive the events that WebHTMLView (at least) needs.
2888         // The following are expensive enough that we don't want to call them over
2889         // and over, so do them when we move into a window.
2890         [window setAcceptsMouseMovedEvents:YES];
2891         WKSetNSWindowShouldPostEventNotifications(window, YES);
2892     } else {
2893         _private->page->setCanStartMedia(false);
2894         _private->page->willMoveOffscreen();
2895     }
2896         
2897     if (window != [self window]) {
2898         [self removeWindowObservers];
2899         [self addWindowObserversForWindow:window];
2900     }
2901 }
2902
2903 - (void)viewDidMoveToWindow
2904 {
2905     // Don't do anything if we aren't initialized.  This happens
2906     // when decoding a WebView.  When WebViews are decoded their subviews
2907     // are created by initWithCoder: and so won't be normally
2908     // initialized.  The stub views are discarded by WebView.
2909     if (!_private || _private->closed)
2910         return;
2911
2912     if ([self window]) {
2913         _private->page->setCanStartMedia(true);
2914         _private->page->didMoveOnscreen();
2915     }
2916     
2917     [self _updateActiveState];
2918 }
2919
2920 - (void)_windowDidBecomeKey:(NSNotification *)notification
2921 {
2922     NSWindow *keyWindow = [notification object];
2923     if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet])
2924         [self _updateActiveState];
2925 }
2926
2927 - (void)_windowDidResignKey:(NSNotification *)notification
2928 {
2929     NSWindow *formerKeyWindow = [notification object];
2930     if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet])
2931         [self _updateActiveState];
2932 }
2933
2934 - (void)_windowWillOrderOnScreen:(NSNotification *)notification
2935 {
2936     if (![self shouldUpdateWhileOffscreen])
2937         [self setNeedsDisplay:YES];
2938 }
2939
2940 - (void)_windowWillClose:(NSNotification *)notification
2941 {
2942     if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow])))
2943         [self close];
2944 }
2945
2946 - (void)setPreferences:(WebPreferences *)prefs
2947 {
2948     if (!prefs)
2949         prefs = [WebPreferences standardPreferences];
2950
2951     if (_private->preferences == prefs)
2952         return;
2953
2954     [prefs willAddToWebView];
2955
2956     WebPreferences *oldPrefs = _private->preferences;
2957
2958     [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
2959     [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]];
2960
2961     _private->preferences = [prefs retain];
2962
2963     // After registering for the notification, post it so the WebCore settings update.
2964     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
2965         name:WebPreferencesChangedNotification object:[self preferences]];
2966     [[self preferences] _postPreferencesChangesNotification];
2967
2968     [oldPrefs didRemoveFromWebView];
2969     [oldPrefs release];
2970 }
2971
2972 - (WebPreferences *)preferences
2973 {
2974     return _private->preferences;
2975 }
2976
2977 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
2978 {
2979     if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) {
2980         WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier];
2981         [self setPreferences:prefs];
2982         [prefs release];
2983     }
2984 }
2985
2986 - (NSString *)preferencesIdentifier
2987 {
2988     return [[self preferences] identifier];
2989 }
2990
2991
2992 - (void)setUIDelegate:delegate
2993 {
2994     _private->UIDelegate = delegate;
2995     [_private->UIDelegateForwarder release];
2996     _private->UIDelegateForwarder = nil;
2997 }
2998
2999 - UIDelegate
3000 {
3001     return _private->UIDelegate;
3002 }
3003
3004 - (void)setResourceLoadDelegate: delegate
3005 {
3006     _private->resourceProgressDelegate = delegate;
3007     [self _cacheResourceLoadDelegateImplementations];
3008 }
3009
3010 - resourceLoadDelegate
3011 {
3012     return _private->resourceProgressDelegate;
3013 }
3014
3015 - (void)setDownloadDelegate: delegate
3016 {
3017     _private->downloadDelegate = delegate;
3018 }
3019
3020
3021 - downloadDelegate
3022 {
3023     return _private->downloadDelegate;
3024 }
3025
3026 - (void)setPolicyDelegate:delegate
3027 {
3028     _private->policyDelegate = delegate;
3029     [_private->policyDelegateForwarder release];
3030     _private->policyDelegateForwarder = nil;
3031 }
3032
3033 - policyDelegate
3034 {
3035     return _private->policyDelegate;
3036 }
3037
3038 - (void)setFrameLoadDelegate:delegate
3039 {
3040     // <rdar://problem/6950660> - Due to some subtle WebKit changes - presumably to delegate callback behavior - we've
3041     // unconvered a latent bug in at least one WebKit app where the delegate wasn't properly retained by the app and
3042     // was dealloc'ed before being cleared.
3043     // This is an effort to keep such apps working for now.
3044     if ([self _needsFrameLoadDelegateRetainQuirk]) {
3045         [delegate retain];
3046         [_private->frameLoadDelegate release];
3047     }
3048     
3049     _private->frameLoadDelegate = delegate;
3050     [self _cacheFrameLoadDelegateImplementations];
3051
3052 #if ENABLE(ICONDATABASE)
3053     // If this delegate wants callbacks for icons, fire up the icon database.
3054     if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc)
3055         [WebIconDatabase sharedIconDatabase];
3056 #endif
3057 }
3058
3059 - frameLoadDelegate
3060 {
3061     return _private->frameLoadDelegate;
3062 }
3063
3064 - (WebFrame *)mainFrame
3065 {
3066     // This can be called in initialization, before _private has been set up (3465613)
3067     if (!_private || !_private->page)
3068         return nil;
3069     return kit(_private->page->mainFrame());
3070 }
3071
3072 - (WebFrame *)selectedFrame
3073 {
3074     if (_private->usesDocumentViews) {
3075         // If the first responder is a view in our tree, we get the frame containing the first responder.
3076         // This is faster than searching the frame hierarchy, and will give us a result even in the case
3077         // where the focused frame doesn't actually contain a selection.
3078         WebFrame *focusedFrame = [self _focusedFrame];
3079         if (focusedFrame)
3080             return focusedFrame;
3081     }
3082     
3083     // If the first responder is outside of our view tree, we search for a frame containing a selection.
3084     // There should be at most only one of these.
3085     return [[self mainFrame] _findFrameWithSelection];
3086 }
3087
3088 - (WebBackForwardList *)backForwardList
3089 {
3090     if (!_private->page)
3091         return nil;
3092     if (!_private->page->backForwardList()->enabled())
3093         return nil;
3094     return kit(_private->page->backForwardList());
3095 }
3096
3097 - (void)setMaintainsBackForwardList:(BOOL)flag
3098 {
3099     if (!_private->page)
3100         return;
3101     _private->page->backForwardList()->setEnabled(flag);
3102 }
3103
3104 - (BOOL)goBack
3105 {
3106     if (!_private->page)
3107         return NO;
3108     
3109     return _private->page->goBack();
3110 }
3111
3112 - (BOOL)goForward
3113 {
3114     if (!_private->page)
3115         return NO;
3116
3117     return _private->page->goForward();
3118 }
3119
3120 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
3121 {
3122     if (!_private->page)
3123         return NO;
3124
3125     _private->page->goToItem(core(item), FrameLoadTypeIndexedBackForward);
3126     return YES;
3127 }
3128
3129 - (void)setTextSizeMultiplier:(float)m
3130 {
3131     [self _setZoomMultiplier:m isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3132 }
3133
3134 - (float)textSizeMultiplier
3135 {
3136     return [self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f;
3137 }
3138
3139 - (void)_setZoomMultiplier:(float)m isTextOnly:(BOOL)isTextOnly
3140 {
3141     // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>)
3142     _private->zoomMultiplier = m;
3143     ASSERT(_private->page);
3144     if (_private->page)
3145         _private->page->settings()->setZoomMode(isTextOnly ? ZoomTextOnly : ZoomPage);
3146     
3147     // FIXME: it would be nice to rework this code so that _private->zoomMultiplier doesn't exist and callers
3148     // all access _private->page->settings().
3149     Frame* coreFrame = [self _mainCoreFrame];
3150     if (coreFrame)
3151         coreFrame->setZoomFactor(m, isTextOnly ? ZoomTextOnly : ZoomPage);
3152 }
3153
3154 - (float)_zoomMultiplier:(BOOL)isTextOnly
3155 {
3156     if (isTextOnly != [self _realZoomMultiplierIsTextOnly])
3157         return 1.0f;
3158     return _private->zoomMultiplier;
3159 }
3160
3161 - (float)_realZoomMultiplier
3162 {
3163     return _private->zoomMultiplier;
3164 }
3165
3166 - (BOOL)_realZoomMultiplierIsTextOnly
3167 {
3168     if (!_private->page)
3169         return NO;
3170     
3171     return _private->page->settings()->zoomMode() == ZoomTextOnly;
3172 }
3173
3174 #define MinimumZoomMultiplier       0.5f
3175 #define MaximumZoomMultiplier       3.0f
3176 #define ZoomMultiplierRatio         1.2f
3177
3178 - (BOOL)_canZoomOut:(BOOL)isTextOnly
3179 {
3180     id docView = [[[self mainFrame] frameView] documentView];
3181     if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
3182         id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
3183         return [zoomingDocView _canZoomOut];
3184     }
3185     return [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio > MinimumZoomMultiplier;
3186 }
3187
3188
3189 - (BOOL)_canZoomIn:(BOOL)isTextOnly
3190 {
3191     id docView = [[[self mainFrame] frameView] documentView];
3192     if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
3193         id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
3194         return [zoomingDocView _canZoomIn];
3195     }
3196     return [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio < MaximumZoomMultiplier;
3197 }
3198
3199 - (IBAction)_zoomOut:(id)sender isTextOnly:(BOOL)isTextOnly
3200 {
3201     id docView = [[[self mainFrame] frameView] documentView];
3202     if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
3203         id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
3204         return [zoomingDocView _zoomOut:sender];
3205     }
3206     float newScale = [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio;
3207     if (newScale > MinimumZoomMultiplier)
3208         [self _setZoomMultiplier:newScale isTextOnly:isTextOnly];
3209 }
3210
3211 - (IBAction)_zoomIn:(id)sender isTextOnly:(BOOL)isTextOnly
3212 {
3213     id docView = [[[self mainFrame] frameView] documentView];
3214     if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
3215         id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
3216         return [zoomingDocView _zoomIn:sender];
3217     }
3218     float newScale = [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio;
3219     if (newScale < MaximumZoomMultiplier)
3220         [self _setZoomMultiplier:newScale isTextOnly:isTextOnly];
3221 }
3222
3223 - (BOOL)_canResetZoom:(BOOL)isTextOnly
3224 {
3225     id docView = [[[self mainFrame] frameView] documentView];
3226     if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
3227         id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
3228         return [zoomingDocView _canResetZoom];
3229     }
3230     return [self _zoomMultiplier:isTextOnly] != 1.0f;
3231 }
3232
3233 - (IBAction)_resetZoom:(id)sender isTextOnly:(BOOL)isTextOnly
3234 {
3235     id docView = [[[self mainFrame] frameView] documentView];
3236     if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) {
3237         id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView;
3238         return [zoomingDocView _resetZoom:sender];
3239     }
3240     if ([self _zoomMultiplier:isTextOnly] != 1.0f)
3241         [self _setZoomMultiplier:1.0f isTextOnly:isTextOnly];
3242 }
3243
3244 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
3245 {
3246     NSString *name = [applicationName copy];
3247     [_private->applicationNameForUserAgent release];
3248     _private->applicationNameForUserAgent = name;
3249     if (!_private->userAgentOverridden)
3250         _private->userAgent = String();
3251 }
3252
3253 - (NSString *)applicationNameForUserAgent
3254 {
3255     return [[_private->applicationNameForUserAgent retain] autorelease];
3256 }
3257
3258 - (void)setCustomUserAgent:(NSString *)userAgentString
3259 {
3260     _private->userAgent = userAgentString;
3261     _private->userAgentOverridden = userAgentString != nil;
3262 }
3263
3264 - (NSString *)customUserAgent
3265 {
3266     if (!_private->userAgentOverridden)
3267         return nil;
3268     return _private->userAgent;
3269 }
3270
3271 - (void)setMediaStyle:(NSString *)mediaStyle
3272 {
3273     if (_private->mediaStyle != mediaStyle) {
3274         [_private->mediaStyle release];
3275         _private->mediaStyle = [mediaStyle copy];
3276     }
3277 }
3278
3279 - (NSString *)mediaStyle
3280 {
3281     return _private->mediaStyle;
3282 }
3283
3284 - (BOOL)supportsTextEncoding
3285 {
3286     id documentView = [[[self mainFrame] frameView] documentView];
3287     return [documentView conformsToProtocol:@protocol(WebDocumentText)]
3288         && [documentView supportsTextEncoding];
3289 }
3290
3291 - (void)setCustomTextEncodingName:(NSString *)encoding
3292 {
3293     NSString *oldEncoding = [self customTextEncodingName];
3294     if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding])
3295         return;
3296     if (Frame* mainFrame = [self _mainCoreFrame])
3297         mainFrame->loader()->reloadWithOverrideEncoding(encoding);
3298 }
3299
3300 - (NSString *)_mainFrameOverrideEncoding
3301 {
3302     WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
3303     if (dataSource == nil)
3304         dataSource = [[self mainFrame] _dataSource];
3305     if (dataSource == nil)
3306         return nil;
3307     return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding());
3308 }
3309
3310 - (NSString *)customTextEncodingName
3311 {
3312     return [self _mainFrameOverrideEncoding];
3313 }
3314
3315 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
3316 {
3317     // Return statements are only valid in a function but some applications pass in scripts
3318     // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions
3319     // silently ignored the return. If the application is linked against an earlier version
3320     // of WebKit we will strip the return so the script wont fail.
3321     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) {
3322         NSRange returnStringRange = [script rangeOfString:@"return "];
3323         if (returnStringRange.length && !returnStringRange.location)
3324             script = [script substringFromIndex:returnStringRange.location + returnStringRange.length];
3325     }
3326
3327     NSString *result = [[self mainFrame] _stringByEvaluatingJavaScriptFromString:script];
3328     // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script
3329     // Since there's no way to get rid of the main frame, result will never ever be nil here.
3330     ASSERT(result);
3331
3332     return result;
3333 }
3334
3335 - (WebScriptObject *)windowScriptObject
3336 {
3337     Frame* coreFrame = [self _mainCoreFrame];
3338     if (!coreFrame)
3339         return nil;
3340     return coreFrame->script()->windowScriptObject();
3341 }
3342
3343 // Get the appropriate user-agent string for a particular URL.
3344 - (NSString *)userAgentForURL:(NSURL *)url
3345 {
3346     if (_private->useSiteSpecificSpoofing) {
3347         // No current site-specific spoofs.
3348     }
3349
3350     if (_private->userAgent.isNull())
3351         _private->userAgent = [[self class] _standardUserAgentWithApplicationName:_private->applicationNameForUserAgent];
3352
3353     return _private->userAgent;
3354 }
3355
3356 - (void)setHostWindow:(NSWindow *)hostWindow
3357 {
3358     if (_private->closed && hostWindow)
3359         return;
3360     if (hostWindow == _private->hostWindow)
3361         return;
3362
3363     Frame* coreFrame = [self _mainCoreFrame];
3364     if (_private->usesDocumentViews) {
3365         for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
3366             [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow];
3367     }
3368     if (_private->hostWindow && [self window] != _private->hostWindow)
3369         [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow];
3370     if (hostWindow)
3371         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow];
3372     [_private->hostWindow release];
3373     _private->hostWindow = [hostWindow retain];
3374     if (_private->usesDocumentViews) {
3375         for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
3376             [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow];
3377     }
3378 }
3379
3380 - (NSWindow *)hostWindow
3381 {
3382     // -[WebView hostWindow] can sometimes be called from the WebView's [super dealloc] method
3383     // so we check here to make sure it's not null.
3384     if (!_private)
3385         return nil;
3386     
3387     return _private->hostWindow;
3388 }
3389
3390 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
3391 {
3392     return [[self _frameViewAtWindowPoint:point] documentView];
3393 }
3394
3395 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
3396 {
3397     WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
3398     if (!frameView)
3399         return nil;
3400     NSView <WebDocumentView> *documentView = [frameView documentView];
3401     if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
3402         NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
3403         return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
3404     }
3405     return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
3406 }
3407
3408 - (NSDictionary *)elementAtPoint:(NSPoint)point
3409 {
3410     return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
3411 }
3412
3413 // The following 2 internal NSView methods are called on the drag destination to make scrolling while dragging work.
3414 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. 
3415 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. 
3416 // Forward these calls to the document subview to make its scroll view scroll.
3417 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
3418 {
3419     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
3420     [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
3421 }
3422
3423 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
3424 {
3425     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
3426     return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
3427 }
3428
3429 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
3430 {
3431     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
3432     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
3433     IntPoint client([draggingInfo draggingLocation]);
3434     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
3435     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
3436     return core(self)->dragController()->dragEntered(&dragData);
3437 }
3438
3439 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
3440 {
3441     Page* page = core(self);
3442     if (!page)
3443         return NSDragOperationNone;
3444
3445     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
3446     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
3447     IntPoint client([draggingInfo draggingLocation]);
3448     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
3449     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
3450     return page->dragController()->dragUpdated(&dragData);
3451 }
3452
3453 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
3454 {
3455     Page* page = core(self);
3456     if (!page)
3457         return;
3458
3459     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
3460     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
3461     IntPoint client([draggingInfo draggingLocation]);
3462     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
3463     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
3464     page->dragController()->dragExited(&dragData);
3465 }
3466
3467 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
3468 {
3469     return YES;
3470 }
3471
3472 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
3473 {
3474     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
3475     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]]? (WebHTMLView*)view : nil);
3476     IntPoint client([draggingInfo draggingLocation]);
3477     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
3478     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
3479     return core(self)->dragController()->performDrag(&dragData);
3480 }
3481
3482 - (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types
3483 {
3484     NSView *hitView = [super _hitTest:point dragTypes:types];
3485     if (!hitView && [[self superview] mouse:*point inRect:[self frame]])
3486         return self;
3487     return hitView;
3488 }
3489
3490 - (BOOL)acceptsFirstResponder
3491 {
3492     if (_private->usesDocumentViews)
3493         return [[[self mainFrame] frameView] acceptsFirstResponder];
3494
3495     // FIXME (Viewless): Need more code from WebHTMLView here.
3496     return YES;
3497 }
3498
3499 - (BOOL)becomeFirstResponder
3500 {
3501     if (_private->usesDocumentViews) {
3502         if (_private->becomingFirstResponder) {
3503             // Fix for unrepro infinite recursion reported in Radar 4448181. If we hit this assert on
3504             // a debug build, we should figure out what causes the problem and do a better fix.
3505             ASSERT_NOT_REACHED();
3506             return NO;
3507         }
3508         
3509         // This works together with setNextKeyView to splice the WebView into
3510         // the key loop similar to the way NSScrollView does this. Note that
3511         // WebFrameView has very similar code.
3512         NSWindow *window = [self window];
3513         WebFrameView *mainFrameView = [[self mainFrame] frameView];
3514
3515         NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming];
3516         BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self);
3517
3518         if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
3519             NSView *previousValidKeyView = [self previousValidKeyView];
3520             if (previousValidKeyView != self && previousValidKeyView != mainFrameView) {
3521                 _private->becomingFirstResponder = YES;
3522                 _private->becomingFirstResponderFromOutside = fromOutside;
3523                 [window makeFirstResponder:previousValidKeyView];
3524                 _private->becomingFirstResponderFromOutside = NO;
3525                 _private->becomingFirstResponder = NO;
3526                 return YES;
3527             }
3528             return NO;
3529         }
3530
3531         if ([mainFrameView acceptsFirstResponder]) {
3532             _private->becomingFirstResponder = YES;
3533             _private->becomingFirstResponderFromOutside = fromOutside;
3534             [window makeFirstResponder:mainFrameView];
3535             _private->becomingFirstResponderFromOutside = NO;
3536             _private->becomingFirstResponder = NO;
3537             return YES;
3538         } 
3539
3540         return NO;
3541     }
3542
3543     // FIXME (Viewless): Need more code from WebHTMLView here.
3544     return YES;
3545 }
3546
3547 - (NSView *)_webcore_effectiveFirstResponder
3548 {
3549     if (_private && _private->usesDocumentViews) {
3550         if (WebFrameView *frameView = [[self mainFrame] frameView])
3551             return [frameView _webcore_effectiveFirstResponder];
3552     }
3553     return [super _webcore_effectiveFirstResponder];
3554 }
3555
3556 - (void)setNextKeyView:(NSView *)view
3557 {
3558     if (_private && _private->usesDocumentViews) {
3559         // This works together with becomeFirstResponder to splice the WebView into
3560         // the key loop similar to the way NSScrollView does this. Note that
3561         // WebFrameView has similar code.
3562         if (WebFrameView *mainFrameView = [[self mainFrame] frameView]) {
3563             [mainFrameView setNextKeyView:view];
3564             return;
3565         }
3566     }
3567
3568     [super setNextKeyView:view];
3569 }
3570
3571 static WebFrame *incrementFrame(WebFrame *frame, BOOL forward, BOOL wrapFlag)
3572 {
3573     Frame* coreFrame = core(frame);
3574     return kit(forward
3575         ? coreFrame->tree()->traverseNextWithWrap(wrapFlag)
3576         : coreFrame->tree()->traversePreviousWithWrap(wrapFlag));
3577 }
3578
3579 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
3580 {
3581     return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
3582 }
3583
3584 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
3585 {
3586     [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
3587     [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
3588     
3589     // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
3590     // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
3591     // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
3592     if ([viewClass class] == [WebHTMLView class])
3593         MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
3594 }
3595
3596 - (void)setGroupName:(NSString *)groupName
3597 {
3598     if (!_private->page)
3599         return;
3600     _private->page->setGroupName(groupName);
3601 }
3602
3603 - (NSString *)groupName
3604 {
3605     if (!_private->page)
3606         return nil;
3607     return _private->page->groupName();
3608 }
3609
3610 - (double)estimatedProgress
3611 {
3612     if (!_private->page)
3613         return 0.0;
3614     return _private->page->progress()->estimatedProgress();
3615 }
3616
3617 - (NSArray *)pasteboardTypesForSelection
3618 {
3619     NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
3620     if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
3621         return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
3622     }
3623     return [NSArray array];
3624 }
3625
3626 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
3627 {
3628     WebFrame *frame = [self _selectedOrMainFrame];
3629     if (frame && [frame _hasSelection]) {
3630         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
3631         if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)])
3632             [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
3633     }
3634 }
3635
3636 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
3637 {
3638     if ([element objectForKey:WebElementImageURLKey] != nil) {
3639         return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
3640     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
3641         return [NSPasteboard _web_writableTypesForURL];
3642     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
3643         return [self pasteboardTypesForSelection];
3644     }
3645     return [NSArray array];
3646 }
3647
3648 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
3649 {
3650     if ([element objectForKey:WebElementImageURLKey] != nil) {
3651         [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard];
3652     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
3653         [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
3654     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
3655         [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
3656     }
3657 }
3658
3659 - (void)moveDragCaretToPoint:(NSPoint)point
3660 {
3661     if (Page* page = core(self))
3662         page->dragController()->placeDragCaret(IntPoint([self convertPoint:point toView:nil]));
3663 }
3664
3665 - (void)removeDragCaret
3666 {
3667     if (Page* page = core(self))
3668         page->dragController()->dragEnded();
3669 }
3670
3671 - (void)setMainFrameURL:(NSString *)URLString
3672 {
3673     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
3674 }
3675
3676 - (NSString *)mainFrameURL
3677 {
3678     WebDataSource *ds;
3679     ds = [[self mainFrame] provisionalDataSource];
3680     if (!ds)
3681         ds = [[self mainFrame] _dataSource];
3682     return [[[ds request] URL] _web_originalDataAsString];
3683 }
3684
3685 - (BOOL)isLoading
3686 {
3687     LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
3688     return [self _isLoading];
3689 }
3690
3691 - (NSString *)mainFrameTitle
3692 {
3693     NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle];
3694     return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
3695 }
3696
3697 - (NSImage *)mainFrameIcon
3698 {
3699     return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
3700 }
3701
3702 - (DOMDocument *)mainFrameDocument
3703 {
3704     // only return the actual value if the state we're in gives NSTreeController
3705     // enough time to release its observers on the old model
3706     if (_private->mainFrameDocumentReady)
3707         return [[self mainFrame] DOMDocument];
3708     return nil;
3709 }
3710
3711 - (void)setDrawsBackground:(BOOL)drawsBackground
3712 {
3713     if (_private->drawsBackground == drawsBackground)
3714         return;
3715     _private->drawsBackground = drawsBackground;
3716     [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
3717 }
3718
3719 - (BOOL)drawsBackground
3720 {
3721     // This method can be called beneath -[NSView dealloc] after we have cleared _private,
3722     // indirectly via -[WebFrameView viewDidMoveToWindow].
3723     return !_private || _private->drawsBackground;
3724 }
3725
3726 - (void)setShouldUpdateWhileOffscreen:(BOOL)updateWhileOffscreen
3727 {
3728     if (_private->shouldUpdateWhileOffscreen == updateWhileOffscreen)
3729         return;
3730     _private->shouldUpdateWhileOffscreen = updateWhileOffscreen;
3731     [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen];
3732 }
3733
3734 - (BOOL)shouldUpdateWhileOffscreen
3735 {
3736     return _private->shouldUpdateWhileOffscreen;
3737 }
3738
3739 - (void)setCurrentNodeHighlight:(WebNodeHighlight *)nodeHighlight
3740 {
3741     id old = _private->currentNodeHighlight;
3742     _private->currentNodeHighlight = [nodeHighlight retain];
3743     [old release];
3744 }
3745
3746 - (WebNodeHighlight *)currentNodeHighlight
3747 {
3748     return _private->currentNodeHighlight;
3749 }
3750
3751 - (NSView *)previousValidKeyView
3752 {
3753     NSView *result = [super previousValidKeyView];
3754
3755     // Work around AppKit bug 6905484. If the result is a view that's inside this one, it's
3756     // possible it is the wrong answer, because the fact that it's a descendant causes the
3757     // code that implements key view redirection to fail; this means we won't redirect to
3758     // the toolbar, for example, when we hit the edge of a window. Since the bug is specific
3759     // to cases where the receiver of previousValidKeyView is an ancestor of the last valid
3760     // key view in the loop, we can sidestep it by walking along previous key views until
3761     // we find one that is not a superview, then using that to call previousValidKeyView.
3762
3763     if (![result isDescendantOf:self])
3764         return result;
3765
3766     // Use a visited set so we don't loop indefinitely when walking crazy key loops.
3767     // AppKit uses such sets internally and we want our loop to be as robust as its loops.
3768     RetainPtr<CFMutableSetRef> visitedViews = CFSetCreateMutable(0, 0, 0);
3769     CFSetAddValue(visitedViews.get(), result);
3770
3771     NSView *previousView = self;
3772     do {
3773         CFSetAddValue(visitedViews.get(), previousView);
3774         previousView = [previousView previousKeyView];
3775         if (!previousView || CFSetGetValue(visitedViews.get(), previousView))
3776             return result;
3777     } while ([result isDescendantOf:previousView]);
3778     return [previousView previousValidKeyView];
3779 }
3780
3781 @end
3782
3783 @implementation WebView (WebIBActions)
3784
3785 - (IBAction)takeStringURLFrom: sender
3786 {
3787     NSString *URLString = [sender stringValue];
3788     
3789     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
3790 }
3791
3792 - (BOOL)canGoBack
3793 {
3794     if (!_private->page)
3795         return NO;
3796
3797     return !!_private->page->backForwardList()->backItem();
3798 }
3799
3800 - (BOOL)canGoForward
3801 {
3802     if (!_private->page)
3803         return NO;
3804
3805     return !!_private->page->backForwardList()->forwardItem();
3806 }
3807
3808 - (IBAction)goBack:(id)sender
3809 {
3810     [self goBack];
3811 }
3812
3813 - (IBAction)goForward:(id)sender
3814 {
3815     [self goForward];
3816 }
3817
3818 - (IBAction)stopLoading:(id)sender
3819 {
3820     [[self mainFrame] stopLoading];
3821 }
3822
3823 - (IBAction)reload:(id)sender
3824 {
3825     [[self mainFrame] reload];
3826 }
3827
3828 - (IBAction)reloadFromOrigin:(id)sender
3829 {
3830     [[self mainFrame] reloadFromOrigin];
3831 }
3832
3833 // FIXME: This code should move into WebCore so that it is not duplicated in each WebKit.
3834 // (This includes canMakeTextSmaller/Larger, makeTextSmaller/Larger, and canMakeTextStandardSize/makeTextStandardSize)
3835 - (BOOL)canMakeTextSmaller
3836 {
3837     return [self _canZoomOut:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3838 }
3839
3840 - (IBAction)makeTextSmaller:(id)sender
3841 {
3842     return [self _zoomOut:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3843 }
3844
3845 - (BOOL)canMakeTextLarger
3846 {
3847     return [self _canZoomIn:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3848 }
3849
3850 - (IBAction)makeTextLarger:(id)sender
3851 {
3852     return [self _zoomIn:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3853 }
3854
3855 - (BOOL)canMakeTextStandardSize
3856 {
3857     return [self _canResetZoom:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3858 }
3859
3860 - (IBAction)makeTextStandardSize:(id)sender
3861 {
3862    return [self _resetZoom:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]];
3863 }
3864
3865 - (IBAction)toggleSmartInsertDelete:(id)sender
3866 {
3867     [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
3868 }
3869
3870 - (IBAction)toggleContinuousSpellChecking:(id)sender
3871 {
3872     [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
3873 }
3874
3875 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
3876 {
3877     id responder = [self _responderForResponderOperations];
3878     if (responder != self && [responder respondsToSelector:[item action]]) {
3879         if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)])
3880             return [responder validateUserInterfaceItemWithoutDelegate:item];
3881         if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)])
3882             return [responder validateUserInterfaceItem:item];
3883         return YES;
3884     }
3885     return NO;
3886 }
3887
3888 #define VALIDATE(name) \
3889     else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
3890
3891 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
3892 {
3893     SEL action = [item action];
3894
3895     if (action == @selector(goBack:)) {
3896         return [self canGoBack];
3897     } else if (action == @selector(goForward:)) {
3898         return [self canGoForward];
3899     } else if (action == @selector(makeTextLarger:)) {
3900         return [self canMakeTextLarger];
3901     } else if (action == @selector(makeTextSmaller:)) {
3902         return [self canMakeTextSmaller];
3903     } else if (action == @selector(makeTextStandardSize:)) {
3904         return [self canMakeTextStandardSize];
3905     } else if (action == @selector(reload:)) {
3906         return [[self mainFrame] _dataSource] != nil;
3907     } else if (action == @selector(stopLoading:)) {
3908         return [self _isLoading];
3909     } else if (action == @selector(toggleContinuousSpellChecking:)) {
3910         BOOL checkMark = NO;
3911         BOOL retVal = NO;
3912         if ([self _continuousCheckingAllowed]) {
3913             checkMark = [self isContinuousSpellCheckingEnabled];
3914             retVal = YES;
3915         }
3916         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3917             NSMenuItem *menuItem = (NSMenuItem *)item;
3918             [menuItem setState:checkMark ? NSOnState : NSOffState];
3919         }
3920         return retVal;
3921     } else if (action == @selector(toggleSmartInsertDelete:)) {
3922         BOOL checkMark = [self smartInsertDeleteEnabled];
3923         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3924             NSMenuItem *menuItem = (NSMenuItem *)item;
3925             [menuItem setState:checkMark ? NSOnState : NSOffState];
3926         }
3927         return YES;
3928 #ifndef BUILDING_ON_TIGER
3929     } else if (action == @selector(toggleGrammarChecking:)) {
3930         BOOL checkMark = [self isGrammarCheckingEnabled];
3931         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3932             NSMenuItem *menuItem = (NSMenuItem *)item;
3933             [menuItem setState:checkMark ? NSOnState : NSOffState];
3934         }
3935         return YES;
3936 #endif
3937 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
3938     } else if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
3939         BOOL checkMark = [self isAutomaticQuoteSubstitutionEnabled];
3940         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3941             NSMenuItem *menuItem = (NSMenuItem *)item;
3942             [menuItem setState:checkMark ? NSOnState : NSOffState];
3943         }
3944         return YES;
3945     } else if (action == @selector(toggleAutomaticLinkDetection:)) {
3946         BOOL checkMark = [self isAutomaticLinkDetectionEnabled];
3947         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3948             NSMenuItem *menuItem = (NSMenuItem *)item;
3949             [menuItem setState:checkMark ? NSOnState : NSOffState];
3950         }
3951         return YES;
3952     } else if (action == @selector(toggleAutomaticDashSubstitution:)) {
3953         BOOL checkMark = [self isAutomaticDashSubstitutionEnabled];
3954         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3955             NSMenuItem *menuItem = (NSMenuItem *)item;
3956             [menuItem setState:checkMark ? NSOnState : NSOffState];
3957         }
3958         return YES;
3959     } else if (action == @selector(toggleAutomaticTextReplacement:)) {
3960         BOOL checkMark = [self isAutomaticTextReplacementEnabled];
3961         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3962             NSMenuItem *menuItem = (NSMenuItem *)item;
3963             [menuItem setState:checkMark ? NSOnState : NSOffState];
3964         }
3965         return YES;
3966     } else if (action == @selector(toggleAutomaticSpellingCorrection:)) {
3967         BOOL checkMark = [self isAutomaticSpellingCorrectionEnabled];
3968         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
3969             NSMenuItem *menuItem = (NSMenuItem *)item;
3970             [menuItem setState:checkMark ? NSOnState : NSOffState];
3971         }
3972         return YES;
3973 #endif
3974     }
3975     FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
3976
3977     return YES;
3978 }
3979
3980 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
3981 {
3982     BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
3983     return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
3984 }
3985
3986 @end
3987
3988 @implementation WebView (WebPendingPublic)
3989
3990 - (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode
3991 {
3992     if (runLoop && mode)
3993         core(self)->addSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode));
3994 }
3995
3996 - (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode
3997 {
3998     if (runLoop && mode)
3999         core(self)->removeSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode));
4000 }
4001
4002 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
4003 {
4004     if (_private->closed)
4005         return NO;
4006     
4007     // Get the frame holding the selection, or start with the main frame
4008     WebFrame *startFrame = [self _selectedOrMainFrame];
4009     
4010     // Search the first frame, then all the other frames, in order
4011     NSView <WebDocumentSearching> *startSearchView = nil;
4012     WebFrame *frame = startFrame;
4013     do {
4014         WebFrame *nextFrame = incrementFrame(frame, forward, wrapFlag);
4015         
4016         BOOL onlyOneFrame = (frame == nextFrame);
4017         ASSERT(!onlyOneFrame || frame == startFrame);
4018         
4019         id <WebDocumentView> view = [[frame frameView] documentView];
4020         if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
4021             NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
4022             
4023             if (frame == startFrame)
4024                 startSearchView = searchView;
4025             
4026             BOOL foundString;
4027             // In some cases we have to search some content twice; see comment later in this method.
4028             // We can avoid ever doing this in the common one-frame case by passing YES for wrapFlag 
4029             // here, and then bailing out before we get to the code that would search again in the
4030             // same content.
4031             BOOL wrapOnThisPass = wrapFlag && onlyOneFrame;
4032             if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
4033                 foundString = [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass startInSelection:startInSelection];
4034             else
4035                 foundString = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass];
4036             
4037             if (foundString) {
4038                 if (frame != startFrame)
4039                     [startFrame _clearSelection];
4040                 [[self window] makeFirstResponder:searchView];
4041                 return YES;
4042             }
4043             
4044             if (onlyOneFrame)
4045                 return NO;
4046         }
4047         frame = nextFrame;
4048     } while (frame && frame != startFrame);
4049     
4050     // 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 
4051     // 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 
4052     // 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
4053     // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice.
4054     // To fix this, we'd need to add a mechanism to specify a range in which to search.
4055     if (wrapFlag && startSearchView) {
4056         BOOL foundString;
4057         if ([startSearchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
4058             foundString = [(NSView <WebDocumentIncrementalSearching> *)startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES startInSelection:startInSelection];
4059         else
4060             foundString = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES];
4061         if (foundString) {
4062             [[self window] makeFirstResponder:startSearchView];
4063             return YES;
4064         }
4065     }
4066     return NO;
4067 }
4068
4069 - (void)setHoverFeedbackSuspended:(BOOL)newValue
4070 {
4071     if (_private->hoverFeedbackSuspended == newValue)
4072         return;
4073     
4074     _private->hoverFeedbackSuspended = newValue;
4075
4076     if (_private->usesDocumentViews) {
4077         id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView];
4078         // FIXME: in a perfect world we'd do this in a general way that worked with any document view,
4079         // such as by calling a protocol method or using respondsToSelector or sending a notification.
4080         // But until there is any need for these more general solutions, we'll just hardwire it to work
4081         // with WebHTMLView.
4082         // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not
4083         // on each subframe separately.
4084         if ([documentView isKindOfClass:[WebHTMLView class]])
4085             [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged];
4086         return;
4087     }
4088
4089     [self _updateMouseoverWithFakeEvent];
4090 }
4091
4092 - (BOOL)isHoverFeedbackSuspended
4093 {
4094     return _private->hoverFeedbackSuspended;
4095 }
4096
4097 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady
4098 {
4099     // by setting this to NO, calls to mainFrameDocument are forced to return nil
4100     // setting this to YES lets it return the actual DOMDocument value
4101     // we use this to tell NSTreeController to reset its observers and clear its state
4102     if (_private->mainFrameDocumentReady == mainFrameDocumentReady)
4103         return;
4104     [self _willChangeValueForKey:_WebMainFrameDocumentKey];
4105     _private->mainFrameDocumentReady = mainFrameDocumentReady;
4106     [self _didChangeValueForKey:_WebMainFrameDocumentKey];
4107     // this will cause observers to call mainFrameDocument where this flag will be checked
4108 }
4109
4110 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it 
4111 // until the day comes when we're no longer supporting Mail on Tiger.
4112 - (WebFrame *)_frameForCurrentSelection
4113 {
4114     return [self _selectedOrMainFrame];
4115 }
4116
4117 - (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements
4118 {
4119     _private->tabKeyCyclesThroughElementsChanged = YES;
4120     if (_private->page)
4121         _private->page->setTabKeyCyclesThroughElements(cyclesElements);
4122 }
4123
4124 - (BOOL)tabKeyCyclesThroughElements
4125 {
4126     return _private->page && _private->page->tabKeyCyclesThroughElements();
4127 }
4128
4129 - (void)setScriptDebugDelegate:(id)delegate
4130 {
4131     _private->scriptDebugDelegate = delegate;
4132     [self _cacheScriptDebugDelegateImplementations];
4133
4134     if (delegate)
4135         [self _attachScriptDebuggerToAllFrames];
4136     else
4137         [self _detachScriptDebuggerFromAllFrames];
4138 }
4139
4140 - (id)scriptDebugDelegate
4141 {
4142     return _private->scriptDebugDelegate;
4143 }
4144   
4145 - (void)setHistoryDelegate:(id)delegate
4146 {
4147     _private->historyDelegate = delegate;
4148     [self _cacheHistoryDelegateImplementations];
4149 }
4150
4151 - (id)historyDelegate
4152 {
4153     return _private->historyDelegate;
4154 }
4155
4156 - (BOOL)shouldClose
4157 {
4158     Frame* coreFrame = [self _mainCoreFrame];
4159     if (!coreFrame)
4160         return YES;
4161     return coreFrame->shouldClose();
4162 }
4163
4164 static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue jsValue)
4165 {
4166     NSAppleEventDescriptor* aeDesc = 0;
4167     if (jsValue.isBoolean())
4168         return [NSAppleEventDescriptor descriptorWithBoolean:jsValue.getBoolean()];
4169     if (jsValue.isString())
4170         return [NSAppleEventDescriptor descriptorWithString:ustringToString(jsValue.getString(exec))];
4171     if (jsValue.isNumber()) {
4172         double value = jsValue.uncheckedGetNumber();
4173         int intValue = value;
4174         if (value == intValue)
4175             return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)];
4176         return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)];
4177     }
4178     if (jsValue.isObject()) {
4179         JSObject* object = jsValue.getObject();
4180         if (object->inherits(&DateInstance::info)) {
4181             DateInstance* date = static_cast<DateInstance*>(object);
4182             double ms = date->internalNumber();
4183             if (!isnan(ms)) {
4184                 CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970;
4185                 LongDateTime ldt;
4186                 if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt))
4187                     return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)];
4188             }
4189         }
4190         else if (object->inherits(&JSArray::info)) {
4191             DEFINE_STATIC_LOCAL(HashSet<JSObject*>, visitedElems, ());
4192             if (!visitedElems.contains(object)) {
4193                 visitedElems.add(object);
4194                 
4195                 JSArray* array = static_cast<JSArray*>(object);
4196                 aeDesc = [NSAppleEventDescriptor listDescriptor];
4197                 unsigned numItems = array->length();
4198                 for (unsigned i = 0; i < numItems; ++i)
4199                     [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->get(exec, i)) atIndex:0];
4200                 
4201                 visitedElems.remove(object);
4202                 return aeDesc;
4203             }
4204         }
4205         JSValue primitive = object->toPrimitive(exec);
4206         if (exec->hadException()) {
4207             exec->clearException();
4208             return [NSAppleEventDescriptor nullDescriptor];
4209         }
4210         return aeDescFromJSValue(exec, primitive);
4211     }
4212     if (jsValue.isUndefined())
4213         return [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue];
4214     ASSERT(jsValue.isNull());
4215     return [NSAppleEventDescriptor nullDescriptor];
4216 }
4217
4218 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
4219 {
4220     Frame* coreFrame = [self _mainCoreFrame];
4221     if (!coreFrame)
4222         return nil;
4223     if (!coreFrame->document())
4224         return nil;
4225     JSValue result = coreFrame->script()->executeScript(script, true).jsValue();
4226     if (!result) // FIXME: pass errors
4227         return 0;
4228     JSLock lock(SilenceAssertionsOnly);
4229     return aeDescFromJSValue(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(), result);
4230 }
4231
4232 - (BOOL)canMarkAllTextMatches
4233 {
4234     WebFrame *frame = [self mainFrame];
4235     do {
4236         id <WebDocumentView> view = [[frame frameView] documentView];
4237         if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)])
4238             return NO;
4239         
4240         frame = incrementFrame(frame, YES, NO);
4241     } while (frame);
4242     
4243     return YES;
4244 }
4245
4246 - (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit
4247 {
4248     WebFrame *frame = [self mainFrame];
4249     unsigned matchCount = 0;
4250     do {
4251         id <WebDocumentView> view = [[frame frameView] documentView];
4252         if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
4253             [(NSView <WebMultipleTextMatches>*)view  setMarkedTextMatchesAreHighlighted:highlight];
4254         
4255             ASSERT(limit == 0 || matchCount < limit);
4256             matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount];
4257
4258             // Stop looking if we've reached the limit. A limit of 0 means no limit.
4259             if (limit > 0 && matchCount >= limit)
4260                 break;
4261         }
4262         
4263         frame = incrementFrame(frame, YES, NO);
4264     } while (frame);
4265     
4266     return matchCount;
4267 }
4268
4269 - (void)unmarkAllTextMatches
4270 {
4271     WebFrame *frame = [self mainFrame];
4272     do {
4273         id <WebDocumentView> view = [[frame frameView] documentView];
4274         if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)])
4275             [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches];
4276         
4277         frame = incrementFrame(frame, YES, NO);
4278     } while (frame);
4279 }
4280
4281 - (NSArray *)rectsForTextMatches
4282 {
4283     NSMutableArray *result = [NSMutableArray array];
4284     WebFrame *frame = [self mainFrame];
4285     do {
4286         id <WebDocumentView> view = [[frame frameView] documentView];
4287         if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
4288             NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view;
4289             NSRect documentViewVisibleRect = [documentView visibleRect];
4290             NSArray *originalRects = [documentView rectsForTextMatches];
4291             unsigned rectCount = [originalRects count];
4292             unsigned rectIndex;
4293             NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4294             for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
4295                 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue];
4296                 // Clip rect to document view's visible rect so rect is confined to subframe
4297                 r = NSIntersectionRect(r, documentViewVisibleRect);
4298                 if (NSIsEmptyRect(r))
4299                     continue;
4300                 
4301                 // Convert rect to our coordinate system
4302                 r = [documentView convertRect:r toView:self];
4303                 [result addObject:[NSValue valueWithRect:r]];
4304                 if (rectIndex % 10 == 0) {
4305                     [pool drain];
4306                     pool = [[NSAutoreleasePool alloc] init];
4307                 }
4308             }
4309             [pool drain];
4310         }
4311         
4312         frame = incrementFrame(frame, YES, NO);
4313     } while (frame);
4314     
4315     return result;
4316 }
4317
4318 - (void)scrollDOMRangeToVisible:(DOMRange *)range
4319 {
4320     [[[[range startContainer] ownerDocument] webFrame] _scrollDOMRangeToVisible:range];
4321 }
4322
4323 - (BOOL)allowsUndo
4324 {
4325     return _private->allowsUndo;
4326 }
4327
4328 - (void)setAllowsUndo:(BOOL)flag
4329 {
4330     _private->allowsUndo = flag;
4331 }
4332
4333 - (void)setPageSizeMultiplier:(float)m
4334 {
4335     [self _setZoomMultiplier:m isTextOnly:NO];
4336 }
4337
4338 - (float)pageSizeMultiplier
4339 {
4340     return ![self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f;
4341 }
4342
4343 - (BOOL)canZoomPageIn
4344 {
4345     return [self _canZoomIn:NO];
4346 }
4347
4348 - (IBAction)zoomPageIn:(id)sender
4349 {
4350     return [self _zoomIn:sender isTextOnly:NO];
4351 }
4352
4353 - (BOOL)canZoomPageOut
4354 {
4355     return [self _canZoomOut:NO];
4356 }
4357
4358 - (IBAction)zoomPageOut:(id)sender
4359 {
4360     return [self _zoomOut:sender isTextOnly:NO];
4361 }
4362
4363 - (BOOL)canResetPageZoom
4364 {
4365     return [self _canResetZoom:NO];
4366 }
4367
4368 - (IBAction)resetPageZoom:(id)sender
4369 {
4370     return [self _resetZoom:sender isTextOnly:NO];
4371 }
4372
4373 - (void)setMediaVolume:(float)volume
4374 {
4375     if (_private->page)
4376         _private->page->setMediaVolume(volume);
4377 }
4378
4379 - (float)mediaVolume
4380 {
4381     if (!_private->page)
4382         return 0;
4383
4384     return _private->page->mediaVolume();
4385 }
4386
4387 - (void)addVisitedLinks:(NSArray *)visitedLinks
4388 {
4389     PageGroup& group = core(self)->group();
4390     
4391     NSEnumerator *enumerator = [visitedLinks objectEnumerator];
4392     while (NSString *url = [enumerator nextObject]) {
4393         size_t length = [url length];
4394         const UChar* characters = CFStringGetCharactersPtr(reinterpret_cast<CFStringRef>(url));
4395         if (characters)
4396             group.addVisitedLink(characters, length);
4397         else {
4398             Vector<UChar, 512> buffer(length);
4399             [url getCharacters:buffer.data()];
4400             group.addVisitedLink(buffer.data(), length);
4401         }
4402     }
4403 }
4404
4405 @end
4406
4407 @implementation WebView (WebViewPrintingPrivate)
4408
4409 - (float)_headerHeight
4410 {
4411     return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:));
4412 }
4413
4414 - (float)_footerHeight
4415 {
4416     return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:));
4417 }
4418
4419 - (void)_drawHeaderInRect:(NSRect)rect
4420 {
4421 #ifdef DEBUG_HEADER_AND_FOOTER
4422     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
4423     [currentContext saveGraphicsState];
4424     [[NSColor yellowColor] set];
4425     NSRectFill(rect);
4426     [currentContext restoreGraphicsState];
4427 #endif
4428
4429     SEL selector = @selector(webView:drawHeaderInRect:);
4430     if (![_private->UIDelegate respondsToSelector:selector])
4431         return;
4432
4433     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
4434     [currentContext saveGraphicsState];
4435
4436     NSRectClip(rect);
4437     CallUIDelegate(self, selector, rect);
4438
4439     [currentContext restoreGraphicsState];
4440 }
4441
4442 - (void)_drawFooterInRect:(NSRect)rect
4443 {
4444 #ifdef DEBUG_HEADER_AND_FOOTER
4445     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
4446     [currentContext saveGraphicsState];
4447     [[NSColor cyanColor] set];
4448     NSRectFill(rect);
4449     [currentContext restoreGraphicsState];
4450 #endif
4451     
4452     SEL selector = @selector(webView:drawFooterInRect:);
4453     if (![_private->UIDelegate respondsToSelector:selector])
4454         return;
4455
4456     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
4457     [currentContext saveGraphicsState];
4458
4459     NSRectClip(rect);
4460     CallUIDelegate(self, selector, rect);
4461
4462     [currentContext restoreGraphicsState];
4463 }
4464
4465 - (void)_adjustPrintingMarginsForHeaderAndFooter
4466 {
4467     NSPrintOperation *op = [NSPrintOperation currentOperation];
4468     NSPrint