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