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