bfa0944f99077aa25bea762ce6461363e29a2132
[WebKit.git] / Source / WebKit / mac / WebView / WebHTMLView.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *           (C) 2006, 2007 Graham Dennis (graham.dennis@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 "WebHTMLView.h"
31
32 #import "DOMCSSStyleDeclarationInternal.h"
33 #import "DOMDocumentFragmentInternal.h"
34 #import "DOMDocumentInternal.h"
35 #import "DOMNodeInternal.h"
36 #import "DOMRangeInternal.h"
37 #import "WebArchive.h"
38 #import "WebClipView.h"
39 #import "WebDOMOperationsInternal.h"
40 #import "WebDataSourceInternal.h"
41 #import "WebDefaultUIDelegate.h"
42 #import "WebDelegateImplementationCaching.h"
43 #import "WebDocumentInternal.h"
44 #import "WebDynamicScrollBarsView.h"
45 #import "WebEditingDelegate.h"
46 #import "WebElementDictionary.h"
47 #import "WebFrameInternal.h"
48 #import "WebFramePrivate.h"
49 #import "WebFrameViewInternal.h"
50 #import "WebHTMLRepresentationPrivate.h"
51 #import "WebHTMLViewInternal.h"
52 #import "WebKitLogging.h"
53 #import "WebKitNSStringExtras.h"
54 #import "WebKitVersionChecks.h"
55 #import "WebLocalizableStrings.h"
56 #import "WebNSAttributedStringExtras.h"
57 #import "WebNSEventExtras.h"
58 #import "WebNSFileManagerExtras.h"
59 #import "WebNSImageExtras.h"
60 #import "WebNSObjectExtras.h"
61 #import "WebNSPasteboardExtras.h"
62 #import "WebNSPrintOperationExtras.h"
63 #import "WebNSURLExtras.h"
64 #import "WebNSViewExtras.h"
65 #import "WebNetscapePluginView.h"
66 #import "WebNodeHighlight.h"
67 #import "WebPluginController.h"
68 #import "WebPreferences.h"
69 #import "WebPreferencesPrivate.h"
70 #import "WebResourcePrivate.h"
71 #import "WebTextCompletionController.h"
72 #import "WebTypesInternal.h"
73 #import "WebUIDelegatePrivate.h"
74 #import "WebViewInternal.h"
75 #import <AppKit/NSAccessibility.h>
76 #import <ApplicationServices/ApplicationServices.h>
77 #import <WebCore/CSSMutableStyleDeclaration.h>
78 #import <WebCore/CachedImage.h>
79 #import <WebCore/CachedResourceClient.h>
80 #import <WebCore/ColorMac.h>
81 #import <WebCore/ContextMenu.h>
82 #import <WebCore/ContextMenuController.h>
83 #import <WebCore/Document.h>
84 #import <WebCore/DocumentFragment.h>
85 #import <WebCore/DocumentMarkerController.h>
86 #import <WebCore/DragController.h>
87 #import <WebCore/Editor.h>
88 #import <WebCore/EditorDeleteAction.h>
89 #import <WebCore/Element.h>
90 #import <WebCore/EventHandler.h>
91 #import <WebCore/ExceptionHandlers.h>
92 #import <WebCore/FloatRect.h>
93 #import <WebCore/FocusController.h>
94 #import <WebCore/Frame.h>
95 #import <WebCore/FrameLoader.h>
96 #import <WebCore/FrameView.h>
97 #import <WebCore/HTMLNames.h>
98 #import <WebCore/HitTestResult.h>
99 #import <WebCore/Image.h>
100 #import <WebCore/KeyboardEvent.h>
101 #import <WebCore/LegacyWebArchive.h>
102 #import <WebCore/MIMETypeRegistry.h>
103 #import <WebCore/Page.h>
104 #import <WebCore/PlatformKeyboardEvent.h>
105 #import <WebCore/Range.h>
106 #import <WebCore/RenderWidget.h>
107 #import <WebCore/RuntimeApplicationChecks.h>
108 #import <WebCore/SelectionController.h>
109 #import <WebCore/SharedBuffer.h>
110 #import <WebCore/SimpleFontData.h>
111 #import <WebCore/Text.h>
112 #import <WebCore/WebCoreObjCExtras.h>
113 #import <WebCore/WebFontCache.h>
114 #import <WebCore/markup.h>
115 #import <WebKit/DOM.h>
116 #import <WebKit/DOMExtensions.h>
117 #import <WebKit/DOMPrivate.h>
118 #import <WebKitSystemInterface.h>
119 #import <dlfcn.h>
120 #import <limits>
121 #import <runtime/InitializeThreading.h>
122 #import <wtf/Threading.h>
123
124 #if USE(ACCELERATED_COMPOSITING)
125 #import <QuartzCore/QuartzCore.h>
126 #endif
127
128 using namespace WebCore;
129 using namespace HTMLNames;
130 using namespace WTF;
131 using namespace std;
132
133 @interface WebMenuTarget : NSObject {
134     WebCore::ContextMenuController* _menuController;
135 }
136 + (WebMenuTarget*)sharedMenuTarget;
137 - (WebCore::ContextMenuController*)menuController;
138 - (void)setMenuController:(WebCore::ContextMenuController*)menuController;
139 - (void)forwardContextMenuAction:(id)sender;
140 - (BOOL)validateMenuItem:(NSMenuItem *)item;
141 @end
142
143 static WebMenuTarget* target;
144
145 @implementation WebMenuTarget
146
147 + (WebMenuTarget*)sharedMenuTarget
148 {
149     if (!target)
150         target = [[WebMenuTarget alloc] init];
151     return target;
152 }
153
154 - (WebCore::ContextMenuController*)menuController
155 {
156     return _menuController;
157 }
158
159 - (void)setMenuController:(WebCore::ContextMenuController*)menuController
160 {
161     _menuController = menuController;
162 }
163
164 - (void)forwardContextMenuAction:(id)sender
165 {
166     WebCore::ContextMenuItem item(WebCore::ActionType, static_cast<WebCore::ContextMenuAction>([sender tag]), [sender title]);
167     _menuController->contextMenuItemSelected(&item);
168 }
169
170 - (BOOL)validateMenuItem:(NSMenuItem *)item
171 {
172     WebCore::ContextMenuItem coreItem(item);
173     ASSERT(_menuController->contextMenu());
174     _menuController->checkOrEnableIfNeeded(coreItem);
175     return coreItem.enabled();
176 }
177
178 @end
179
180 @interface NSWindow (BorderViewAccess)
181 - (NSView*)_web_borderView;
182 @end
183
184 @implementation NSWindow (BorderViewAccess)
185 - (NSView*)_web_borderView
186 {
187     return _borderView;
188 }
189 @end
190
191 @interface WebResponderChainSink : NSResponder {
192     NSResponder* _lastResponderInChain;
193     BOOL _receivedUnhandledCommand;
194 }
195 - (id)initWithResponderChain:(NSResponder *)chain;
196 - (void)detach;
197 - (BOOL)receivedUnhandledCommand;
198 @end
199
200 // if YES, do the standard NSView hit test (which can't give the right result when HTML overlaps a view)
201 static BOOL forceNSViewHitTest;
202
203 // if YES, do the "top WebHTMLView" hit test (which we'd like to do all the time but can't because of Java requirements [see bug 4349721])
204 static BOOL forceWebHTMLViewHitTest;
205
206 static WebHTMLView *lastHitView;
207
208 static bool needsCursorRectsSupportAtPoint(NSWindow* window, NSPoint point)
209 {
210     forceNSViewHitTest = YES;
211     NSView* view = [[window _web_borderView] hitTest:point];
212     forceNSViewHitTest = NO;
213
214     // WebHTMLView doesn't use cursor rects.
215     if ([view isKindOfClass:[WebHTMLView class]])
216         return false;
217
218 #if ENABLE(NETSCAPE_PLUGIN_API)
219     // Neither do NPAPI plug-ins.
220     if ([view isKindOfClass:[WebBaseNetscapePluginView class]])
221         return false;
222 #endif
223
224     // Non-Web content, WebPDFView, and WebKit plug-ins use normal cursor handling.
225     return true;
226 }
227
228 #ifndef BUILDING_ON_TIGER
229
230 static IMP oldSetCursorForMouseLocationIMP;
231
232 // Overriding an internal method is a hack; <rdar://problem/7662987> tracks finding a better solution.
233 static void setCursor(NSWindow *self, SEL cmd, NSPoint point)
234 {
235     if (needsCursorRectsSupportAtPoint(self, point))
236         oldSetCursorForMouseLocationIMP(self, cmd, point);
237 }
238
239 #else
240
241 static IMP oldResetCursorRectsIMP;
242 static IMP oldSetCursorIMP;
243 static BOOL canSetCursor = YES;
244
245 static void resetCursorRects(NSWindow* self, SEL cmd)
246 {
247     canSetCursor = needsCursorRectsSupportAtPoint(self, [self mouseLocationOutsideOfEventStream]);
248     oldResetCursorRectsIMP(self, cmd);
249     canSetCursor = YES;
250 }
251
252 static void setCursor(NSCursor* self, SEL cmd)
253 {
254     if (canSetCursor)
255         oldSetCursorIMP(self, cmd);
256 }
257
258 #endif
259
260 extern "C" {
261
262 // Need to declare these attribute names because AppKit exports them but does not make them available in API or SPI headers.
263
264 extern NSString *NSMarkedClauseSegmentAttributeName;
265 extern NSString *NSTextInputReplacementRangeAttributeName;
266
267 }
268
269 @interface NSView (WebNSViewDetails)
270 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView;
271 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect;
272 - (void)_recursive:(BOOL)recurse displayRectIgnoringOpacity:(NSRect)displayRect inContext:(NSGraphicsContext *)context topView:(BOOL)topView;
273 - (NSRect)_dirtyRect;
274 - (void)_setDrawsOwnDescendants:(BOOL)drawsOwnDescendants;
275 - (BOOL)_drawnByAncestor;
276 - (void)_invalidateGStatesForTree;
277 - (void)_propagateDirtyRectsToOpaqueAncestors;
278 - (void)_windowChangedKeyState;
279 #if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD)
280 - (void)_updateLayerGeometryFromView;
281 #endif
282 @end
283
284 #if USE(ACCELERATED_COMPOSITING)
285 static IMP oldSetNeedsDisplayInRectIMP;
286
287 static void setNeedsDisplayInRect(NSView *self, SEL cmd, NSRect invalidRect)
288 {
289     if (![self _drawnByAncestor]) {
290         oldSetNeedsDisplayInRectIMP(self, cmd, invalidRect);
291         return;
292     }
293
294     static Class webFrameViewClass = [WebFrameView class];
295     WebFrameView *enclosingWebFrameView = (WebFrameView *)self;
296     while (enclosingWebFrameView && ![enclosingWebFrameView isKindOfClass:webFrameViewClass])
297         enclosingWebFrameView = (WebFrameView *)[enclosingWebFrameView superview];
298
299     if (!enclosingWebFrameView) {
300         oldSetNeedsDisplayInRectIMP(self, cmd, invalidRect);
301         return;
302     }
303
304     Frame* coreFrame = core([enclosingWebFrameView webFrame]);
305     FrameView* frameView = coreFrame ? coreFrame->view() : 0;
306     if (!frameView || !frameView->isEnclosedInCompositingLayer()) {
307         oldSetNeedsDisplayInRectIMP(self, cmd, invalidRect);
308         return;
309     }
310
311     NSRect invalidRectInWebFrameViewCoordinates = [enclosingWebFrameView convertRect:invalidRect fromView:self];
312     IntRect invalidRectInFrameViewCoordinates(invalidRectInWebFrameViewCoordinates);
313     if (![enclosingWebFrameView isFlipped])
314         invalidRectInFrameViewCoordinates.setY(frameView->frameRect().size().height() - invalidRectInFrameViewCoordinates.bottom());
315
316     frameView->invalidateRect(invalidRectInFrameViewCoordinates);
317 }
318 #endif // USE(ACCELERATED_COMPOSITING)
319
320 @interface NSApplication (WebNSApplicationDetails)
321 - (void)speakString:(NSString *)string;
322 @end
323
324 @interface NSWindow (WebNSWindowDetails)
325 - (id)_newFirstResponderAfterResigning;
326 @end
327
328 @interface NSAttributedString (WebNSAttributedStringDetails)
329 - (id)_initWithDOMRange:(DOMRange *)range;
330 - (DOMDocumentFragment *)_documentFromRange:(NSRange)range document:(DOMDocument *)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources;
331 @end
332
333 @interface NSSpellChecker (WebNSSpellCheckerDetails)
334 - (void)learnWord:(NSString *)word;
335 @end
336
337 // By imaging to a width a little wider than the available pixels,
338 // thin pages will be scaled down a little, matching the way they
339 // print in IE and Camino. This lets them use fewer sheets than they
340 // would otherwise, which is presumably why other browsers do this.
341 // Wide pages will be scaled down more than this.
342 const float _WebHTMLViewPrintingMinimumShrinkFactor = 1.25;
343
344 // This number determines how small we are willing to reduce the page content
345 // in order to accommodate the widest line. If the page would have to be
346 // reduced smaller to make the widest line fit, we just clip instead (this
347 // behavior matches MacIE and Mozilla, at least)
348 const float _WebHTMLViewPrintingMaximumShrinkFactor = 2;
349
350 #define AUTOSCROLL_INTERVAL             0.1f
351
352 // Any non-zero value will do, but using something recognizable might help us debug some day.
353 #define TRACKING_RECT_TAG 0xBADFACE
354
355 // FIXME: This constant is copied from AppKit's _NXSmartPaste constant.
356 #define WebSmartPastePboardType @"NeXT smart paste pasteboard type"
357
358 #define STANDARD_WEIGHT 5
359 #define MIN_BOLD_WEIGHT 7
360 #define STANDARD_BOLD_WEIGHT 9
361
362 // Fake URL scheme.
363 #define WebDataProtocolScheme @"webkit-fake-url"
364
365 // <rdar://problem/4985524> References to WebCoreScrollView as a subview of a WebHTMLView may be present
366 // in some NIB files, so NSUnarchiver must be still able to look up this now-unused class.
367 @interface WebCoreScrollView : NSScrollView
368 @end
369
370 @implementation WebCoreScrollView
371 @end
372
373 // We need this to be able to safely reference the CachedImage for the promised drag data
374 static CachedResourceClient* promisedDataClient()
375 {
376     static CachedResourceClient* staticCachedResourceClient = new CachedResourceClient;
377     return staticCachedResourceClient;
378 }
379
380 @interface WebHTMLView (WebHTMLViewFileInternal)
381 - (BOOL)_imageExistsAtPaths:(NSArray *)paths;
382 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard inContext:(DOMRange *)context allowPlainText:(BOOL)allowPlainText;
383 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard;
384 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText;
385 - (void)_removeMouseMovedObserverUnconditionally;
386 - (void)_removeSuperviewObservers;
387 - (void)_removeWindowObservers;
388 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
389 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
390 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action;
391 - (DOMRange *)_selectedRange;
392 - (BOOL)_shouldDeleteRange:(DOMRange *)range;
393 - (NSView *)_hitViewForEvent:(NSEvent *)event;
394 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString;
395 - (DOMRange *)_documentRange;
396 - (void)_setMouseDownEvent:(NSEvent *)event;
397 - (WebHTMLView *)_topHTMLView;
398 - (BOOL)_isTopHTMLView;
399 - (void)_web_setPrintingModeRecursive;
400 - (void)_web_setPrintingModeRecursiveAndAdjustViewSize;
401 - (void)_web_clearPrintingModeRecursive;
402 @end
403
404 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
405
406 @interface WebHTMLView (WebHTMLViewTextCheckingInternal)
407 - (void)orderFrontSubstitutionsPanel:(id)sender;
408 - (BOOL)smartInsertDeleteEnabled;
409 - (void)setSmartInsertDeleteEnabled:(BOOL)flag;
410 - (void)toggleSmartInsertDelete:(id)sender;
411 - (BOOL)isAutomaticQuoteSubstitutionEnabled;
412 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag;
413 - (void)toggleAutomaticQuoteSubstitution:(id)sender;
414 - (BOOL)isAutomaticLinkDetectionEnabled;
415 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag;
416 - (void)toggleAutomaticLinkDetection:(id)sender;
417 - (BOOL)isAutomaticDashSubstitutionEnabled;
418 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag;
419 - (void)toggleAutomaticDashSubstitution:(id)sender;
420 - (BOOL)isAutomaticTextReplacementEnabled;
421 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag;
422 - (void)toggleAutomaticTextReplacement:(id)sender;
423 - (BOOL)isAutomaticSpellingCorrectionEnabled;
424 - (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag;
425 - (void)toggleAutomaticSpellingCorrection:(id)sender;
426 @end
427
428 #endif
429
430 @interface WebHTMLView (WebForwardDeclaration) // FIXME: Put this in a normal category and stop doing the forward declaration trick.
431 - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth height:(float)minPageHeight maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize paginateScreenContent:(BOOL)paginateScreenContent;
432 @end
433
434 @class NSTextInputContext;
435 @interface NSResponder (AppKitDetails)
436 - (NSTextInputContext *)inputContext;
437 @end
438
439 @interface NSObject (NSTextInputContextDetails)
440 - (BOOL)wantsToHandleMouseEvents;
441 - (BOOL)handleMouseEvent:(NSEvent *)event;
442 @end
443
444 @interface WebHTMLView (WebNSTextInputSupport) <NSTextInput>
445 - (void)_updateSelectionForInputManager;
446 @end
447
448 @interface WebHTMLView (WebEditingStyleSupport)
449 - (DOMCSSStyleDeclaration *)_emptyStyle;
450 - (NSString *)_colorAsString:(NSColor *)color;
451 @end
452
453 @interface NSView (WebHTMLViewFileInternal)
454 - (void)_web_addDescendantWebHTMLViewsToArray:(NSMutableArray *) array;
455 @end
456
457 @interface NSMutableDictionary (WebHTMLViewFileInternal)
458 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key;
459 @end
460
461 struct WebHTMLViewInterpretKeyEventsParameters {
462     KeyboardEvent* event;
463     BOOL eventWasHandled;
464     BOOL shouldSaveCommand;
465     // The Input Method may consume an event and not tell us, in
466     // which case we should not bubble the event up the DOM
467     BOOL consumedByIM;
468 };
469
470 @interface WebHTMLViewPrivate : NSObject {
471 @public
472     BOOL closed;
473     BOOL ignoringMouseDraggedEvents;
474     BOOL printing;
475     BOOL paginateScreenContent;
476     BOOL observingMouseMovedNotifications;
477     BOOL observingSuperviewNotifications;
478     BOOL observingWindowNotifications;
479     
480     id savedSubviews;
481     BOOL subviewsSetAside;
482
483 #if USE(ACCELERATED_COMPOSITING)
484     NSView *layerHostingView;
485     BOOL drawingIntoLayer;
486 #endif
487
488     NSEvent *mouseDownEvent; // Kept after handling the event.
489     BOOL handlingMouseDownEvent;
490     NSEvent *keyDownEvent; // Kept after handling the event.
491
492     // A WebHTMLView has a single input context, but we return nil when in non-editable content to avoid making input methods do their work.
493     // This state is saved each time selection changes, because computing it causes style recalc, which is not always safe to do.
494     BOOL exposeInputContext;
495
496     NSPoint lastScrollPosition;
497 #ifndef BUILDING_ON_TIGER
498     BOOL inScrollPositionChanged;
499 #endif
500
501     WebPluginController *pluginController;
502     
503     NSString *toolTip;
504     NSToolTipTag lastToolTipTag;
505     id trackingRectOwner;
506     void *trackingRectUserData;
507     
508     NSTimer *autoscrollTimer;
509     NSEvent *autoscrollTriggerEvent;
510     
511     NSArray *pageRects;
512
513     NSMutableDictionary *highlighters;
514
515 #ifdef BUILDING_ON_TIGER
516     BOOL nextResponderDisabledOnce;
517 #endif
518     
519     WebTextCompletionController *completionController;
520     
521     BOOL transparentBackground;
522
523     WebHTMLViewInterpretKeyEventsParameters* interpretKeyEventsParameters;
524     BOOL receivedNOOP;
525     
526     WebDataSource *dataSource;
527     WebCore::CachedImage* promisedDragTIFFDataSource;
528     
529     CFRunLoopTimerRef updateMouseoverTimer;
530
531     SEL selectorForDoCommandBySelector;
532
533 #ifndef NDEBUG
534     BOOL enumeratingSubviews;
535 #endif
536 }
537 - (void)clear;
538 @end
539
540 static NSCellStateValue kit(TriState state)
541 {
542     switch (state) {
543         case FalseTriState:
544             return NSOffState;
545         case TrueTriState:
546             return NSOnState;
547         case MixedTriState:
548             return NSMixedState;
549     }
550     ASSERT_NOT_REACHED();
551     return NSOffState;
552 }
553
554 static FindOptions coreOptions(WebFindOptions options)
555 {
556     return (options & WebFindOptionsCaseInsensitive ? CaseInsensitive : 0)
557         | (options & WebFindOptionsAtWordStarts ? AtWordStarts : 0)
558         | (options & WebFindOptionsTreatMedialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0)
559         | (options & WebFindOptionsBackwards ? Backwards : 0)
560         | (options & WebFindOptionsWrapAround ? WrapAround : 0)
561         | (options & WebFindOptionsStartInSelection ? StartInSelection : 0);
562 }
563
564 @implementation WebHTMLViewPrivate
565
566 + (void)initialize
567 {
568     JSC::initializeThreading();
569     WTF::initializeMainThreadToProcessMainThread();
570 #ifndef BUILDING_ON_TIGER
571     WebCoreObjCFinalizeOnMainThread(self);
572 #endif
573     
574 #ifndef BUILDING_ON_TIGER
575     if (!oldSetCursorForMouseLocationIMP) {
576         Method setCursorMethod = class_getInstanceMethod([NSWindow class], @selector(_setCursorForMouseLocation:));
577         ASSERT(setCursorMethod);
578         oldSetCursorForMouseLocationIMP = method_setImplementation(setCursorMethod, (IMP)setCursor);
579         ASSERT(oldSetCursorForMouseLocationIMP);
580     }
581
582 #if USE(ACCELERATED_COMPOSITING)
583     if (!oldSetNeedsDisplayInRectIMP) {
584         Method setNeedsDisplayInRectMethod = class_getInstanceMethod([NSView class], @selector(setNeedsDisplayInRect:));
585         ASSERT(setNeedsDisplayInRectMethod);
586         oldSetNeedsDisplayInRectIMP = method_setImplementation(setNeedsDisplayInRectMethod, (IMP)setNeedsDisplayInRect);
587         ASSERT(oldSetNeedsDisplayInRectIMP);
588     }
589 #endif // USE(ACCELERATED_COMPOSITING)
590
591 #else // defined(BUILDING_ON_TIGER)
592     if (!oldSetCursorIMP) {
593         Method setCursorMethod = class_getInstanceMethod([NSCursor class], @selector(set));
594         ASSERT(setCursorMethod);
595         oldSetCursorIMP = method_setImplementation(setCursorMethod, (IMP)setCursor);
596         ASSERT(oldSetCursorIMP);
597     }
598     if (!oldResetCursorRectsIMP) {
599         Method resetCursorRectsMethod = class_getInstanceMethod([NSWindow class], @selector(resetCursorRects));
600         ASSERT(resetCursorRectsMethod);
601         oldResetCursorRectsIMP = method_setImplementation(resetCursorRectsMethod, (IMP)resetCursorRects);
602         ASSERT(oldResetCursorRectsIMP);
603     }
604 #endif
605
606 }
607
608 - (void)dealloc
609 {
610     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHTMLViewPrivate class], self))
611         return;
612
613     ASSERT(!autoscrollTimer);
614     ASSERT(!autoscrollTriggerEvent);
615     ASSERT(!updateMouseoverTimer);
616     
617     [mouseDownEvent release];
618     [keyDownEvent release];
619     [pluginController release];
620     [toolTip release];
621     [completionController release];
622     [dataSource release];
623     [highlighters release];
624     if (promisedDragTIFFDataSource)
625         promisedDragTIFFDataSource->removeClient(promisedDataClient());
626
627     [super dealloc];
628 }
629
630 - (void)finalize
631 {
632     ASSERT_MAIN_THREAD();
633
634     if (promisedDragTIFFDataSource)
635         promisedDragTIFFDataSource->removeClient(promisedDataClient());
636
637     [super finalize];
638 }
639
640 - (void)clear
641 {
642     [mouseDownEvent release];
643     [keyDownEvent release];
644     [pluginController release];
645     [toolTip release];
646     [completionController release];
647     [dataSource release];
648     [highlighters release];
649     if (promisedDragTIFFDataSource)
650         promisedDragTIFFDataSource->removeClient(promisedDataClient());
651
652     mouseDownEvent = nil;
653     keyDownEvent = nil;
654     pluginController = nil;
655     toolTip = nil;
656     completionController = nil;
657     dataSource = nil;
658     highlighters = nil;
659     promisedDragTIFFDataSource = 0;
660
661 #if USE(ACCELERATED_COMPOSITING)
662     layerHostingView = nil;
663 #endif
664 }
665
666 @end
667
668 @implementation WebHTMLView (WebHTMLViewFileInternal)
669
670 - (DOMRange *)_documentRange
671 {
672     return [[[self _frame] DOMDocument] _documentRange];
673 }
674
675 - (BOOL)_imageExistsAtPaths:(NSArray *)paths
676 {
677     NSEnumerator *enumerator = [paths objectEnumerator];
678     NSString *path;
679     
680     while ((path = [enumerator nextObject]) != nil) {
681         NSString *MIMEType = WKGetMIMETypeForExtension([path pathExtension]);
682         if (MIMETypeRegistry::isSupportedImageResourceMIMEType(MIMEType))
683             return YES;
684     }
685     
686     return NO;
687 }
688
689 - (WebDataSource *)_dataSource
690 {
691     return _private->dataSource;
692 }
693
694 - (WebView *)_webView
695 {
696     return [_private->dataSource _webView];
697 }
698
699 - (WebFrameView *)_frameView
700 {
701     return [[_private->dataSource webFrame] frameView];
702 }
703
704 - (DOMDocumentFragment *)_documentFragmentWithPaths:(NSArray *)paths
705 {
706     DOMDocumentFragment *fragment;
707     NSEnumerator *enumerator = [paths objectEnumerator];
708     NSMutableArray *domNodes = [[NSMutableArray alloc] init];
709     NSString *path;
710     
711     while ((path = [enumerator nextObject]) != nil) {
712         // Non-image file types; _web_userVisibleString is appropriate here because this will
713         // be pasted as visible text.
714         NSString *url = [[[NSURL fileURLWithPath:path] _webkit_canonicalize] _web_userVisibleString];
715         [domNodes addObject:[[[self _frame] DOMDocument] createTextNode: url]];
716     }
717     
718     fragment = [[self _frame] _documentFragmentWithNodesAsParagraphs:domNodes]; 
719     
720     [domNodes release];
721     
722     return [fragment firstChild] != nil ? fragment : nil;
723 }
724
725 + (NSArray *)_excludedElementsForAttributedStringConversion
726 {
727     static NSArray *elements = nil;
728     if (elements == nil) {
729         elements = [[NSArray alloc] initWithObjects:
730             // Omit style since we want style to be inline so the fragment can be easily inserted.
731             @"style",
732             // Omit xml so the result is not XHTML.
733             @"xml", 
734             // Omit tags that will get stripped when converted to a fragment anyway.
735             @"doctype", @"html", @"head", @"body",
736             // Omit deprecated tags.
737             @"applet", @"basefont", @"center", @"dir", @"font", @"isindex", @"menu", @"s", @"strike", @"u",
738             // Omit object so no file attachments are part of the fragment.
739             @"object", nil];
740         CFRetain(elements);
741     }
742     return elements;
743 }
744
745 static NSURL* uniqueURLWithRelativePart(NSString *relativePart)
746 {
747     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
748     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
749     CFRelease(UUIDRef);
750     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@/%@", WebDataProtocolScheme, UUIDString, relativePart]];
751     CFRelease(UUIDString);
752
753     return URL;
754 }
755
756 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
757                                                inContext:(DOMRange *)context
758                                           allowPlainText:(BOOL)allowPlainText
759 {
760     NSArray *types = [pasteboard types];
761     DOMDocumentFragment *fragment = nil;
762
763     if ([types containsObject:WebArchivePboardType] &&
764         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
765                                                   forType:WebArchivePboardType
766                                                 inContext:context
767                                              subresources:0]))
768         return fragment;
769                                            
770     if ([types containsObject:NSFilenamesPboardType] &&
771         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
772                                                   forType:NSFilenamesPboardType
773                                                 inContext:context
774                                              subresources:0]))
775         return fragment;
776     
777     if ([types containsObject:NSHTMLPboardType] &&
778         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
779                                                   forType:NSHTMLPboardType
780                                                 inContext:context
781                                              subresources:0]))
782         return fragment;
783     
784     if ([types containsObject:NSRTFDPboardType] &&
785         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
786                                                   forType:NSRTFDPboardType
787                                                 inContext:context
788                                              subresources:0]))
789         return fragment;
790     
791     if ([types containsObject:NSRTFPboardType] &&
792         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
793                                                   forType:NSRTFPboardType
794                                                 inContext:context
795                                              subresources:0]))
796         return fragment;
797
798     if ([types containsObject:NSTIFFPboardType] &&
799         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
800                                                   forType:NSTIFFPboardType
801                                                 inContext:context
802                                              subresources:0]))
803         return fragment;
804
805     if ([types containsObject:NSPDFPboardType] &&
806         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
807                                                   forType:NSPDFPboardType
808                                                 inContext:context
809                                              subresources:0]))
810         return fragment;
811
812 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
813     if ([types containsObject:NSPICTPboardType] &&
814         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
815                                                   forType:NSPICTPboardType
816                                                 inContext:context
817                                              subresources:0]))
818         return fragment;
819 #endif
820
821     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
822     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
823     if ([types containsObject:(NSString*)kUTTypePNG] &&
824         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
825                                                   forType:(NSString*)kUTTypePNG
826                                                 inContext:context
827                                              subresources:0]))
828         return fragment;
829         
830     if ([types containsObject:NSURLPboardType] &&
831         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
832                                                   forType:NSURLPboardType
833                                                 inContext:context
834                                              subresources:0]))
835         return fragment;
836         
837     if (allowPlainText && [types containsObject:NSStringPboardType] &&
838         (fragment = [self _documentFragmentFromPasteboard:pasteboard
839                                                   forType:NSStringPboardType
840                                                 inContext:context
841                                              subresources:0])) {
842         return fragment;
843     }
844     
845     return nil;
846 }
847
848 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard
849 {
850     NSArray *types = [pasteboard types];
851     
852     if ([types containsObject:NSStringPboardType])
853         return [[pasteboard stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping];
854     
855     NSAttributedString *attributedString = nil;
856     NSString *string;
857
858     if ([types containsObject:NSRTFDPboardType])
859         attributedString = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
860     if (attributedString == nil && [types containsObject:NSRTFPboardType])
861         attributedString = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
862     if (attributedString != nil) {
863         string = [[attributedString string] copy];
864         [attributedString release];
865         return [string autorelease];
866     }
867     
868     if ([types containsObject:NSFilenamesPboardType]) {
869         string = [[pasteboard propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"];
870         if (string != nil)
871             return string;
872     }
873     
874     NSURL *URL;
875     
876     if ((URL = [NSURL URLFromPasteboard:pasteboard])) {
877         string = [URL _web_userVisibleString];
878         if ([string length] > 0)
879             return string;
880     }
881     
882     return nil;
883 }
884
885 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText
886 {
887     WebView *webView = [[self _webView] retain];
888     [webView _setInsertionPasteboard:pasteboard];
889
890     DOMRange *range = [self _selectedRange];
891     Frame* coreFrame = core([self _frame]);
892     
893 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
894     DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
895     if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionPasted])
896         coreFrame->editor()->pasteAsFragment(core(fragment), [self _canSmartReplaceWithPasteboard:pasteboard], false);
897 #else
898     // Mail is ignoring the frament passed to the delegate and creates a new one.
899     // We want to avoid creating the fragment twice.
900     if (applicationIsAppleMail()) {
901         if ([self _shouldInsertFragment:nil replacingDOMRange:range givenAction:WebViewInsertActionPasted]) {
902             DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
903             if (fragment)
904                 coreFrame->editor()->pasteAsFragment(core(fragment), [self _canSmartReplaceWithPasteboard:pasteboard], false);
905         }        
906     } else {
907         DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
908         if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionPasted])
909             coreFrame->editor()->pasteAsFragment(core(fragment), [self _canSmartReplaceWithPasteboard:pasteboard], false);
910     }
911 #endif
912     [webView _setInsertionPasteboard:nil];
913     [webView release];
914 }
915
916 - (void)_removeMouseMovedObserverUnconditionally
917 {
918     if (!_private || !_private->observingMouseMovedNotifications)
919         return;
920     
921     [[NSNotificationCenter defaultCenter] removeObserver:self name:WKMouseMovedNotification() object:nil];
922     _private->observingMouseMovedNotifications = false;
923 }
924
925 - (void)_removeSuperviewObservers
926 {
927     if (!_private || !_private->observingSuperviewNotifications)
928         return;
929     
930     NSView *superview = [self superview];
931     if (!superview || ![self window])
932         return;
933     
934     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
935     [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:superview];
936     [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:superview];
937     
938     _private->observingSuperviewNotifications = false;
939 }
940
941 - (void)_removeWindowObservers
942 {
943     if (!_private->observingWindowNotifications)
944         return;
945     
946     NSWindow *window = [self window];
947     if (!window)
948         return;
949     
950     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
951     [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
952     [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
953     [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:window];
954     
955     _private->observingWindowNotifications = false;
956 }
957
958 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
959 {
960     WebView *webView = [self _webView];
961     DOMNode *child = [fragment firstChild];
962     if ([fragment lastChild] == child && [child isKindOfClass:[DOMCharacterData class]])
963         return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:[(DOMCharacterData *)child data] replacingDOMRange:range givenAction:action];
964     return [[webView _editingDelegateForwarder] webView:webView shouldInsertNode:fragment replacingDOMRange:range givenAction:action];
965 }
966
967 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
968 {
969     WebView *webView = [self _webView];
970     return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:range givenAction:action];
971 }
972
973 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action
974 {
975     return [self _shouldInsertText:text replacingDOMRange:[self _selectedRange] givenAction:action];
976 }
977
978 - (DOMRange *)_selectedRange
979 {
980     Frame* coreFrame = core([self _frame]);
981     return coreFrame ? kit(coreFrame->selection()->toNormalizedRange().get()) : nil;
982 }
983
984 - (BOOL)_shouldDeleteRange:(DOMRange *)range
985 {
986     Frame* coreFrame = core([self _frame]);
987     return coreFrame && coreFrame->editor()->shouldDeleteRange(core(range));
988 }
989
990 - (NSView *)_hitViewForEvent:(NSEvent *)event
991 {
992     // Usually, we hack AK's hitTest method to catch all events at the topmost WebHTMLView.  
993     // Callers of this method, however, want to query the deepest view instead.
994     forceNSViewHitTest = YES;
995     NSView *hitView = [[[self window] contentView] hitTest:[event locationInWindow]];
996     forceNSViewHitTest = NO;    
997     return hitView;
998 }
999
1000 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString
1001 {
1002     // Put HTML on the pasteboard.
1003     if ([types containsObject:WebArchivePboardType]) {
1004         if (RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::createFromSelection(core([self _frame]))) {
1005             if (RetainPtr<CFDataRef> data = coreArchive ? coreArchive->rawDataRepresentation() : 0)
1006                 [pasteboard setData:(NSData *)data.get() forType:WebArchivePboardType];
1007         }
1008     }
1009     
1010     // Put the attributed string on the pasteboard (RTF/RTFD format).
1011     if ([types containsObject:NSRTFDPboardType]) {
1012         if (attributedString == nil) {
1013             attributedString = [self selectedAttributedString];
1014         }        
1015         NSData *RTFDData = [attributedString RTFDFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
1016         [pasteboard setData:RTFDData forType:NSRTFDPboardType];
1017     }        
1018     if ([types containsObject:NSRTFPboardType]) {
1019         if (attributedString == nil) {
1020             attributedString = [self selectedAttributedString];
1021         }
1022         if ([attributedString containsAttachments]) {
1023             attributedString = [attributedString _web_attributedStringByStrippingAttachmentCharacters];
1024         }
1025         NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
1026         [pasteboard setData:RTFData forType:NSRTFPboardType];
1027     }
1028     
1029     // Put plain string on the pasteboard.
1030     if ([types containsObject:NSStringPboardType]) {
1031         // Map &nbsp; to a plain old space because this is better for source code, other browsers do it,
1032         // and because HTML forces you to do this any time you want two spaces in a row.
1033         NSMutableString *s = [[self selectedString] mutableCopy];
1034         const unichar NonBreakingSpaceCharacter = 0xA0;
1035         NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&NonBreakingSpaceCharacter length:1];
1036         [s replaceOccurrencesOfString:NonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
1037         [pasteboard setString:s forType:NSStringPboardType];
1038         [s release];
1039     }
1040     
1041     if ([self _canSmartCopyOrDelete] && [types containsObject:WebSmartPastePboardType]) {
1042         [pasteboard setData:nil forType:WebSmartPastePboardType];
1043     }
1044 }
1045
1046 - (void)_setMouseDownEvent:(NSEvent *)event
1047 {
1048     ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
1049
1050     if (event == _private->mouseDownEvent)
1051         return;
1052
1053     [event retain];
1054     [_private->mouseDownEvent release];
1055     _private->mouseDownEvent = event;
1056 }
1057
1058 - (void)_cancelUpdateMouseoverTimer
1059 {
1060     if (_private->updateMouseoverTimer) {
1061         CFRunLoopTimerInvalidate(_private->updateMouseoverTimer);
1062         CFRelease(_private->updateMouseoverTimer);
1063         _private->updateMouseoverTimer = NULL;
1064     }
1065 }
1066
1067 - (WebHTMLView *)_topHTMLView
1068 {
1069     // FIXME: this can fail if the dataSource is nil, which happens when the WebView is tearing down from the window closing.
1070     WebHTMLView *view = (WebHTMLView *)[[[[_private->dataSource _webView] mainFrame] frameView] documentView];
1071     ASSERT(!view || [view isKindOfClass:[WebHTMLView class]]);
1072     return view;
1073 }
1074
1075 - (BOOL)_isTopHTMLView
1076 {
1077     // FIXME: this should be a cached boolean that doesn't rely on _topHTMLView since that can fail (see _topHTMLView).
1078     return self == [self _topHTMLView];
1079 }
1080
1081 - (void)_web_setPrintingModeRecursive
1082 {
1083     [self _setPrinting:YES minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:NO paginateScreenContent:[self _isInScreenPaginationMode]];
1084
1085 #ifndef NDEBUG
1086     _private->enumeratingSubviews = YES;
1087 #endif
1088
1089     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
1090
1091     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
1092
1093     unsigned count = [descendantWebHTMLViews count];
1094     for (unsigned i = 0; i < count; ++i)
1095         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:YES minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:NO paginateScreenContent:[self _isInScreenPaginationMode]];
1096
1097     [descendantWebHTMLViews release];
1098
1099 #ifndef NDEBUG
1100     _private->enumeratingSubviews = NO;
1101 #endif
1102 }
1103
1104 - (void)_web_clearPrintingModeRecursive
1105 {
1106     [self _setPrinting:NO minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:NO paginateScreenContent:[self _isInScreenPaginationMode]];
1107
1108 #ifndef NDEBUG
1109     _private->enumeratingSubviews = YES;
1110 #endif
1111
1112     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
1113
1114     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
1115
1116     unsigned count = [descendantWebHTMLViews count];
1117     for (unsigned i = 0; i < count; ++i)
1118         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:NO minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:NO paginateScreenContent:[self _isInScreenPaginationMode]];
1119
1120     [descendantWebHTMLViews release];
1121
1122 #ifndef NDEBUG
1123     _private->enumeratingSubviews = NO;
1124 #endif
1125 }
1126
1127 - (void)_web_setPrintingModeRecursiveAndAdjustViewSize
1128 {
1129     [self _setPrinting:YES minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:YES paginateScreenContent:[self _isInScreenPaginationMode]];
1130
1131 #ifndef NDEBUG
1132     _private->enumeratingSubviews = YES;
1133 #endif
1134
1135     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
1136
1137     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
1138
1139     unsigned count = [descendantWebHTMLViews count];
1140     for (unsigned i = 0; i < count; ++i)
1141         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:YES minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:YES paginateScreenContent:[self _isInScreenPaginationMode]];
1142
1143     [descendantWebHTMLViews release];
1144
1145 #ifndef NDEBUG
1146     _private->enumeratingSubviews = NO;
1147 #endif
1148 }
1149
1150 @end
1151
1152 @implementation WebHTMLView (WebPrivate)
1153
1154 + (NSArray *)supportedMIMETypes
1155 {
1156     return [WebHTMLRepresentation supportedMIMETypes];
1157 }
1158
1159 + (NSArray *)supportedImageMIMETypes
1160 {
1161     return [WebHTMLRepresentation supportedImageMIMETypes];
1162 }
1163
1164 + (NSArray *)supportedNonImageMIMETypes
1165 {
1166     return [WebHTMLRepresentation supportedNonImageMIMETypes];
1167 }
1168
1169 + (NSArray *)unsupportedTextMIMETypes
1170 {
1171     return [NSArray arrayWithObjects:
1172         @"text/calendar",       // iCal
1173         @"text/x-calendar",
1174         @"text/x-vcalendar",
1175         @"text/vcalendar",
1176         @"text/vcard",          // vCard
1177         @"text/x-vcard",
1178         @"text/directory",
1179         @"text/ldif",           // Netscape Address Book
1180         @"text/qif",            // Quicken
1181         @"text/x-qif",
1182         @"text/x-csv",          // CSV (for Address Book and Microsoft Outlook)
1183         @"text/x-vcf",          // vCard type used in Sun affinity app
1184         @"text/rtf",            // Rich Text Format
1185         nil];
1186 }
1187
1188 + (void)_postFlagsChangedEvent:(NSEvent *)flagsChangedEvent
1189 {
1190     // This is a workaround for: <rdar://problem/2981619> NSResponder_Private should include notification for FlagsChanged
1191     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
1192         location:[[flagsChangedEvent window] convertScreenToBase:[NSEvent mouseLocation]]
1193         modifierFlags:[flagsChangedEvent modifierFlags]
1194         timestamp:[flagsChangedEvent timestamp]
1195         windowNumber:[flagsChangedEvent windowNumber]
1196         context:[flagsChangedEvent context]
1197         eventNumber:0 clickCount:0 pressure:0];
1198
1199     // Pretend it's a mouse move.
1200     [[NSNotificationCenter defaultCenter]
1201         postNotificationName:WKMouseMovedNotification() object:self
1202         userInfo:[NSDictionary dictionaryWithObject:fakeEvent forKey:@"NSEvent"]];
1203 }
1204
1205 - (id)_bridge
1206 {
1207     // This method exists to maintain compatibility with Leopard's Dictionary.app, since it
1208     // calls _bridge to get access to convertNSRangeToDOMRange: and convertDOMRangeToNSRange:.
1209     // Return the WebFrame, which implements the compatibility methods. <rdar://problem/6002160>
1210     return [self _frame];
1211 }
1212
1213 - (void)_updateMouseoverWithFakeEvent
1214 {
1215     [self _cancelUpdateMouseoverTimer];
1216     
1217     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
1218         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
1219         modifierFlags:[[NSApp currentEvent] modifierFlags]
1220         timestamp:[NSDate timeIntervalSinceReferenceDate]
1221         windowNumber:[[self window] windowNumber]
1222         context:[[NSApp currentEvent] context]
1223         eventNumber:0 clickCount:0 pressure:0];
1224     
1225     [self _updateMouseoverWithEvent:fakeEvent];
1226 }
1227
1228 static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info)
1229 {
1230     WebHTMLView *view = (WebHTMLView *)info;
1231     
1232     [view _updateMouseoverWithFakeEvent];
1233 }
1234
1235 - (void)_frameOrBoundsChanged
1236 {
1237     WebView *webView = [self _webView];
1238     WebDynamicScrollBarsView *scrollView = [[[webView mainFrame] frameView] _scrollView];
1239
1240     NSPoint origin = [[self superview] bounds].origin;
1241     if (!NSEqualPoints(_private->lastScrollPosition, origin) && ![scrollView inProgramaticScroll]) {
1242         if (Frame* coreFrame = core([self _frame])) {
1243             if (FrameView* coreView = coreFrame->view()) {
1244 #ifndef BUILDING_ON_TIGER
1245                 _private->inScrollPositionChanged = YES;
1246 #endif
1247                 coreView->scrollPositionChangedViaPlatformWidget();
1248 #ifndef BUILDING_ON_TIGER
1249                 _private->inScrollPositionChanged = NO;
1250 #endif
1251             }
1252         }
1253     
1254         [_private->completionController endRevertingChange:NO moveLeft:NO];
1255         
1256         [[webView _UIDelegateForwarder] webView:webView didScrollDocumentInFrameView:[self _frameView]];
1257     }
1258     _private->lastScrollPosition = origin;
1259
1260     if ([self window] && !_private->closed && !_private->updateMouseoverTimer) {
1261         CFRunLoopTimerContext context = { 0, self, NULL, NULL, NULL };
1262         
1263         // Use a 100ms delay so that the synthetic mouse over update doesn't cause cursor thrashing when pages are loading
1264         // and scrolling rapidly back to back.
1265         _private->updateMouseoverTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 0.1, 0, 0, 0,
1266                                                               _updateMouseoverTimerCallback, &context);
1267         CFRunLoopAddTimer(CFRunLoopGetCurrent(), _private->updateMouseoverTimer, kCFRunLoopDefaultMode);
1268     }
1269     
1270 #if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD)
1271     [self _updateLayerHostingViewPosition];
1272 #endif
1273 }
1274
1275 - (void)_setAsideSubviews
1276 {
1277     ASSERT(!_private->subviewsSetAside);
1278     ASSERT(_private->savedSubviews == nil);
1279     _private->savedSubviews = _subviews;
1280 #if USE(ACCELERATED_COMPOSITING)
1281     // We need to keep the layer-hosting view in the subviews, otherwise the layers flash.
1282     if (_private->layerHostingView) {
1283         NSArray* newSubviews = [[NSArray alloc] initWithObjects:_private->layerHostingView, nil];
1284         _subviews = newSubviews;
1285     } else
1286         _subviews = nil;
1287 #else
1288     _subviews = nil;
1289 #endif    
1290     _private->subviewsSetAside = YES;
1291  }
1292  
1293  - (void)_restoreSubviews
1294  {
1295     ASSERT(_private->subviewsSetAside);
1296 #if USE(ACCELERATED_COMPOSITING)
1297     if (_private->layerHostingView) {
1298         [_subviews release];
1299         _subviews = _private->savedSubviews;
1300     } else {
1301         ASSERT(_subviews == nil);
1302         _subviews = _private->savedSubviews;
1303     }
1304 #else
1305     ASSERT(_subviews == nil);
1306     _subviews = _private->savedSubviews;
1307 #endif    
1308     _private->savedSubviews = nil;
1309     _private->subviewsSetAside = NO;
1310 }
1311
1312 #ifndef NDEBUG
1313
1314 - (void)didAddSubview:(NSView *)subview
1315 {
1316     if (_private->enumeratingSubviews)
1317         LOG(View, "A view of class %s was added during subview enumeration for layout or printing mode change. This view might paint without first receiving layout.", object_getClassName([subview class]));
1318 }
1319 #endif
1320
1321 #ifdef BUILDING_ON_TIGER
1322
1323 // This is called when we are about to draw, but before our dirty rect is propagated to our ancestors.
1324 // That's the perfect time to do a layout, except that ideally we'd want to be sure that we're dirty
1325 // before doing it. As a compromise, when we're opaque we do the layout only when actually asked to
1326 // draw, but when we're transparent we do the layout at this stage so views behind us know that they
1327 // need to be redrawn (in case the layout causes some things to get dirtied).
1328 - (void)_propagateDirtyRectsToOpaqueAncestors
1329 {
1330     if (![[self _webView] drawsBackground])
1331         [self _web_updateLayoutAndStyleIfNeededRecursive];
1332     [super _propagateDirtyRectsToOpaqueAncestors];
1333 }
1334
1335 #else
1336
1337 - (void)viewWillDraw
1338 {
1339     // On window close we will be called when the datasource is nil, then hit an assert in _topHTMLView
1340     // So check if the dataSource is nil before calling [self _isTopHTMLView], this can be removed
1341     // once the FIXME in _isTopHTMLView is fixed.
1342     if (_private->dataSource && [self _isTopHTMLView])
1343         [self _web_updateLayoutAndStyleIfNeededRecursive];
1344     [super viewWillDraw];
1345 }
1346
1347 #endif
1348
1349 // Don't let AppKit even draw subviews. We take care of that.
1350 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView
1351 {
1352     // This helps when we print as part of a larger print process.
1353     // If the WebHTMLView itself is what we're printing, then we will never have to do this.
1354     BOOL wasInPrintingMode = _private->printing;
1355     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
1356     if (isPrinting) {
1357         if (!wasInPrintingMode)
1358             [self _web_setPrintingModeRecursive];
1359 #ifndef BUILDING_ON_TIGER
1360         else
1361             [self _web_updateLayoutAndStyleIfNeededRecursive];
1362 #endif
1363     } else if (wasInPrintingMode)
1364         [self _web_clearPrintingModeRecursive];
1365
1366 #ifndef BUILDING_ON_TIGER
1367     // There are known cases where -viewWillDraw is not called on all views being drawn.
1368     // See <rdar://problem/6964278> for example. Performing layout at this point prevents us from
1369     // trying to paint without layout (which WebCore now refuses to do, instead bailing out without
1370     // drawing at all), but we may still fail to update any regions dirtied by the layout which are
1371     // not already dirty. 
1372     if ([self _needsLayout]) {
1373         NSInteger rectCount;
1374         [self getRectsBeingDrawn:0 count:&rectCount];
1375         if (rectCount) {
1376             LOG_ERROR("View needs layout. Either -viewWillDraw wasn't called or layout was invalidated during the display operation. Performing layout now.");
1377             [self _web_updateLayoutAndStyleIfNeededRecursive];
1378         }
1379     }
1380 #else
1381     // Because Tiger does not have viewWillDraw we need to do layout here.
1382     [self _web_updateLayoutAndStyleIfNeededRecursive];
1383     [_subviews makeObjectsPerformSelector:@selector(_propagateDirtyRectsToOpaqueAncestors)];
1384 #endif
1385
1386     [self _setAsideSubviews];
1387     [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect isVisibleRect:isVisibleRect rectIsVisibleRectForView:visibleView topView:topView];
1388     [self _restoreSubviews];
1389
1390     if (wasInPrintingMode != isPrinting) {
1391         if (wasInPrintingMode)
1392             [self _web_setPrintingModeRecursive];
1393         else
1394             [self _web_clearPrintingModeRecursive];
1395     }
1396 }
1397
1398 // Don't let AppKit even draw subviews. We take care of that.
1399 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect
1400 {
1401     BOOL needToSetAsideSubviews = !_private->subviewsSetAside;
1402
1403     BOOL wasInPrintingMode = _private->printing;
1404     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
1405
1406     if (needToSetAsideSubviews) {
1407         // This helps when we print as part of a larger print process.
1408         // If the WebHTMLView itself is what we're printing, then we will never have to do this.
1409         if (isPrinting) {
1410             if (!wasInPrintingMode)
1411                 [self _web_setPrintingModeRecursive];
1412 #ifndef BUILDING_ON_TIGER
1413             else
1414                 [self _web_updateLayoutAndStyleIfNeededRecursive];
1415 #endif
1416         } else if (wasInPrintingMode)
1417             [self _web_clearPrintingModeRecursive];
1418
1419 #ifdef BUILDING_ON_TIGER
1420
1421         // Because Tiger does not have viewWillDraw we need to do layout here.
1422         NSRect boundsBeforeLayout = [self bounds];
1423         if (!NSIsEmptyRect(visRect))
1424             [self _web_updateLayoutAndStyleIfNeededRecursive];
1425
1426         // If layout changes the view's bounds, then we need to recompute the visRect.
1427         // That's because the visRect passed to us was based on the bounds at the time
1428         // we were called. This method is only displayed to draw "all", so it's safe
1429         // to just call visibleRect to compute the entire rectangle.
1430         if (!NSEqualRects(boundsBeforeLayout, [self bounds]))
1431             visRect = [self visibleRect];
1432
1433 #endif
1434
1435         [self _setAsideSubviews];
1436     }
1437
1438     [super _recursiveDisplayAllDirtyWithLockFocus:needsLockFocus visRect:visRect];
1439
1440     if (needToSetAsideSubviews) {
1441         if (wasInPrintingMode != isPrinting) {
1442             if (wasInPrintingMode)
1443                 [self _web_setPrintingModeRecursive];
1444             else
1445                 [self _web_clearPrintingModeRecursive];
1446         }
1447
1448         [self _restoreSubviews];
1449     }
1450 }
1451
1452 // Don't let AppKit even draw subviews. We take care of that.
1453 - (void)_recursive:(BOOL)recurse displayRectIgnoringOpacity:(NSRect)displayRect inContext:(NSGraphicsContext *)context topView:(BOOL)topView
1454 {
1455 #ifdef BUILDING_ON_TIGER 
1456     // Because Tiger does not have viewWillDraw we need to do layout here.
1457     [self _web_updateLayoutAndStyleIfNeededRecursive];
1458 #endif
1459
1460     [self _setAsideSubviews];
1461     [super _recursive:recurse displayRectIgnoringOpacity:displayRect inContext:context topView:topView];
1462     [self _restoreSubviews];
1463 }
1464
1465 - (BOOL)_insideAnotherHTMLView
1466 {
1467     return self != [self _topHTMLView];
1468 }
1469
1470 - (NSView *)hitTest:(NSPoint)point
1471 {
1472     // WebHTMLView objects handle all events for objects inside them.
1473     // To get those events, we prevent hit testing from AppKit.
1474
1475     // But there are three exceptions to this:
1476     //   1) For right mouse clicks and control clicks we don't yet have an implementation
1477     //      that works for nested views, so we let the hit testing go through the
1478     //      standard NSView code path (needs to be fixed, see bug 4361618).
1479     //   2) Java depends on doing a hit test inside it's mouse moved handling,
1480     //      so we let the hit testing go through the standard NSView code path
1481     //      when the current event is a mouse move (except when we are calling
1482     //      from _updateMouseoverWithEvent, so we have to use a global,
1483     //      forceWebHTMLViewHitTest, for that)
1484     //   3) The acceptsFirstMouse: and shouldDelayWindowOrderingForEvent: methods
1485     //      both need to figure out which view to check with inside the WebHTMLView.
1486     //      They use a global to change the behavior of hitTest: so they can get the
1487     //      right view. The global is forceNSViewHitTest and the method they use to
1488     //      do the hit testing is _hitViewForEvent:. (But this does not work correctly
1489     //      when there is HTML overlapping the view, see bug 4361626)
1490     //   4) NSAccessibilityHitTest relies on this for checking the cursor position.
1491     //      Our check for that is whether the event is NSFlagsChanged.  This works
1492     //      for VoiceOver's Control-Option-F5 command (move focus to item under cursor)
1493     //      and Dictionary's Command-Control-D (open dictionary popup for item under cursor).
1494     //      This is of course a hack.
1495
1496     if (_private->closed)
1497         return nil;
1498
1499     BOOL captureHitsOnSubviews;
1500     if (forceNSViewHitTest)
1501         captureHitsOnSubviews = NO;
1502     else if (forceWebHTMLViewHitTest)
1503         captureHitsOnSubviews = YES;
1504     else {
1505         // FIXME: Why doesn't this include mouse entered/exited events, or other mouse button events?
1506         NSEvent *event = [[self window] currentEvent];
1507         captureHitsOnSubviews = !([event type] == NSMouseMoved
1508             || [event type] == NSRightMouseDown
1509             || ([event type] == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask) != 0)
1510             || [event type] == NSFlagsChanged);
1511     }
1512
1513     if (!captureHitsOnSubviews) {
1514         NSView* hitView = [super hitTest:point];
1515 #if USE(ACCELERATED_COMPOSITING)
1516         if (_private && hitView == _private->layerHostingView)
1517             hitView = self;
1518 #endif
1519         return hitView;
1520     }
1521     if ([[self superview] mouse:point inRect:[self frame]])
1522         return self;
1523     return nil;
1524 }
1525
1526 - (void)_clearLastHitViewIfSelf
1527 {
1528     if (lastHitView == self)
1529         lastHitView = nil;
1530 }
1531
1532 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
1533 {
1534     ASSERT(_private->trackingRectOwner == nil);
1535     _private->trackingRectOwner = owner;
1536     _private->trackingRectUserData = data;
1537     return TRACKING_RECT_TAG;
1538 }
1539
1540 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
1541 {
1542     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
1543     ASSERT(_private->trackingRectOwner == nil);
1544     _private->trackingRectOwner = owner;
1545     _private->trackingRectUserData = data;
1546     return TRACKING_RECT_TAG;
1547 }
1548
1549 - (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count
1550 {
1551     ASSERT(count == 1);
1552     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
1553     ASSERT(_private->trackingRectOwner == nil);
1554     _private->trackingRectOwner = owner;
1555     _private->trackingRectUserData = userDataList[0];
1556     trackingNums[0] = TRACKING_RECT_TAG;
1557 }
1558
1559 - (void)removeTrackingRect:(NSTrackingRectTag)tag
1560 {
1561     if (tag == 0)
1562         return;
1563     
1564     if (_private && (tag == TRACKING_RECT_TAG)) {
1565         _private->trackingRectOwner = nil;
1566         return;
1567     }
1568     
1569     if (_private && (tag == _private->lastToolTipTag)) {
1570         [super removeTrackingRect:tag];
1571         _private->lastToolTipTag = 0;
1572         return;
1573     }
1574     
1575     // If any other tracking rect is being removed, we don't know how it was created
1576     // and it's possible there's a leak involved (see 3500217)
1577     ASSERT_NOT_REACHED();
1578 }
1579
1580 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count
1581 {
1582     int i;
1583     for (i = 0; i < count; ++i) {
1584         int tag = tags[i];
1585         if (tag == 0)
1586             continue;
1587         ASSERT(tag == TRACKING_RECT_TAG);
1588         if (_private != nil) {
1589             _private->trackingRectOwner = nil;
1590         }
1591     }
1592 }
1593
1594 - (void)_sendToolTipMouseExited
1595 {
1596     // Nothing matters except window, trackingNumber, and userData.
1597     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited
1598         location:NSMakePoint(0, 0)
1599         modifierFlags:0
1600         timestamp:0
1601         windowNumber:[[self window] windowNumber]
1602         context:NULL
1603         eventNumber:0
1604         trackingNumber:TRACKING_RECT_TAG
1605         userData:_private->trackingRectUserData];
1606     [_private->trackingRectOwner mouseExited:fakeEvent];
1607 }
1608
1609 - (void)_sendToolTipMouseEntered
1610 {
1611     // Nothing matters except window, trackingNumber, and userData.
1612     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered
1613         location:NSMakePoint(0, 0)
1614         modifierFlags:0
1615         timestamp:0
1616         windowNumber:[[self window] windowNumber]
1617         context:NULL
1618         eventNumber:0
1619         trackingNumber:TRACKING_RECT_TAG
1620         userData:_private->trackingRectUserData];
1621     [_private->trackingRectOwner mouseEntered:fakeEvent];
1622 }
1623
1624 - (void)_setToolTip:(NSString *)string
1625 {
1626     NSString *toolTip = [string length] == 0 ? nil : string;
1627     NSString *oldToolTip = _private->toolTip;
1628     if ((toolTip == nil || oldToolTip == nil) ? toolTip == oldToolTip : [toolTip isEqualToString:oldToolTip]) {
1629         return;
1630     }
1631     if (oldToolTip) {
1632         [self _sendToolTipMouseExited];
1633         [oldToolTip release];
1634     }
1635     _private->toolTip = [toolTip copy];
1636     if (toolTip) {
1637         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
1638         [self removeAllToolTips];
1639         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
1640         _private->lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL];
1641         [self _sendToolTipMouseEntered];
1642     }
1643 }
1644
1645 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
1646 {
1647     return [[_private->toolTip copy] autorelease];
1648 }
1649
1650 - (void)_updateMouseoverWithEvent:(NSEvent *)event
1651 {
1652     if (_private->closed)
1653         return;
1654
1655     NSView *contentView = [[event window] contentView];
1656     NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil];
1657     
1658     forceWebHTMLViewHitTest = YES;
1659     NSView *hitView = [contentView hitTest:locationForHitTest];
1660     forceWebHTMLViewHitTest = NO;
1661     
1662     WebHTMLView *view = nil;
1663     if ([hitView isKindOfClass:[WebHTMLView class]] && ![[(WebHTMLView *)hitView _webView] isHoverFeedbackSuspended])
1664         view = (WebHTMLView *)hitView;    
1665
1666     if (view)
1667         [view retain];
1668
1669     if (lastHitView != view && lastHitView && [lastHitView _frame]) {
1670         // If we are moving out of a view (or frame), let's pretend the mouse moved
1671         // all the way out of that view. But we have to account for scrolling, because
1672         // WebCore doesn't understand our clipping.
1673         NSRect visibleRect = [[[[lastHitView _frame] frameView] _scrollView] documentVisibleRect];
1674         float yScroll = visibleRect.origin.y;
1675         float xScroll = visibleRect.origin.x;
1676
1677         NSEvent *event = [NSEvent mouseEventWithType:NSMouseMoved
1678             location:NSMakePoint(-1 - xScroll, -1 - yScroll)
1679             modifierFlags:[[NSApp currentEvent] modifierFlags]
1680             timestamp:[NSDate timeIntervalSinceReferenceDate]
1681             windowNumber:[[view window] windowNumber]
1682             context:[[NSApp currentEvent] context]
1683             eventNumber:0 clickCount:0 pressure:0];
1684         if (Frame* lastHitCoreFrame = core([lastHitView _frame]))
1685             lastHitCoreFrame->eventHandler()->mouseMoved(event);
1686     }
1687
1688     lastHitView = view;
1689
1690     if (view) {
1691         if (Frame* coreFrame = core([view _frame]))
1692             coreFrame->eventHandler()->mouseMoved(event);
1693
1694         [view release];
1695     }
1696 }
1697
1698 + (NSArray *)_insertablePasteboardTypes
1699 {
1700     static NSArray *types = nil;
1701     if (!types) {
1702         types = [[NSArray alloc] initWithObjects:WebArchivePboardType, NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPDFPboardType,
1703 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
1704             NSPICTPboardType,
1705 #endif
1706             NSURLPboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, NSColorPboardType, kUTTypePNG, nil];
1707         CFRetain(types);
1708     }
1709     return types;
1710 }
1711
1712 + (NSArray *)_selectionPasteboardTypes
1713 {
1714     // FIXME: We should put data for NSHTMLPboardType on the pasteboard but Microsoft Excel doesn't like our format of HTML (3640423).
1715     return [NSArray arrayWithObjects:WebArchivePboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, nil];
1716 }
1717
1718 - (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
1719 {
1720     [self setPromisedDragTIFFDataSource:0];
1721 }
1722
1723 - (void)pasteboard:(NSPasteboard *)pasteboard provideDataForType:(NSString *)type
1724 {
1725     if ([type isEqual:NSRTFDPboardType] && [[pasteboard types] containsObject:WebArchivePboardType]) {
1726         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
1727         [pasteboard _web_writePromisedRTFDFromArchive:archive containsImage:[[pasteboard types] containsObject:NSTIFFPboardType]];
1728         [archive release];
1729     } else if ([type isEqual:NSTIFFPboardType] && [self promisedDragTIFFDataSource]) {
1730         if (Image* image = [self promisedDragTIFFDataSource]->image())
1731             [pasteboard setData:(NSData *)image->getTIFFRepresentation() forType:NSTIFFPboardType];
1732         [self setPromisedDragTIFFDataSource:0];
1733     }
1734 }
1735
1736 - (BOOL)mouseDownCanMoveWindow
1737 {
1738     BOOL result = [super mouseDownCanMoveWindow];
1739
1740     NSLog(@"%@, %@ %d", self, NSStringFromSelector(_cmd), result);
1741     return result;
1742 }
1743
1744 - (void)_handleAutoscrollForMouseDragged:(NSEvent *)event 
1745
1746     [self autoscroll:event]; 
1747     [self _startAutoscrollTimer:event]; 
1748
1749
1750 - (WebPluginController *)_pluginController
1751 {
1752     return _private->pluginController;
1753 }
1754
1755 - (void)_layoutForPrinting
1756 {
1757     // Set printing mode temporarily so we can adjust the size of the view. This will allow
1758     // AppKit's pagination code to use the correct height for the page content. Leaving printing
1759     // mode on indefinitely would interfere with Mail's printing mechanism (at least), so we just
1760     // turn it off again after adjusting the size.
1761     [self _web_setPrintingModeRecursiveAndAdjustViewSize];
1762     [self _web_clearPrintingModeRecursive];
1763 }
1764
1765 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1766 {
1767     if (!pasteString || !rangeToReplace || ![[self _webView] smartInsertDeleteEnabled]) {
1768         if (beforeString)
1769             *beforeString = nil;
1770         if (afterString)
1771             *afterString = nil;
1772         return;
1773     }
1774     
1775     [[self _frame] _smartInsertForString:pasteString replacingRange:rangeToReplace beforeString:beforeString afterString:afterString];
1776 }
1777
1778 - (BOOL)_canSmartReplaceWithPasteboard:(NSPasteboard *)pasteboard
1779 {
1780     return [[self _webView] smartInsertDeleteEnabled] && [[pasteboard types] containsObject:WebSmartPastePboardType];
1781 }
1782
1783 - (void)_startAutoscrollTimer:(NSEvent *)triggerEvent
1784 {
1785     if (_private->autoscrollTimer == nil) {
1786         _private->autoscrollTimer = [[NSTimer scheduledTimerWithTimeInterval:AUTOSCROLL_INTERVAL
1787             target:self selector:@selector(_autoscroll) userInfo:nil repeats:YES] retain];
1788         _private->autoscrollTriggerEvent = [triggerEvent retain];
1789     }
1790 }
1791
1792 // FIXME: _selectionRect is deprecated in favor of selectionRect, which is in protocol WebDocumentSelection.
1793 // We can't remove this yet because it's still in use by Mail.
1794 - (NSRect)_selectionRect
1795 {
1796     return [self selectionRect];
1797 }
1798
1799 - (void)_stopAutoscrollTimer
1800 {
1801     NSTimer *timer = _private->autoscrollTimer;
1802     _private->autoscrollTimer = nil;
1803     [_private->autoscrollTriggerEvent release];
1804     _private->autoscrollTriggerEvent = nil;
1805     [timer invalidate];
1806     [timer release];
1807 }
1808
1809 - (void)_autoscroll
1810 {
1811     // Guarantee that the autoscroll timer is invalidated, even if we don't receive
1812     // a mouse up event.
1813     BOOL isStillDown = CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft);   
1814     if (!isStillDown){
1815         [self _stopAutoscrollTimer];
1816         return;
1817     }
1818
1819     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
1820         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
1821         modifierFlags:[[NSApp currentEvent] modifierFlags]
1822         timestamp:[NSDate timeIntervalSinceReferenceDate]
1823         windowNumber:[[self window] windowNumber]
1824         context:[[NSApp currentEvent] context]
1825         eventNumber:0 clickCount:0 pressure:0];
1826     [self mouseDragged:fakeEvent];
1827 }
1828
1829 - (BOOL)_canEdit
1830 {
1831     Frame* coreFrame = core([self _frame]);
1832     return coreFrame && coreFrame->editor()->canEdit();
1833 }
1834
1835 - (BOOL)_canEditRichly
1836 {
1837     Frame* coreFrame = core([self _frame]);
1838     return coreFrame && coreFrame->editor()->canEditRichly();
1839 }
1840
1841 - (BOOL)_canAlterCurrentSelection
1842 {
1843     return [self _hasSelectionOrInsertionPoint] && [self _isEditable];
1844 }
1845
1846 - (BOOL)_hasSelection
1847 {
1848     Frame* coreFrame = core([self _frame]);
1849     return coreFrame && coreFrame->selection()->isRange();
1850 }
1851
1852 - (BOOL)_hasSelectionOrInsertionPoint
1853 {
1854     Frame* coreFrame = core([self _frame]);
1855     return coreFrame && coreFrame->selection()->isCaretOrRange();
1856 }
1857
1858 - (BOOL)_hasInsertionPoint
1859 {
1860     Frame* coreFrame = core([self _frame]);
1861     return coreFrame && coreFrame->selection()->isCaret();
1862 }
1863
1864 - (BOOL)_isEditable
1865 {
1866     Frame* coreFrame = core([self _frame]);
1867     return coreFrame && coreFrame->selection()->isContentEditable();
1868 }
1869
1870 - (BOOL)_transparentBackground
1871 {
1872     return _private->transparentBackground;
1873 }
1874
1875 - (void)_setTransparentBackground:(BOOL)f
1876 {
1877     _private->transparentBackground = f;
1878 }
1879
1880 - (NSImage *)_selectionDraggingImage
1881 {
1882     if (![self _hasSelection])
1883         return nil;
1884     NSImage *dragImage = core([self _frame])->selectionImage();
1885     [dragImage _web_dissolveToFraction:WebDragImageAlpha];
1886     return dragImage;
1887 }
1888
1889 - (NSRect)_selectionDraggingRect
1890 {
1891     // Mail currently calls this method. We can eliminate it when Mail no longer calls it.
1892     return [self selectionRect];
1893 }
1894
1895 - (DOMNode *)_insertOrderedList
1896 {
1897     Frame* coreFrame = core([self _frame]);
1898     return coreFrame ? kit(coreFrame->editor()->insertOrderedList().get()) : nil;
1899 }
1900
1901 - (DOMNode *)_insertUnorderedList
1902 {
1903     Frame* coreFrame = core([self _frame]);
1904     return coreFrame ? kit(coreFrame->editor()->insertUnorderedList().get()) : nil;
1905 }
1906
1907 - (BOOL)_canIncreaseSelectionListLevel
1908 {
1909     Frame* coreFrame = core([self _frame]);
1910     return coreFrame && coreFrame->editor()->canIncreaseSelectionListLevel();
1911 }
1912
1913 - (BOOL)_canDecreaseSelectionListLevel
1914 {
1915     Frame* coreFrame = core([self _frame]);
1916     return coreFrame && coreFrame->editor()->canDecreaseSelectionListLevel();
1917 }
1918
1919 - (DOMNode *)_increaseSelectionListLevel
1920 {
1921     Frame* coreFrame = core([self _frame]);
1922     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevel().get()) : nil;
1923 }
1924
1925 - (DOMNode *)_increaseSelectionListLevelOrdered
1926 {
1927     Frame* coreFrame = core([self _frame]);
1928     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevelOrdered().get()) : nil;
1929 }
1930
1931 - (DOMNode *)_increaseSelectionListLevelUnordered
1932 {
1933     Frame* coreFrame = core([self _frame]);
1934     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevelUnordered().get()) : nil;
1935 }
1936
1937 - (void)_decreaseSelectionListLevel
1938 {
1939     Frame* coreFrame = core([self _frame]);
1940     if (coreFrame)
1941         coreFrame->editor()->decreaseSelectionListLevel();
1942 }
1943
1944 - (void)_setHighlighter:(id<WebHTMLHighlighter>)highlighter ofType:(NSString*)type
1945 {
1946     if (!_private->highlighters)
1947         _private->highlighters = [[NSMutableDictionary alloc] init];
1948     [_private->highlighters setObject:highlighter forKey:type];
1949 }
1950
1951 - (void)_removeHighlighterOfType:(NSString*)type
1952 {
1953     [_private->highlighters removeObjectForKey:type];
1954 }
1955
1956 - (void)_writeSelectionToPasteboard:(NSPasteboard *)pasteboard
1957 {
1958     ASSERT([self _hasSelection]);
1959     NSArray *types = [self pasteboardTypesForSelection];
1960
1961     // Don't write RTFD to the pasteboard when the copied attributed string has no attachments.
1962     NSAttributedString *attributedString = [self selectedAttributedString];
1963     NSMutableArray *mutableTypes = nil;
1964     if (![attributedString containsAttachments]) {
1965         mutableTypes = [types mutableCopy];
1966         [mutableTypes removeObject:NSRTFDPboardType];
1967         types = mutableTypes;
1968     }
1969
1970     [pasteboard declareTypes:types owner:[self _topHTMLView]];
1971     [self _writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard cachedAttributedString:attributedString];
1972     [mutableTypes release];
1973 }
1974
1975 - (void)close
1976 {
1977     // Check for a nil _private here in case we were created with initWithCoder. In that case, the WebView is just throwing
1978     // out the archived WebHTMLView and recreating a new one if needed. So close doesn't need to do anything in that case.
1979     if (!_private || _private->closed)
1980         return;
1981
1982     _private->closed = YES;
1983
1984     [self _cancelUpdateMouseoverTimer];
1985     [self _clearLastHitViewIfSelf];
1986     [self _removeMouseMovedObserverUnconditionally];
1987     [self _removeWindowObservers];
1988     [self _removeSuperviewObservers];
1989     [_private->pluginController destroyAllPlugins];
1990     [_private->pluginController setDataSource:nil];
1991     // remove tooltips before clearing _private so removeTrackingRect: will work correctly
1992     [self removeAllToolTips];
1993
1994     [_private clear];
1995
1996     Page* page = core([self _webView]);
1997     if (page)
1998         page->dragController()->setDraggingImageURL(KURL());
1999 }
2000
2001 - (BOOL)_hasHTMLDocument
2002 {
2003     Frame* coreFrame = core([self _frame]);
2004     if (!coreFrame)
2005         return NO;
2006     Document* document = coreFrame->document();
2007     return document && document->isHTMLDocument();
2008 }
2009
2010 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
2011                                                  forType:(NSString *)pboardType
2012                                                inContext:(DOMRange *)context
2013                                             subresources:(NSArray **)subresources
2014 {
2015     if (pboardType == WebArchivePboardType) {
2016         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
2017         if (subresources)
2018             *subresources = [archive subresources];
2019         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithArchive:archive];
2020         [archive release];
2021         return fragment;
2022     }
2023     if (pboardType == NSFilenamesPboardType)
2024         return [self _documentFragmentWithPaths:[pasteboard propertyListForType:NSFilenamesPboardType]];
2025         
2026     if (pboardType == NSHTMLPboardType) {
2027         NSString *HTMLString = [pasteboard stringForType:NSHTMLPboardType];
2028         // This is a hack to make Microsoft's HTML pasteboard data work. See 3778785.
2029         if ([HTMLString hasPrefix:@"Version:"]) {
2030             NSRange range = [HTMLString rangeOfString:@"<html" options:NSCaseInsensitiveSearch];
2031             if (range.location != NSNotFound)
2032                 HTMLString = [HTMLString substringFromIndex:range.location];
2033         }
2034         if ([HTMLString length] == 0)
2035             return nil;
2036         
2037         return [[self _frame] _documentFragmentWithMarkupString:HTMLString baseURLString:nil];
2038     }
2039
2040     // The _hasHTMLDocument clause here is a workaround for a bug in NSAttributedString: Radar 5052369.
2041     // If we call _documentFromRange on an XML document we'll get "setInnerHTML: method not found".
2042     // FIXME: Remove this once bug 5052369 is fixed.
2043     if ([self _hasHTMLDocument] && (pboardType == NSRTFPboardType || pboardType == NSRTFDPboardType)) {
2044         NSAttributedString *string = nil;
2045         if (pboardType == NSRTFDPboardType)
2046             string = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
2047         if (string == nil)
2048             string = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
2049         if (string == nil)
2050             return nil;
2051             
2052         NSDictionary *documentAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
2053             [[self class] _excludedElementsForAttributedStringConversion], NSExcludedElementsDocumentAttribute,
2054             self, @"WebResourceHandler", nil];
2055         NSArray *s;
2056         
2057         BOOL wasDeferringCallbacks = [[self _webView] defersCallbacks];
2058         if (!wasDeferringCallbacks)
2059             [[self _webView] setDefersCallbacks:YES];
2060             
2061         DOMDocumentFragment *fragment = [string _documentFromRange:NSMakeRange(0, [string length]) 
2062                                                           document:[[self _frame] DOMDocument] 
2063                                                 documentAttributes:documentAttributes
2064                                                       subresources:&s];
2065         if (subresources)
2066             *subresources = s;
2067         
2068         NSEnumerator *e = [s objectEnumerator];
2069         WebResource *r;
2070         while ((r = [e nextObject]))
2071             [[self _dataSource] addSubresource:r];
2072         
2073         if (!wasDeferringCallbacks)
2074             [[self _webView] setDefersCallbacks:NO];
2075         
2076         [documentAttributes release];
2077         [string release];
2078         return fragment;
2079     }
2080     if (pboardType == NSTIFFPboardType) {
2081         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSTIFFPboardType]
2082                                                               URL:uniqueURLWithRelativePart(@"image.tiff")
2083                                                          MIMEType:@"image/tiff" 
2084                                                  textEncodingName:nil
2085                                                         frameName:nil];
2086         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2087         [resource release];
2088         return fragment;
2089     }
2090     if (pboardType == NSPDFPboardType) {
2091         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPDFPboardType]
2092                                                               URL:uniqueURLWithRelativePart(@"application.pdf")
2093                                                          MIMEType:@"application/pdf" 
2094                                                  textEncodingName:nil
2095                                                         frameName:nil];
2096         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2097         [resource release];
2098         return fragment;
2099     }
2100 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
2101     if (pboardType == NSPICTPboardType) {
2102         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPICTPboardType]
2103                                                               URL:uniqueURLWithRelativePart(@"image.pict")
2104                                                          MIMEType:@"image/pict" 
2105                                                  textEncodingName:nil
2106                                                         frameName:nil];
2107         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2108         [resource release];
2109         return fragment;
2110     }
2111 #endif
2112     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
2113     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
2114     if ([pboardType isEqualToString:(NSString*)kUTTypePNG]) {
2115         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:(NSString*)kUTTypePNG]
2116                                                               URL:uniqueURLWithRelativePart(@"image.png")
2117                                                          MIMEType:@"image/png" 
2118                                                  textEncodingName:nil
2119                                                         frameName:nil];
2120         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2121         [resource release];
2122         return fragment;
2123     }
2124     if (pboardType == NSURLPboardType) {
2125         NSURL *URL = [NSURL URLFromPasteboard:pasteboard];
2126         DOMDocument* document = [[self _frame] DOMDocument];
2127         ASSERT(document);
2128         if (!document)
2129             return nil;
2130         DOMHTMLAnchorElement *anchor = (DOMHTMLAnchorElement *)[document createElement:@"a"];
2131         NSString *URLString = [URL _web_originalDataAsString]; // Original data is ASCII-only, so there is no need to precompose.
2132         if ([URLString length] == 0)
2133             return nil;
2134         NSString *URLTitleString = [[pasteboard stringForType:WebURLNamePboardType] precomposedStringWithCanonicalMapping];
2135         DOMText *text = [document createTextNode:URLTitleString];
2136         [anchor setHref:URLString];
2137         [anchor appendChild:text];
2138         DOMDocumentFragment *fragment = [document createDocumentFragment];
2139         [fragment appendChild:anchor];
2140         return fragment;
2141     }
2142     if (pboardType == NSStringPboardType)
2143         return kit(createFragmentFromText(core(context), [[pasteboard stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping]).get());
2144     return nil;
2145 }
2146
2147 #if ENABLE(NETSCAPE_PLUGIN_API) 
2148 - (void)_pauseNullEventsForAllNetscapePlugins 
2149
2150     NSArray *subviews = [self subviews]; 
2151     unsigned int subviewCount = [subviews count]; 
2152     unsigned int subviewIndex; 
2153     
2154     for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) { 
2155         NSView *subview = [subviews objectAtIndex:subviewIndex]; 
2156         if ([subview isKindOfClass:[WebBaseNetscapePluginView class]]) 
2157             [(WebBaseNetscapePluginView *)subview stopTimers];
2158     } 
2159
2160 #endif 
2161
2162 #if ENABLE(NETSCAPE_PLUGIN_API) 
2163 - (void)_resumeNullEventsForAllNetscapePlugins 
2164
2165     NSArray *subviews = [self subviews]; 
2166     unsigned int subviewCount = [subviews count]; 
2167     unsigned int subviewIndex; 
2168     
2169     for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) { 
2170         NSView *subview = [subviews objectAtIndex:subviewIndex]; 
2171         if ([subview isKindOfClass:[WebBaseNetscapePluginView class]]) 
2172             [(WebBaseNetscapePluginView *)subview restartTimers]; 
2173     } 
2174
2175 #endif 
2176
2177 - (BOOL)_isUsingAcceleratedCompositing
2178 {
2179 #if USE(ACCELERATED_COMPOSITING)
2180     return _private->layerHostingView != nil;
2181 #else
2182     return NO;
2183 #endif
2184 }
2185
2186 - (NSView *)_compositingLayersHostingView
2187 {
2188 #if USE(ACCELERATED_COMPOSITING)
2189     return _private->layerHostingView;
2190 #else
2191     return 0;
2192 #endif
2193 }
2194
2195 - (BOOL)_isInPrintMode
2196 {
2197     return _private->printing;
2198 }
2199
2200 - (BOOL)_beginPrintModeWithMinimumPageWidth:(CGFloat)minimumPageWidth height:(CGFloat)minimumPageHeight maximumPageWidth:(CGFloat)maximumPageWidth
2201 {
2202     Frame* frame = core([self _frame]);
2203     if (!frame)
2204         return NO;
2205
2206     if (frame->document() && frame->document()->isFrameSet()) {
2207         minimumPageWidth = 0;
2208         minimumPageHeight = 0;
2209         maximumPageWidth = 0;
2210     }
2211
2212     [self _setPrinting:YES minimumPageWidth:minimumPageWidth height:minimumPageHeight maximumPageWidth:maximumPageWidth adjustViewSize:YES paginateScreenContent:[self _isInScreenPaginationMode]];
2213     return YES;
2214 }
2215
2216 - (BOOL)_beginPrintModeWithPageWidth:(float)pageWidth height:(float)pageHeight shrinkToFit:(BOOL)shrinkToFit
2217 {
2218     Frame* frame = core([self _frame]);
2219     if (!frame)
2220         return NO;
2221
2222     float minLayoutWidth = 0;
2223     float minLayoutHeight = 0;
2224     float maxLayoutWidth = 0;
2225
2226     // If we are a frameset just print with the layout we have onscreen, otherwise relayout
2227     // according to the page width.
2228     if (!frame->document() || !frame->document()->isFrameSet()) {
2229         minLayoutWidth = shrinkToFit ? pageWidth * _WebHTMLViewPrintingMinimumShrinkFactor : pageWidth;
2230         minLayoutHeight = shrinkToFit ? pageHeight * _WebHTMLViewPrintingMinimumShrinkFactor : pageHeight;
2231         maxLayoutWidth = shrinkToFit ? pageWidth * _WebHTMLViewPrintingMaximumShrinkFactor : pageWidth;
2232     }
2233     [self _setPrinting:YES minimumPageWidth:minLayoutWidth height:minLayoutHeight maximumPageWidth:maxLayoutWidth adjustViewSize:YES paginateScreenContent:[self _isInScreenPaginationMode]];
2234
2235     return YES;
2236 }
2237
2238 - (void)_endPrintMode
2239 {
2240     [self _setPrinting:NO minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:YES paginateScreenContent:[self _isInScreenPaginationMode]];
2241 }
2242
2243 - (BOOL)_isInScreenPaginationMode
2244 {
2245     return _private->paginateScreenContent;
2246 }
2247
2248 - (BOOL)_beginScreenPaginationModeWithPageSize:(CGSize)pageSize shrinkToFit:(BOOL)shrinkToFit
2249 {
2250     Frame* frame = core([self _frame]);
2251     if (!frame)
2252         return NO;
2253
2254     CGFloat minLayoutWidth = 0;
2255     CGFloat minLayoutHeight = 0;
2256     CGFloat maxLayoutWidth = 0;
2257
2258     // If we are a frameset just print with the layout we have on the screen. Otherwise do a relayout
2259     // according to the page width.
2260     if (!frame->document() || !frame->document()->isFrameSet()) {
2261         minLayoutWidth = shrinkToFit ? pageSize.width * _WebHTMLViewPrintingMinimumShrinkFactor : pageSize.width;
2262         minLayoutHeight = shrinkToFit ? pageSize.height * _WebHTMLViewPrintingMinimumShrinkFactor : pageSize.height;
2263         maxLayoutWidth = shrinkToFit ? pageSize.width * _WebHTMLViewPrintingMaximumShrinkFactor : pageSize.width;
2264     }
2265     [self _setPrinting:[self _isInPrintMode] minimumPageWidth:minLayoutWidth height:minLayoutHeight maximumPageWidth:maxLayoutWidth adjustViewSize:YES paginateScreenContent:YES];
2266
2267     return YES;
2268 }
2269
2270 - (void)_endScreenPaginationMode
2271 {
2272     [self _setPrinting:[self _isInPrintMode] minimumPageWidth:0 height:0 maximumPageWidth:0 adjustViewSize:YES paginateScreenContent:NO];
2273 }
2274
2275 - (CGFloat)_adjustedBottomOfPageWithTop:(CGFloat)top bottom:(CGFloat)bottom limit:(CGFloat)bottomLimit
2276 {
2277     Frame* frame = core([self _frame]);
2278     if (!frame)
2279         return bottom;
2280
2281     FrameView* view = frame->view();
2282     if (!view)
2283         return bottom;
2284
2285     float newBottom;
2286     view->adjustPageHeightDeprecated(&newBottom, top, bottom, bottomLimit);
2287
2288 #ifdef __LP64__
2289     // If the new bottom is equal to the old bottom (when both are treated as floats), we just return the original
2290     // bottom. This prevents rounding errors that can occur when converting newBottom to a double.
2291     if (fabs(static_cast<float>(bottom) - newBottom) <= numeric_limits<float>::epsilon()) 
2292         return bottom;
2293     else
2294 #endif
2295         return newBottom;
2296 }
2297
2298 @end
2299
2300 @implementation NSView (WebHTMLViewFileInternal)
2301
2302 - (void)_web_addDescendantWebHTMLViewsToArray:(NSMutableArray *)array
2303 {
2304     unsigned count = [_subviews count];
2305     for (unsigned i = 0; i < count; ++i) {
2306         NSView *child = [_subviews objectAtIndex:i];
2307         if ([child isKindOfClass:[WebHTMLView class]])
2308             [array addObject:child];
2309         [child _web_addDescendantWebHTMLViewsToArray:array];
2310     }
2311 }
2312
2313 @end
2314
2315 @implementation NSMutableDictionary (WebHTMLViewFileInternal)
2316
2317 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key
2318 {
2319     if (object == nil) {
2320         [self removeObjectForKey:key];
2321     } else {
2322         [self setObject:object forKey:key];
2323     }
2324 }
2325
2326 @end
2327
2328 static bool matchesExtensionOrEquivalent(NSString *filename, NSString *extension)
2329 {
2330     NSString *extensionAsSuffix = [@"." stringByAppendingString:extension];
2331     return [filename _webkit_hasCaseInsensitiveSuffix:extensionAsSuffix]
2332         || ([extension _webkit_isCaseInsensitiveEqualToString:@"jpeg"]
2333             && [filename _webkit_hasCaseInsensitiveSuffix:@".jpg"]);
2334 }
2335
2336 #ifdef BUILDING_ON_TIGER
2337
2338 // The following is a workaround for
2339 // <rdar://problem/3429631> window stops getting mouse moved events after first tooltip appears
2340 // The trick is to define a category on NSToolTipPanel that implements setAcceptsMouseMovedEvents:.
2341 // Since the category will be searched before the real class, we'll prevent the flag from being
2342 // set on the tool tip panel.
2343
2344 @interface NSToolTipPanel : NSPanel
2345 @end
2346
2347 @interface NSToolTipPanel (WebHTMLViewFileInternal)
2348 @end
2349
2350 @implementation NSToolTipPanel (WebHTMLViewFileInternal)
2351
2352 - (void)setAcceptsMouseMovedEvents:(BOOL)flag
2353 {
2354     // Do nothing, preventing the tool tip panel from trying to accept mouse-moved events.
2355 }
2356
2357 @end
2358
2359 #endif
2360
2361 @implementation WebHTMLView
2362
2363 + (void)initialize
2364 {
2365     [NSApp registerServicesMenuSendTypes:[[self class] _selectionPasteboardTypes] 
2366                              returnTypes:[[self class] _insertablePasteboardTypes]];
2367     JSC::initializeThreading();
2368     WTF::initializeMainThreadToProcessMainThread();
2369 #ifndef BUILDING_ON_TIGER
2370     WebCoreObjCFinalizeOnMainThread(self);
2371 #endif
2372 }
2373
2374 - (id)initWithFrame:(NSRect)frame
2375 {
2376     self = [super initWithFrame:frame];
2377     if (!self)
2378         return nil;
2379     
2380     [self setFocusRingType:NSFocusRingTypeNone];
2381     
2382     // Make all drawing go through us instead of subviews.
2383     [self _setDrawsOwnDescendants:YES];
2384     
2385     _private = [[WebHTMLViewPrivate alloc] init];
2386
2387     _private->pluginController = [[WebPluginController alloc] initWithDocumentView:self];
2388     
2389     return self;
2390 }
2391
2392 - (void)dealloc
2393 {
2394     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHTMLView class], self))
2395         return;
2396
2397     // We can't assert that close has already been called because
2398     // this view can be removed from it's superview, even though
2399     // it could be needed later, so close if needed.
2400     [self close];
2401     [_private release];
2402     _private = nil;
2403     [super dealloc];
2404 }
2405
2406 - (void)finalize
2407 {
2408     ASSERT_MAIN_THREAD();
2409     // We can't assert that close has already been called because
2410     // this view can be removed from it's superview, even though
2411     // it could be needed later, so close if needed.
2412     [self close];
2413     [super finalize];
2414 }
2415
2416 // Returns YES if the delegate returns YES (so we should do no more work).
2417 - (BOOL)callDelegateDoCommandBySelectorIfNeeded:(SEL)selector
2418 {
2419     BOOL callerAlreadyCalledDelegate = _private->selectorForDoCommandBySelector == selector;
2420     _private->selectorForDoCommandBySelector = 0;
2421     if (callerAlreadyCalledDelegate)
2422         return NO;
2423     WebView *webView = [self _webView];
2424     return [[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector];
2425 }
2426
2427 typedef HashMap<SEL, String> SelectorNameMap;
2428
2429 // Map selectors into Editor command names.
2430 // This is not needed for any selectors that have the same name as the Editor command.
2431 static const SelectorNameMap* createSelectorExceptionMap()
2432 {
2433     SelectorNameMap* map = new HashMap<SEL, String>;
2434
2435     map->add(@selector(insertNewlineIgnoringFieldEditor:), "InsertNewline");
2436     map->add(@selector(insertParagraphSeparator:), "InsertNewline");
2437     map->add(@selector(insertTabIgnoringFieldEditor:), "InsertTab");
2438     map->add(@selector(pageDown:), "MovePageDown");
2439     map->add(@selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection");
2440     map->add(@selector(pageUp:), "MovePageUp");
2441     map->add(@selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection");
2442
2443     return map;
2444 }
2445
2446 static String commandNameForSelector(SEL selector)
2447 {
2448     // Check the exception map first.
2449     static const SelectorNameMap* exceptionMap = createSelectorExceptionMap();
2450     SelectorNameMap::const_iterator it = exceptionMap->find(selector);
2451     if (it != exceptionMap->end())
2452         return it->second;
2453
2454     // Remove the trailing colon.
2455     // No need to capitalize the command name since Editor command names are
2456     // not case sensitive.
2457     const char* selectorName = sel_getName(selector);
2458     size_t selectorNameLength = strlen(selectorName);
2459     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
2460         return String();
2461     return String(selectorName, selectorNameLength - 1);
2462 }
2463
2464 - (Editor::Command)coreCommandBySelector:(SEL)selector
2465 {
2466     Frame* coreFrame = core([self _frame]);
2467     if (!coreFrame)
2468         return Editor::Command();
2469     return coreFrame->editor()->command(commandNameForSelector(selector));
2470 }
2471
2472 - (Editor::Command)coreCommandByName:(const char*)name
2473 {
2474     Frame* coreFrame = core([self _frame]);
2475     if (!coreFrame)
2476         return Editor::Command();
2477     return coreFrame->editor()->command(name);
2478 }
2479
2480 - (void)executeCoreCommandBySelector:(SEL)selector
2481 {
2482     if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
2483         return;
2484     [self coreCommandBySelector:selector].execute();
2485 }
2486
2487 - (void)executeCoreCommandByName:(const char*)name
2488 {
2489     [self coreCommandByName:name].execute();
2490 }
2491
2492 // These commands are forwarded to the Editor object in WebCore.
2493 // Ideally we'd do this for all editing commands; more of the code
2494 // should be moved from here to there, and more commands should be
2495 // added to this list.
2496
2497 // FIXME: Maybe we should set things up so that all these share a single method implementation function.
2498 // The functions are identical.
2499
2500 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { [self executeCoreCommandBySelector:_cmd]; }
2501
2502 WEBCORE_COMMAND(alignCenter)
2503 WEBCORE_COMMAND(alignJustified)
2504 WEBCORE_COMMAND(alignLeft)
2505 WEBCORE_COMMAND(alignRight)
2506 WEBCORE_COMMAND(copy)
2507 WEBCORE_COMMAND(cut)
2508 WEBCORE_COMMAND(paste)
2509 WEBCORE_COMMAND(delete)
2510 WEBCORE_COMMAND(deleteBackward)
2511 WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter)
2512 WEBCORE_COMMAND(deleteForward)
2513 WEBCORE_COMMAND(deleteToBeginningOfLine)
2514 WEBCORE_COMMAND(deleteToBeginningOfParagraph)
2515 WEBCORE_COMMAND(deleteToEndOfLine)
2516 WEBCORE_COMMAND(deleteToEndOfParagraph)
2517 WEBCORE_COMMAND(deleteToMark)
2518 WEBCORE_COMMAND(deleteWordBackward)
2519 WEBCORE_COMMAND(deleteWordForward)
2520 WEBCORE_COMMAND(ignoreSpelling)
2521 WEBCORE_COMMAND(indent)
2522 WEBCORE_COMMAND(insertBacktab)
2523 WEBCORE_COMMAND(insertLineBreak)
2524 WEBCORE_COMMAND(insertNewline)
2525 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
2526 WEBCORE_COMMAND(insertParagraphSeparator)
2527 WEBCORE_COMMAND(insertTab)
2528 WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
2529 WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight)
2530 WEBCORE_COMMAND(makeTextWritingDirectionNatural)
2531 WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft)
2532 WEBCORE_COMMAND(moveBackward)
2533 WEBCORE_COMMAND(moveBackwardAndModifySelection)
2534 WEBCORE_COMMAND(moveDown)
2535 WEBCORE_COMMAND(moveDownAndModifySelection)
2536 WEBCORE_COMMAND(moveForward)
2537 WEBCORE_COMMAND(moveForwardAndModifySelection)
2538 WEBCORE_COMMAND(moveLeft)
2539 WEBCORE_COMMAND(moveLeftAndModifySelection)
2540 WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection)
2541 WEBCORE_COMMAND(moveParagraphForwardAndModifySelection)
2542 WEBCORE_COMMAND(moveRight)
2543 WEBCORE_COMMAND(moveRightAndModifySelection)
2544 WEBCORE_COMMAND(moveToBeginningOfDocument)
2545 WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection)
2546 WEBCORE_COMMAND(moveToBeginningOfLine)
2547 WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection)
2548 WEBCORE_COMMAND(moveToBeginningOfParagraph)
2549 WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection)
2550 WEBCORE_COMMAND(moveToBeginningOfSentence)
2551 WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection)
2552 WEBCORE_COMMAND(moveToEndOfDocument)
2553 WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection)
2554 WEBCORE_COMMAND(moveToEndOfLine)
2555 WEBCORE_COMMAND(moveToEndOfLineAndModifySelection)
2556 WEBCORE_COMMAND(moveToEndOfParagraph)
2557 WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection)
2558 WEBCORE_COMMAND(moveToEndOfSentence)
2559 WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection)
2560 WEBCORE_COMMAND(moveToLeftEndOfLine)
2561 WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection)
2562 WEBCORE_COMMAND(moveToRightEndOfLine)
2563 WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection)
2564 WEBCORE_COMMAND(moveUp)
2565 WEBCORE_COMMAND(moveUpAndModifySelection)
2566 WEBCORE_COMMAND(moveWordBackward)
2567 WEBCORE_COMMAND(moveWordBackwardAndModifySelection)
2568 WEBCORE_COMMAND(moveWordForward)
2569 WEBCORE_COMMAND(moveWordForwardAndModifySelection)
2570 WEBCORE_COMMAND(moveWordLeft)
2571 WEBCORE_COMMAND(moveWordLeftAndModifySelection)
2572 WEBCORE_COMMAND(moveWordRight)
2573 WEBCORE_COMMAND(moveWordRightAndModifySelection)
2574 WEBCORE_COMMAND(outdent)
2575 WEBCORE_COMMAND(pageDown)
2576 WEBCORE_COMMAND(pageDownAndModifySelection)
2577 WEBCORE_COMMAND(pageUp)
2578 WEBCORE_COMMAND(pageUpAndModifySelection)
2579 WEBCORE_COMMAND(pasteAsPlainText)
2580 WEBCORE_COMMAND(selectAll)
2581 WEBCORE_COMMAND(selectLine)
2582 WEBCORE_COMMAND(selectParagraph)
2583 WEBCORE_COMMAND(selectSentence)
2584 WEBCORE_COMMAND(selectToMark)
2585 WEBCORE_COMMAND(selectWord)
2586 WEBCORE_COMMAND(setMark)
2587 WEBCORE_COMMAND(subscript)
2588 WEBCORE_COMMAND(superscript)
2589 WEBCORE_COMMAND(swapWithMark)
2590 WEBCORE_COMMAND(transpose)
2591 WEBCORE_COMMAND(underline)
2592 WEBCORE_COMMAND(unscript)
2593 WEBCORE_COMMAND(yank)
2594 WEBCORE_COMMAND(yankAndSelect)
2595
2596 #undef WEBCORE_COMMAND
2597
2598 #define COMMAND_PROLOGUE if ([self callDelegateDoCommandBySelectorIfNeeded:_cmd]) return;
2599
2600 - (IBAction)takeFindStringFromSelection:(id)sender
2601 {
2602     COMMAND_PROLOGUE
2603
2604     if (![self _hasSelection]) {
2605         NSBeep();
2606         return;
2607     }
2608
2609     [NSPasteboard _web_setFindPasteboardString:[self selectedString] withOwner:self];
2610 }
2611
2612 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
2613 {
2614     [pasteboard declareTypes:types owner:[self _topHTMLView]];
2615     [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2616     return YES;
2617 }
2618
2619 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
2620 {
2621     BOOL isSendTypeOK = !sendType || ([[self pasteboardTypesForSelection] containsObject:sendType] && [self _hasSelection]);
2622     BOOL isReturnTypeOK = NO;
2623     if (!returnType)
2624         isReturnTypeOK = YES;
2625     else if ([[[self class] _insertablePasteboardTypes] containsObject:returnType] && [self _isEditable]) {
2626         // We can insert strings in any editable context.  We can insert other types, like images, only in rich edit contexts.
2627         isReturnTypeOK = [returnType isEqualToString:NSStringPboardType] || [self _canEditRichly];
2628     }
2629     if (isSendTypeOK && isReturnTypeOK)
2630         return self;
2631     return [[self nextResponder] validRequestorForSendType:sendType returnType:returnType];
2632 }
2633
2634 // jumpToSelection is the old name for what AppKit now calls centerSelectionInVisibleArea. Safari
2635 // was using the old jumpToSelection selector in its menu. Newer versions of Safari will use the
2636 // selector centerSelectionInVisibleArea. We'll leave the old selector in place for two reasons:
2637 // (1) Compatibility between older Safari and newer WebKit; (2) other WebKit-based applications
2638 // might be using the selector, and we don't want to break them.
2639 - (void)jumpToSelection:(id)sender
2640 {
2641     COMMAND_PROLOGUE
2642
2643     if (Frame* coreFrame = core([self _frame]))
2644         coreFrame->selection()->revealSelection(ScrollAlignment::alignCenterAlways);
2645 }
2646
2647 - (NSCellStateValue)selectionHasStyle:(CSSStyleDeclaration*)style
2648 {
2649     Frame* coreFrame = core([self _frame]);
2650     if (!coreFrame)
2651         return NSOffState;
2652     return kit(coreFrame->editor()->selectionHasStyle(style));
2653 }
2654
2655 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
2656 {
2657     SEL action = [item action];
2658     RefPtr<Frame> frame = core([self _frame]);
2659
2660     if (!frame)
2661         return NO;
2662     
2663     if (Document* doc = frame->document()) {
2664         if (doc->isPluginDocument())
2665             return NO;
2666         if (doc->isImageDocument()) {            
2667             if (action == @selector(copy:))
2668                 return frame->loader()->isComplete();
2669             return NO;
2670         }
2671     }
2672
2673     if (action == @selector(changeSpelling:)
2674             || action == @selector(_changeSpellingFromMenu:)
2675             || action == @selector(checkSpelling:)
2676             || action == @selector(complete:)
2677             || action == @selector(pasteFont:))
2678         return [self _canEdit];
2679
2680     if (action == @selector(showGuessPanel:)) {
2681 #ifndef BUILDING_ON_TIGER
2682         // Match OS X AppKit behavior for post-Tiger. Don't change Tiger behavior.
2683         NSMenuItem *menuItem = (NSMenuItem *)item;
2684         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2685             BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible];
2686             [menuItem setTitle:panelShowing
2687                 ? UI_STRING("Hide Spelling and Grammar", "menu item title")
2688                 : UI_STRING("Show Spelling and Grammar", "menu item title")];
2689         }
2690 #endif
2691         return [self _canEdit];
2692     }
2693     
2694     if (action == @selector(changeBaseWritingDirection:)
2695             || action == @selector(makeBaseWritingDirectionLeftToRight:)
2696             || action == @selector(makeBaseWritingDirectionRightToLeft:)) {
2697         NSWritingDirection writingDirection;
2698
2699         if (action == @selector(changeBaseWritingDirection:)) {
2700             writingDirection = static_cast<NSWritingDirection>([item tag]);
2701             if (writingDirection == NSWritingDirectionNatural)
2702                 return NO;
2703         } else if (action == @selector(makeBaseWritingDirectionLeftToRight:))
2704             writingDirection = NSWritingDirectionLeftToRight;
2705         else
2706             writingDirection = NSWritingDirectionRightToLeft;
2707
2708         NSMenuItem *menuItem = (NSMenuItem *)item;
2709         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2710             RefPtr<CSSStyleDeclaration> style = CSSMutableStyleDeclaration::create();
2711             ExceptionCode ec;
2712             style->setProperty("direction", writingDirection == NSWritingDirectionLeftToRight ? "LTR" : "RTL", ec);
2713             [menuItem setState:frame->editor()->selectionHasStyle(style.get())];
2714         }
2715         return [self _canEdit];
2716     }
2717
2718     if (action == @selector(makeBaseWritingDirectionNatural:)) {
2719         NSMenuItem *menuItem = (NSMenuItem *)item;
2720         if ([menuItem isKindOfClass:[NSMenuItem class]])
2721             [menuItem setState:NSOffState];
2722         return NO;
2723     }
2724
2725     if (action == @selector(toggleBaseWritingDirection:)) {
2726         NSMenuItem *menuItem = (NSMenuItem *)item;
2727         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2728             RefPtr<CSSStyleDeclaration> style = CSSMutableStyleDeclaration::create();
2729             ExceptionCode ec;
2730             style->setProperty("direction", "RTL", ec);
2731             // Take control of the title of the menu item instead of just checking/unchecking it because
2732             // a check would be ambiguous.
2733             [menuItem setTitle:frame->editor()->selectionHasStyle(style.get())
2734                 ? UI_STRING("Left to Right", "Left to Right context menu item")
2735                 : UI_STRING("Right to Left", "Right to Left context menu item")];
2736         }
2737         return [self _canEdit];
2738     } 
2739     
2740     if (action == @selector(changeAttributes:)
2741             || action == @selector(changeColor:)        
2742             || action == @selector(changeFont:))
2743         return [self _canEditRichly];
2744     
2745     if (action == @selector(capitalizeWord:)
2746                || action == @selector(lowercaseWord:)
2747                || action == @selector(uppercaseWord:))
2748         return [self _hasSelection] && [self _isEditable];
2749
2750     if (action == @selector(centerSelectionInVisibleArea:)
2751                || action == @selector(jumpToSelection:)
2752                || action == @selector(copyFont:))
2753         return [self _hasSelection] || ([self _isEditable] && [self _hasInsertionPoint]);
2754     
2755     if (action == @selector(changeDocumentBackgroundColor:))
2756         return [[self _webView] isEditable] && [self _canEditRichly];
2757     
2758     if (action == @selector(_ignoreSpellingFromMenu:)
2759             || action == @selector(_learnSpellingFromMenu:)
2760             || action == @selector(takeFindStringFromSelection:))
2761         return [self _hasSelection];
2762     
2763     if (action == @selector(paste:) || action == @selector(pasteAsPlainText:))
2764         return frame && (frame->editor()->canDHTMLPaste() || frame->editor()->canPaste());
2765     
2766     if (action == @selector(pasteAsRichText:))
2767         return frame && (frame->editor()->canDHTMLPaste()
2768             || (frame->editor()->canPaste() && frame->selection()->isContentRichlyEditable()));
2769     
2770     if (action == @selector(performFindPanelAction:))
2771         return NO;
2772     
2773     if (action == @selector(_lookUpInDictionaryFromMenu:))
2774         return [self _hasSelection];
2775
2776     if (action == @selector(stopSpeaking:))
2777         return [NSApp isSpeaking];
2778
2779 #ifndef BUILDING_ON_TIGER
2780     if (action == @selector(toggleGrammarChecking:)) {
2781         // FIXME 4799134: WebView is the bottleneck for this grammar-checking logic, but we must validate 
2782         // the selector here because we implement it here, and we must implement it here because the AppKit 
2783         // code checks the first responder.
2784         NSMenuItem *menuItem = (NSMenuItem *)item;
2785         if ([menuItem isKindOfClass:[NSMenuItem class]])
2786             [menuItem setState:[self isGrammarCheckingEnabled] ? NSOnState : NSOffState];
2787         return YES;
2788     }
2789 #endif
2790
2791 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2792     if (action == @selector(orderFrontSubstitutionsPanel:)) {
2793         NSMenuItem *menuItem = (NSMenuItem *)item;
2794         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2795             BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible];
2796             [menuItem setTitle:panelShowing
2797                 ? UI_STRING("Hide Substitutions", "menu item title")
2798                 : UI_STRING("Show Substitutions", "menu item title")];
2799         }
2800         return [self _canEdit];
2801     }
2802     // FIXME 4799134: WebView is the bottleneck for this logic, but we must validate 
2803     // the selector here because we implement it here, and we must implement it here because the AppKit 
2804     // code checks the first responder.
2805     if (action == @selector(toggleSmartInsertDelete:)) {
2806         NSMenuItem *menuItem = (NSMenuItem *)item;
2807         if ([menuItem isKindOfClass:[NSMenuItem class]])
2808             [menuItem setState:[self smartInsertDeleteEnabled] ? NSOnState : NSOffState];
2809         return [self _canEdit];
2810     }
2811     if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
2812         NSMenuItem *menuItem = (NSMenuItem *)item;
2813         if ([menuItem isKindOfClass:[NSMenuItem class]])
2814             [menuItem setState:[self isAutomaticQuoteSubstitutionEnabled] ? NSOnState : NSOffState];
2815         return [self _canEdit];
2816     }
2817     if (action == @selector(toggleAutomaticLinkDetection:)) {
2818         NSMenuItem *menuItem = (NSMenuItem *)item;
2819         if ([menuItem isKindOfClass:[NSMenuItem class]])
2820             [menuItem setState:[self isAutomaticLinkDetectionEnabled] ? NSOnState : NSOffState];
2821         return [self _canEdit];
2822     }
2823     if (action == @selector(toggleAutomaticDashSubstitution:)) {
2824         NSMenuItem *menuItem = (NSMenuItem *)item;
2825         if ([menuItem isKindOfClass:[NSMenuItem class]])
2826             [menuItem setState:[self isAutomaticDashSubstitutionEnabled] ? NSOnState : NSOffState];
2827         return [self _canEdit];
2828     }
2829     if (action == @selector(toggleAutomaticTextReplacement:)) {
2830         NSMenuItem *menuItem = (NSMenuItem *)item;
2831         if ([menuItem isKindOfClass:[NSMenuItem class]])
2832             [menuItem setState:[self isAutomaticTextReplacementEnabled] ? NSOnState : NSOffState];
2833         return [self _canEdit];
2834     }
2835     if (action == @selector(toggleAutomaticSpellingCorrection:)) {
2836         NSMenuItem *menuItem = (NSMenuItem *)item;
2837         if ([menuItem isKindOfClass:[NSMenuItem class]])
2838             [menuItem setState:[self isAutomaticSpellingCorrectionEnabled] ? NSOnState : NSOffState];
2839         return [self _canEdit];
2840     }
2841 #endif
2842     
2843     Editor::Command command = [self coreCommandBySelector:action];
2844     if (command.isSupported()) {
2845         NSMenuItem *menuItem = (NSMenuItem *)item;
2846         if ([menuItem isKindOfClass:[NSMenuItem class]])
2847             [menuItem setState:kit(command.state())];
2848         return command.isEnabled();
2849     }
2850
2851     return YES;
2852 }
2853
2854 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2855 {
2856     // This can be called during teardown when _webView is nil. Return NO when this happens, because CallUIDelegateReturningBoolean
2857     // assumes the WebVIew is non-nil.
2858     if (![self _webView])
2859         return NO;
2860     BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
2861     return CallUIDelegateReturningBoolean(result, [self _webView], @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
2862 }
2863
2864 - (BOOL)acceptsFirstResponder
2865 {
2866     // Don't accept first responder when we first click on this view.
2867     // We have to pass the event down through WebCore first to be sure we don't hit a subview.
2868     // Do accept first responder at any other time, for example from keyboard events,
2869     // or from calls back from WebCore once we begin mouse-down event handling.
2870     NSEvent *event = [NSApp currentEvent];
2871     if ([event type] == NSLeftMouseDown
2872             && !_private->handlingMouseDownEvent
2873             && NSPointInRect([event locationInWindow], [self convertRect:[self visibleRect] toView:nil])) {
2874         return NO;
2875     }
2876     return YES;
2877 }
2878
2879 - (BOOL)maintainsInactiveSelection
2880 {
2881     // This method helps to determine whether the WebHTMLView should maintain
2882     // an inactive selection when it's not first responder.
2883     // Traditionally, these views have not maintained such selections,
2884     // clearing them when the view was not first responder. However,
2885     // to fix bugs like this one:
2886     // <rdar://problem/3672088>: "Editable WebViews should maintain a selection even 
2887     //                            when they're not firstResponder"
2888     // it was decided to add a switch to act more like an NSTextView.
2889
2890     if ([[self _webView] maintainsInactiveSelection])
2891         return YES;
2892
2893     // Predict the case where we are losing first responder status only to
2894     // gain it back again. Want to keep the selection in that case.
2895     id nextResponder = [[self window] _newFirstResponderAfterResigning];
2896     if ([nextResponder isKindOfClass:[NSScrollView class]]) {
2897         id contentView = [nextResponder contentView];
2898         if (contentView)
2899             nextResponder = contentView;
2900     }
2901     if ([nextResponder isKindOfClass:[NSClipView class]]) {
2902         id documentView = [nextResponder documentView];
2903         if (documentView)
2904             nextResponder = documentView;
2905     }
2906     if (nextResponder == self)
2907         return YES;
2908
2909     Frame* coreFrame = core([self _frame]);
2910     bool selectionIsEditable = coreFrame && coreFrame->selection()->isContentEditable();
2911     bool nextResponderIsInWebView = [nextResponder isKindOfClass:[NSView class]]
2912         && [nextResponder isDescendantOf:[[[self _webView] mainFrame] frameView]];
2913
2914     return selectionIsEditable && nextResponderIsInWebView;
2915 }
2916
2917 - (void)addMouseMovedObserver
2918 {
2919     if (!_private->dataSource || ![self _isTopHTMLView] || _private->observingMouseMovedNotifications)
2920         return;
2921
2922     // Unless the Dashboard asks us to do this for all windows, keep an observer going only for the key window.
2923     if (!([[self window] isKeyWindow] 
2924 #if ENABLE(DASHBOARD_SUPPORT)
2925             || [[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows]
2926 #endif
2927         ))
2928         return;
2929
2930     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mouseMovedNotification:)
2931         name:WKMouseMovedNotification() object:nil];
2932     [self _frameOrBoundsChanged];
2933     _private->observingMouseMovedNotifications = true;
2934 }
2935
2936 - (void)removeMouseMovedObserver
2937 {
2938 #if ENABLE(DASHBOARD_SUPPORT)
2939     // Don't remove the observer if we're running the Dashboard.
2940     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows])
2941         return;
2942 #endif
2943
2944     [[self _webView] _mouseDidMoveOverElement:nil modifierFlags:0];
2945     [self _removeMouseMovedObserverUnconditionally];
2946 }
2947
2948 - (void)addSuperviewObservers
2949 {
2950     if (_private->observingSuperviewNotifications)
2951         return;
2952
2953     NSView *superview = [self superview];
2954     if (!superview || ![self window])
2955         return;
2956     
2957     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
2958     [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewFrameDidChangeNotification object:superview];
2959     [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewBoundsDidChangeNotification object:superview];
2960     
2961     // In addition to registering for frame/bounds change notifications, call -_frameOrBoundsChanged.
2962     // It will check the current scroll against the previous layout's scroll.  We need to
2963     // do this here to catch the case where the WebView is laid out at one size, removed from its
2964     // window, resized, and inserted into another window.  Our frame/bounds changed notifications
2965     // will not be sent in that situation, since we only watch for changes while in the view hierarchy.
2966     [self _frameOrBoundsChanged];
2967     
2968     _private->observingSuperviewNotifications = true;
2969 }
2970
2971 - (void)addWindowObservers
2972 {
2973     if (_private->observingWindowNotifications)
2974         return;
2975     
2976     NSWindow *window = [self window];
2977     if (!window)
2978         return;
2979     
2980     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
2981     [notificationCenter addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:nil];
2982     [notificationCenter addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:nil];
2983     [notificationCenter addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:window];
2984     
2985     _private->observingWindowNotifications = true;
2986 }
2987
2988 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
2989 {
2990     [self _removeSuperviewObservers];
2991 }
2992
2993 - (void)viewDidMoveToSuperview
2994 {
2995     if ([self superview] != nil)
2996         [self addSuperviewObservers];
2997
2998 #if USE(ACCELERATED_COMPOSITING)
2999     if ([self superview] && [self _isUsingAcceleratedCompositing]) {
3000         WebView *webView = [self _webView];
3001         if ([webView _postsAcceleratedCompositingNotifications])
3002             [[NSNotificationCenter defaultCenter] postNotificationName:_WebViewDidStartAcceleratedCompositingNotification object:webView userInfo:nil];
3003     }
3004 #endif
3005 }
3006
3007 - (void)viewWillMoveToWindow:(NSWindow *)window
3008 {
3009     // Don't do anything if we aren't initialized.  This happens
3010     // when decoding a WebView.  When WebViews are decoded their subviews
3011     // are created by initWithCoder: and so won't be normally
3012     // initialized.  The stub views are discarded by WebView.
3013     if (!_private)
3014         return;
3015
3016     // FIXME: Some of these calls may not work because this view may be already removed from it's superview.
3017     [self _removeMouseMovedObserverUnconditionally];
3018     [self _removeWindowObservers];
3019     [self _removeSuperviewObservers];
3020     [self _cancelUpdateMouseoverTimer];
3021
3022     // FIXME: This accomplishes the same thing as the call to setCanStartMedia(false) in
3023     // WebView. It would be nice to have a single mechanism instead of two.
3024     [[self _pluginController] stopAllPlugins];
3025 }
3026
3027 - (void)viewDidMoveToWindow
3028 {
3029     // Don't do anything if we aren't initialized.  This happens
3030     // when decoding a WebView.  When WebViews are decoded their subviews
3031     // are created by initWithCoder: and so won't be normally
3032     // initialized.  The stub views are discarded by WebView.
3033     if (!_private || _private->closed)
3034         return;
3035         
3036     [self _stopAutoscrollTimer];
3037     if ([self window]) {
3038         _private->lastScrollPosition = [[self superview] bounds].origin;
3039         [self addWindowObservers];
3040         [self addSuperviewObservers];
3041         [self addMouseMovedObserver];
3042
3043         // FIXME: This accomplishes the same thing as the call to setCanStartMedia(true) in
3044         // WebView. It would be nice to have a single mechanism instead of two.
3045         [[self _pluginController] startAllPlugins];
3046
3047         _private->lastScrollPosition = NSZeroPoint;
3048         
3049 #if USE(ACCELERATED_COMPOSITING) && !defined(BUILDING_ON_LEOPARD)
3050         // We may have created the layer hosting view while outside the window. Update the scale factor
3051         // now that we have a window to get it from.
3052         if (_private->layerHostingView) {
3053             CGFloat scaleFactor = [[self window] userSpaceScaleFactor];
3054             [[_private->layerHostingView layer] setTransform:CATransform3DMakeScale(scaleFactor, scaleFactor, 1)];
3055         }
3056 #endif
3057     }
3058 }
3059
3060 - (void)_web_makePluginSubviewsPerformSelector:(SEL)selector withObject:(id)object
3061 {
3062 #if ENABLE(NETSCAPE_PLUGIN_API)
3063     // Copy subviews because [self subviews] returns the view's mutable internal array,
3064     // and we must avoid mutating the array while enumerating it.
3065     NSArray *subviews = [[self subviews] copy];
3066     
3067     NSEnumerator *enumerator = [subviews objectEnumerator];
3068     WebNetscapePluginView *view;
3069     while ((view = [enumerator nextObject]) != nil)
3070         if ([view isKindOfClass:[WebBaseNetscapePluginView class]])
3071             [view performSelector:selector withObject:object];
3072     
3073     [subviews release];
3074 #endif
3075 }
3076
3077 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
3078 {
3079     [self _web_makePluginSubviewsPerformSelector:@selector(viewWillMoveToHostWindow:) withObject:hostWindow];
3080 }
3081
3082 - (void)viewDidMoveToHostWindow
3083 {
3084     [self _web_makePluginSubviewsPerformSelector:@selector(viewDidMoveToHostWindow) withObject:nil];
3085 }
3086
3087
3088 - (void)addSubview:(NSView *)view
3089 {
3090     [super addSubview:view];
3091
3092     if ([WebPluginController isPlugInView:view])
3093         [[self _pluginController] addPlugin:view];
3094 }
3095
3096 - (void)willRemoveSubview:(NSView *)subview
3097 {
3098 #ifndef NDEBUG
3099     // Have to null-check _private, since this can be called via -dealloc when
3100     // cleaning up the the layerHostingView.
3101     if (_private && _private->enumeratingSubviews)
3102         LOG(View, "A view of class %s was removed during subview enumeration for layout or printing mode change. We will still do layout or the printing mode change even though this view is no longer in the view hierarchy.", object_getClassName([subview class]));
3103 #endif
3104
3105     if ([WebPluginController isPlugInView:subview])
3106         [[self _pluginController] destroyPlugin:subview];
3107
3108     [super willRemoveSubview:subview];
3109 }
3110
3111 - (void)reapplyStyles
3112 {
3113 #ifdef LOG_TIMES
3114     double start = CFAbsoluteTimeGetCurrent();
3115 #endif
3116
3117     if (Frame* coreFrame = core([self _frame]))
3118         coreFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
3119     
3120 #ifdef LOG_TIMES        
3121     double thisTime = CFAbsoluteTimeGetCurrent() - start;
3122     LOG(Timing, "%s apply style seconds = %f", [self URL], thisTime);
3123 #endif
3124 }
3125
3126 // Do a layout, but set up a new fixed width for the purposes of doing printing layout.
3127 // minPageWidth==0 implies a non-printing layout
3128 - (void)layoutToMinimumPageWidth:(float)minPageWidth height:(float)minPageHeight maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)adjustViewSize
3129 {    
3130     if (![self _needsLayout])
3131         return;
3132
3133 #ifdef LOG_TIMES        
3134     double start = CFAbsoluteTimeGetCurrent();
3135 #endif
3136
3137     LOG(View, "%@ doing layout", self);
3138
3139     Frame* coreFrame = core([self _frame]);
3140     if (!coreFrame)
3141         return;
3142
3143     if (FrameView* coreView = coreFrame->view()) {
3144         if (minPageWidth > 0.0)
3145             coreView->forceLayoutForPagination(FloatSize(minPageWidth, minPageHeight), maxPageWidth / minPageWidth, adjustViewSize ? Frame::AdjustViewSize : Frame::DoNotAdjustViewSize);
3146         else {
3147             coreView->forceLayout(!adjustViewSize);
3148             if (adjustViewSize)
3149                 coreView->adjustViewSize();
3150         }
3151     }
3152     
3153 #ifdef LOG_TIMES        
3154     double thisTime = CFAbsoluteTimeGetCurrent() - start;
3155     LOG(Timing, "%s layout seconds = %f", [self URL], thisTime);
3156 #endif
3157 }
3158
3159 - (void)layout
3160 {
3161     [self layoutToMinimumPageWidth:0 height:0 maximumPageWidth:0 adjustingViewSize:NO];
3162 }
3163
3164 // Deliver mouseup events to the DOM for button 2.
3165 - (void)rightMouseUp:(NSEvent *)event
3166 {
3167     // There's a chance that if we run a nested event loop the event will be released.
3168     // Retaining and then autoreleasing prevents that from causing a problem later here or
3169     // inside AppKit code.
3170     [[event retain] autorelease];
3171
3172     [super rightMouseUp:event];
3173
3174     if (Frame* coreframe = core([self _frame]))
3175         coreframe->eventHandler()->mouseUp(event);
3176 }
3177
3178 static void setMenuItemTarget(NSMenuItem* menuItem)
3179 {
3180     // Don't set the menu item's action to the context menu action forwarder if we already
3181     // have an action.
3182     if ([menuItem action])
3183         return;
3184
3185     [menuItem setTarget:[WebMenuTarget sharedMenuTarget]];
3186     [menuItem setAction:@selector(forwardContextMenuAction:)];
3187 }
3188
3189 static void setMenuTargets(NSMenu* menu)
3190 {
3191     NSInteger itemCount = [menu numberOfItems];
3192     for (NSInteger i = 0; i < itemCount; ++i) {
3193         NSMenuItem *item = [menu itemAtIndex:i];
3194         setMenuItemTarget(item);
3195         if ([item hasSubmenu])
3196             setMenuTargets([item submenu]);
3197     }
3198 }
3199
3200 - (NSMenu *)menuForEvent:(NSEvent *)event
3201 {
3202     // There's a chance that if we run a nested event loop the event will be released.
3203     // Retaining and then autoreleasing prevents that from causing a problem later here or
3204     // inside AppKit code.
3205     [[event retain] autorelease];
3206
3207     [_private->completionController endRevertingChange:NO moveLeft:NO];
3208
3209     RefPtr<Frame> coreFrame = core([self _frame]);
3210     if (!coreFrame)
3211         return nil;
3212
3213     Page* page = coreFrame->page();
3214     if (!page)
3215         return nil;
3216
3217     // Match behavior of other browsers by sending a mousedown event for right clicks.
3218     _private->handlingMouseDownEvent = YES;
3219     page->contextMenuController()->clearContextMenu();
3220     coreFrame->eventHandler()->mouseDown(event);
3221     BOOL handledEvent = coreFrame->eventHandler()->sendContextMenuEvent(event);
3222     _private->handlingMouseDownEvent = NO;
3223
3224     if (!handledEvent)
3225         return nil;
3226
3227     // Re-get page, since it might have gone away during event handling.
3228     page = coreFrame->page();
3229     if (!page)
3230         return nil;
3231
3232     ContextMenu* coreMenu = page->contextMenuController()->contextMenu();
3233     if (!coreMenu)
3234         return nil;
3235
3236     NSArray* menuItems = coreMenu->platformDescription();
3237     if (!menuItems)
3238         return nil;
3239
3240     NSUInteger count = [menuItems count];
3241     if (!count)
3242         return nil;
3243
3244     NSMenu* menu = [[[NSMenu alloc] init] autorelease];
3245     for (NSUInteger i = 0; i < count; i++)
3246         [menu addItem:[menuItems objectAtIndex:i]];
3247     setMenuTargets(menu);
3248     
3249     [[WebMenuTarget sharedMenuTarget] setMenuController:page->contextMenuController()];
3250     
3251     return menu;
3252 }
3253
3254 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
3255 {
3256     return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
3257 }
3258
3259 - (void)clearFocus
3260 {
3261     Frame* coreFrame = core([self _frame]);
3262     if (!coreFrame)
3263         return;
3264     Document* document = coreFrame->document();
3265     if (!document)
3266         return;
3267     
3268     document->setFocusedNode(0);
3269 }
3270
3271 - (BOOL)isOpaque
3272 {
3273     return [[self _webView] drawsBackground];
3274 }
3275
3276 #if !LOG_DISABLED
3277 - (void)setNeedsDisplay:(BOOL)flag
3278 {
3279     LOG(View, "%@ setNeedsDisplay:%@", self, flag ? @"YES" : @"NO");
3280     [super setNeedsDisplay:flag];
3281 }
3282 #endif
3283
3284 #ifndef BUILDING_ON_TIGER
3285 - (void)setNeedsDisplayInRect:(NSRect)invalidRect
3286 {
3287     if (_private->inScrollPositionChanged) {
3288         // When scrolling, the dirty regions are adjusted for the scroll only
3289         // after NSViewBoundsDidChangeNotification is sent. Translate the invalid
3290         // rect to pre-scrolled coordinates in order to get the right dirty region
3291         // after adjustment. See <rdar://problem/7678927>.
3292         NSPoint origin = [[self superview] bounds].origin;
3293         invalidRect.origin.x -= _private->lastScrollPosition.x - origin.x;
3294         invalidRect.origin.y -= _private->lastScrollPosition.y - origin.y;
3295     }
3296     [super setNeedsDisplayInRect:invalidRect];
3297 }
3298 #endif
3299
3300 - (void)setNeedsLayout: (BOOL)flag
3301 {
3302     LOG(View, "%@ setNeedsLayout:%@", self, flag ? @"YES" : @"NO");
3303     if (!flag)
3304         return; // There's no way to say you don't need a layout.
3305     if (Frame* frame = core([self _frame])) {
3306         if (frame->document() && frame->document()->inPageCache())
3307             return;
3308         if (FrameView* view = frame->view())
3309             view->setNeedsLayout();
3310     }
3311 }
3312
3313 - (void)setNeedsToApplyStyles: (BOOL)flag
3314 {
3315     LOG(View, "%@ setNeedsToApplyStyles:%@", self, flag ? @"YES" : @"NO");
3316     if (!flag)
3317         return; // There's no way to say you don't need a style recalc.
3318     if (Frame* frame = core([self _frame])) {
3319         if (frame->document() && frame->document()->inPageCache())
3320             return;
3321         frame->document()->scheduleForcedStyleRecalc();
3322     }
3323 }
3324
3325 - (void)drawSingleRect:(NSRect)rect
3326 {
3327     [NSGraphicsContext saveGraphicsState];
3328     NSRectClip(rect);
3329         
3330     ASSERT([[self superview] isKindOfClass:[WebClipView class]]);
3331
3332     [(WebClipView *)[self superview] setAdditionalClip:rect];
3333
3334     @try {
3335         if ([self _transparentBackground]) {
3336             [[NSColor clearColor] set];
3337             NSRectFill (rect);
3338         }
3339
3340         [[self _frame] _drawRect:rect contentsOnly:YES];
3341
3342         WebView *webView = [self _webView];
3343
3344         // This hack is needed for <rdar://problem/5023545>. We can hit a race condition where drawRect will be
3345         // called after the WebView has closed. If the client did not properly close the WebView and set the 
3346         // UIDelegate to nil, then the UIDelegate will be stale and this code will crash. 
3347         static BOOL version3OrLaterClient = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_QUICKBOOKS_QUIRK);
3348         if (version3OrLaterClient)
3349             [[webView _UIDelegateForwarder] webView:webView didDrawRect:[webView convertRect:rect fromView:self]];
3350
3351         if (WebNodeHighlight *currentHighlight = [webView currentNodeHighlight])
3352             [currentHighlight setNeedsUpdateInTargetViewRect:[self convertRect:rect toView:[currentHighlight targetView]]];
3353
3354         [(WebClipView *)[self superview] resetAdditionalClip];
3355
3356         [NSGraphicsContext restoreGraphicsState];
3357     } @catch (NSException *localException) {
3358         [(WebClipView *)[self superview] resetAdditionalClip];
3359         [NSGraphicsContext restoreGraphicsState];
3360         LOG_ERROR("Exception caught while drawing: %@", localException);
3361         [localException raise];
3362     }
3363 }
3364
3365 - (void)drawRect:(NSRect)rect
3366 {
3367     ASSERT_MAIN_THREAD();
3368     LOG(View, "%@ drawing", self);
3369
3370     const NSRect *rects;
3371     NSInteger count;
3372     [self getRectsBeingDrawn:&rects count:&count];
3373
3374     BOOL subviewsWereSetAside = _private->subviewsSetAside;
3375     if (subviewsWereSetAside)
3376         [self _restoreSubviews];
3377
3378 #ifdef LOG_TIMES
3379     double start = CFAbsoluteTimeGetCurrent();
3380 #endif
3381
3382     WebView *webView = [self _webView];
3383     if ([webView _mustDrawUnionedRect:rect singleRects:rects count:count])
3384         [self drawSingleRect:rect];
3385     else
3386         for (int i = 0; i < count; ++i)
3387             [self drawSingleRect:rects[i]];
3388
3389 #ifdef LOG_TIMES
3390     double thisTime = CFAbsoluteTimeGetCurrent() - start;
3391     LOG(Timing, "%s draw seconds = %f", widget->part()->baseURL().URL().latin1(), thisTime);
3392 #endif
3393
3394     if (subviewsWereSetAside)
3395         [self _setAsideSubviews];
3396
3397 #if USE(ACCELERATED_COMPOSITING)
3398     // Only do the synchronization dance if we're drawing into the window, otherwise
3399     // we risk disabling screen updates when no flush is pending.
3400     if ([NSGraphicsContext currentContext] == [[self window] graphicsContext] && [webView _needsOneShotDrawingSynchronization]) {
3401         // Disable screen updates to minimize the chances of the race between the CA
3402         // display link and AppKit drawing causing flashes.
3403         [[self window] disableScreenUpdatesUntilFlush];
3404         
3405         // Make sure any layer changes that happened as a result of layout
3406         // via -viewWillDraw are committed.
3407         [CATransaction flush];
3408         [webView _setNeedsOneShotDrawingSynchronization:NO];
3409     }
3410 #endif
3411
3412     if (webView)
3413         CallUIDelegate(webView, @selector(webView:didDrawFrame:), [self _frame]);
3414 }
3415
3416 // Turn off the additional clip while computing our visibleRect.
3417 - (NSRect)visibleRect
3418 {
3419     if (!([[self superview] isKindOfClass:[WebClipView class]]))
3420         return [super visibleRect];
3421
3422     WebClipView *clipView = (WebClipView *)[self superview];
3423
3424     BOOL hasAdditionalClip = [clipView hasAdditionalClip];
3425     if (!hasAdditionalClip) {
3426         return [super visibleRect];
3427     }
3428     
3429     NSRect additionalClip = [clipView additionalClip];
3430     [clipView resetAdditionalClip];
3431     NSRect visibleRect = [super visibleRect];
3432     [clipView setAdditionalClip:additionalClip];
3433     return visibleRect;
3434 }
3435
3436 - (void)_invalidateGStatesForTree
3437 {
3438     // AppKit is in the process of traversing the NSView tree, and is going to send -renewGState to
3439     // descendants, including plug-in views. This can result in calls out to plug-in code and back into
3440     // WebCore via JavaScript, which could normally mutate the NSView tree while it is being traversed.
3441     // Defer those mutations while descendants are being traveresed.
3442     RenderWidget::suspendWidgetHierarchyUpdates();
3443     [super _invalidateGStatesForTree];
3444     RenderWidget::resumeWidgetHierarchyUpdates();
3445 }
3446
3447 - (BOOL)isFlipped 
3448 {
3449     return YES;
3450 }
3451
3452 - (void)windowDidBecomeKey:(NSNotification *)notification
3453 {
3454     if (!pthread_main_np()) {
3455         [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
3456         return;
3457     }
3458
3459     NSWindow *keyWindow = [notification object];
3460
3461     if (keyWindow == [self window])
3462         [self addMouseMovedObserver];
3463 }
3464
3465 - (void)windowDidResignKey:(NSNotification *)notification
3466 {
3467     if (!pthread_main_np()) {
3468         [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
3469         return;
3470     }
3471
3472     NSWindow *formerKeyWindow = [notification object];
3473
3474     if (formerKeyWindow == [self window])
3475         [self removeMouseMovedObserver];
3476
3477     if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet])
3478         [_private->completionController endRevertingChange:NO moveLeft:NO];
3479 }
3480
3481 - (void)windowWillClose:(NSNotification *)notification
3482 {
3483     if (!pthread_main_np()) {
3484         [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
3485         return;
3486     }
3487
3488     [_private->completionController endRevertingChange:NO moveLeft:NO];
3489     [[self _pluginController] destroyAllPlugins];
3490 }
3491
3492 - (void)scrollWheel:(NSEvent *)event
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     Frame* frame = core([self _frame]);
3500     if (!frame || !frame->eventHandler()->wheelEvent(event))
3501         [super scrollWheel:event];
3502 }
3503
3504 - (BOOL)_isSelectionEvent:(NSEvent *)event
3505 {
3506     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
3507     return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsSelectedKey] boolValue];
3508 }
3509
3510 - (BOOL)_isScrollBarEvent:(NSEvent *)event
3511 {
3512     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
3513     return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsInScrollBarKey] boolValue];
3514 }
3515
3516 - (BOOL)acceptsFirstMouse:(NSEvent *)event
3517 {
3518     // There's a chance that responding to this event will run a nested event loop, and
3519     // fetching a new event might release the old one. Retaining and then autoreleasing
3520     // the current event prevents that from causing a problem inside WebKit or AppKit code.
3521     [[event retain] autorelease];
3522
3523     NSView *hitView = [self _hitViewForEvent:event];
3524     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
3525     
3526 #if ENABLE(DASHBOARD_SUPPORT)
3527     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysAcceptsFirstMouse])
3528         return YES;
3529 #endif
3530     
3531     if (hitHTMLView) {
3532         bool result = false;