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