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