JavaScriptCore:
[WebKit-https.git] / WebKit / WebView / WebHTMLView.m
1 /*
2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import <WebKit/WebHTMLView.h>
30
31 #import <ApplicationServices/ApplicationServices.h>
32 #import <WebKit/DOM.h>
33 #import <WebKit/DOMExtensions.h>
34 #import <WebKit/DOMPrivate.h>
35 #import <WebKit/WebArchive.h>
36 #import <WebKit/WebArchiver.h>
37 #import <WebKit/WebBaseNetscapePluginViewInternal.h>
38 #import <WebKit/WebFrameBridge.h>
39 #import <WebKit/WebClipView.h>
40 #import <WebKit/WebDataProtocol.h>
41 #import <WebKit/WebDataSourceInternal.h>
42 #import <WebKit/WebDefaultUIDelegate.h>
43 #import <WebKit/WebDocumentInternal.h>
44 #import <WebKit/WebDOMOperationsPrivate.h>
45 #import <WebKit/WebEditingDelegate.h>
46 #import <WebKit/WebElementDictionary.h>
47 #import <WebKit/WebFramePrivate.h>
48 #import <WebKit/WebFrameInternal.h>
49 #import <WebKit/WebFrameViewInternal.h>
50 #import <WebKit/WebHTMLViewInternal.h>
51 #import <WebKit/WebHTMLRepresentationPrivate.h>
52 #import <WebKit/WebKitLogging.h>
53 #import <WebKit/WebKitNSStringExtras.h>
54 #import <WebKit/WebNetscapePluginEmbeddedView.h>
55 #import <WebKit/WebNSAttributedStringExtras.h>
56 #import <WebKit/WebNSEventExtras.h>
57 #import <WebKit/WebNSFileManagerExtras.h>
58 #import <WebKit/WebNSImageExtras.h>
59 #import <WebKit/WebNSObjectExtras.h>
60 #import <WebKit/WebNSPasteboardExtras.h>
61 #import <WebKit/WebNSPrintOperationExtras.h>
62 #import <WebKit/WebNSURLExtras.h>
63 #import <WebKit/WebNSViewExtras.h>
64 #import <WebKit/WebPluginController.h>
65 #import <WebKit/WebPreferences.h>
66 #import <WebKit/WebPreferencesPrivate.h>
67 #import <WebKit/WebResourcePrivate.h>
68 #import <WebKit/WebStringTruncator.h>
69 #import <WebKit/WebUIDelegatePrivate.h>
70 #import <WebKit/WebViewInternal.h>
71 #import <WebKitSystemInterface.h>
72 #import <WebCore/WebCoreTextRenderer.h>
73
74 #import <AppKit/NSAccessibility.h>
75
76 // Included so usage of _NSSoftLinkingGetFrameworkFuncPtr will compile
77 #import <mach-o/dyld.h> 
78
79
80 // need to declare this because AppKit does not make it available as API or SPI
81 extern NSString *NSMarkedClauseSegmentAttributeName; 
82 extern NSString *NSTextInputReplacementRangeAttributeName; 
83
84 // Kill ring calls. Would be better to use NSKillRing.h, but that's not available in SPI.
85 void _NSInitializeKillRing(void);
86 void _NSAppendToKillRing(NSString *);
87 void _NSPrependToKillRing(NSString *);
88 NSString *_NSYankFromKillRing(void);
89 NSString *_NSYankPreviousFromKillRing(void);
90 void _NSNewKillRingSequence(void);
91 void _NSSetKillRingToYankedState(void);
92 void _NSResetKillRingOperationFlag(void);
93
94 @interface NSView (AppKitSecretsIKnowAbout)
95 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView;
96 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect;
97 - (NSRect)_dirtyRect;
98 - (void)_setDrawsOwnDescendants:(BOOL)drawsOwnDescendants;
99 - (void)_propagateDirtyRectsToOpaqueAncestors;
100 @end
101
102 @interface NSApplication (AppKitSecretsIKnowAbout)
103 - (void)speakString:(NSString *)string;
104 @end
105
106 @interface NSWindow (AppKitSecretsIKnowAbout)
107 - (id)_newFirstResponderAfterResigning;
108 @end
109
110 @interface NSAttributedString (AppKitSecretsIKnowAbout)
111 - (id)_initWithDOMRange:(DOMRange *)domRange;
112 - (DOMDocumentFragment *)_documentFromRange:(NSRange)range document:(DOMDocument *)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources;
113 @end
114
115 @interface NSSpellChecker (CurrentlyPrivateForTextView)
116 - (void)learnWord:(NSString *)word;
117 @end
118
119 // By imaging to a width a little wider than the available pixels,
120 // thin pages will be scaled down a little, matching the way they
121 // print in IE and Camino. This lets them use fewer sheets than they
122 // would otherwise, which is presumably why other browsers do this.
123 // Wide pages will be scaled down more than this.
124 #define PrintingMinimumShrinkFactor     1.25f
125
126 // This number determines how small we are willing to reduce the page content
127 // in order to accommodate the widest line. If the page would have to be
128 // reduced smaller to make the widest line fit, we just clip instead (this
129 // behavior matches MacIE and Mozilla, at least)
130 #define PrintingMaximumShrinkFactor     2.0f
131
132 #define AUTOSCROLL_INTERVAL             0.1f
133
134 #define DRAG_LABEL_BORDER_X             4.0f
135 #define DRAG_LABEL_BORDER_Y             2.0f
136 #define DRAG_LABEL_RADIUS               5.0f
137 #define DRAG_LABEL_BORDER_Y_OFFSET              2.0f
138
139 #define MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP        120.0f
140 #define MAX_DRAG_LABEL_WIDTH                    320.0f
141
142 #define DRAG_LINK_LABEL_FONT_SIZE   11.0f
143 #define DRAG_LINK_URL_FONT_SIZE   10.0f
144
145 // Any non-zero value will do, but using something recognizable might help us debug some day.
146 #define TRACKING_RECT_TAG 0xBADFACE
147
148 // FIXME: This constant is copied from AppKit's _NXSmartPaste constant.
149 #define WebSmartPastePboardType @"NeXT smart paste pasteboard type"
150
151 #define STANDARD_WEIGHT 5
152 #define MIN_BOLD_WEIGHT 9
153 #define STANDARD_BOLD_WEIGHT 10
154
155 typedef enum {
156     deleteSelectionAction,
157     deleteKeyAction,
158     forwardDeleteKeyAction
159 } WebDeletionAction;
160
161 // if YES, do the standard NSView hit test (which can't give the right result when HTML overlaps a view)
162 static BOOL forceNSViewHitTest = NO;
163
164 // if YES, do the "top WebHTMLView" it test (which we'd like to do all the time but can't because of Java requirements [see bug 4349721])
165 static BOOL forceWebHTMLViewHitTest = NO;
166
167 // Used to avoid linking with ApplicationServices framework for _DCMDictionaryServiceWindowShow
168 void *_NSSoftLinkingGetFrameworkFuncPtr(NSString *inUmbrellaFrameworkName,
169                                         NSString *inFrameworkName,
170                                         const char *inFuncName,
171                                         const struct mach_header **ioCachedFrameworkImageHeaderPtr);
172
173
174 @interface WebHTMLView (WebTextSizing) <_WebDocumentTextSizing>
175 @end
176
177 @interface WebHTMLView (WebHTMLViewFileInternal)
178 - (BOOL)_imageExistsAtPaths:(NSArray *)paths;
179 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard inContext:(DOMRange *)context allowPlainText:(BOOL)allowPlainText chosePlainText:(BOOL *)chosePlainText;
180 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard;
181 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText;
182 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard;
183 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
184 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
185 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action;
186 - (float)_calculatePrintHeight;
187 - (void)_updateTextSizeMultiplier;
188 - (DOMRange *)_selectedRange;
189 - (BOOL)_shouldDeleteRange:(DOMRange *)range;
190 - (void)_deleteRange:(DOMRange *)range 
191             killRing:(BOOL)killRing 
192              prepend:(BOOL)prepend 
193        smartDeleteOK:(BOOL)smartDeleteOK
194       deletionAction:(WebDeletionAction)deletionAction
195          granularity:(WebBridgeSelectionGranularity)granularity;
196 - (void)_deleteSelection;
197 - (BOOL)_canSmartReplaceWithPasteboard:(NSPasteboard *)pasteboard;
198 - (NSView *)_hitViewForEvent:(NSEvent *)event;
199 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString;
200 - (DOMRange *)_documentRange;
201 - (WebFrameBridge *)_bridge;
202 - (void)_setMouseDownEvent:(NSEvent *)event;
203 @end
204
205 @interface WebHTMLView (WebForwardDeclaration) // FIXME: Put this in a normal category and stop doing the forward declaration trick.
206 - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize;
207 @end
208
209 @interface WebHTMLView (WebNSTextInputSupport) <NSTextInput>
210 - (void)_updateSelectionForInputManager;
211 - (void)_insertText:(NSString *)text selectInsertedText:(BOOL)selectText;
212 @end
213
214 @interface WebHTMLView (WebEditingStyleSupport)
215 - (DOMCSSStyleDeclaration *)_emptyStyle;
216 - (NSString *)_colorAsString:(NSColor *)color;
217 @end
218
219 @interface NSView (WebHTMLViewFileInternal)
220 - (void)_web_setPrintingModeRecursive;
221 - (void)_web_clearPrintingModeRecursive;
222 - (void)_web_layoutIfNeededRecursive;
223 - (void)_web_layoutIfNeededRecursive:(NSRect)rect testDirtyRect:(bool)testDirtyRect;
224 @end
225
226 @interface NSMutableDictionary (WebHTMLViewFileInternal)
227 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key;
228 @end
229
230 // Handles the complete: text command
231 @interface WebTextCompleteController : NSObject
232 {
233 @private
234     WebHTMLView *_view;
235     NSWindow *_popupWindow;
236     NSTableView *_tableView;
237     NSArray *_completions;
238     NSString *_originalString;
239     int prefixLength;
240 }
241 - (id)initWithHTMLView:(WebHTMLView *)view;
242 - (void)doCompletion;
243 - (void)endRevertingChange:(BOOL)revertChange moveLeft:(BOOL)goLeft;
244 - (BOOL)filterKeyDown:(NSEvent *)event;
245 - (void)_reflectSelection;
246 @end
247
248 @implementation WebHTMLViewPrivate
249
250 - (void)dealloc
251 {
252     ASSERT(autoscrollTimer == nil);
253     ASSERT(autoscrollTriggerEvent == nil);
254     
255     [mouseDownEvent release];
256     [draggingImageURL release];
257     [pluginController release];
258     [toolTip release];
259     [compController release];
260     [firstResponderTextViewAtMouseDownTime release];
261     [dataSource release];
262     [highlighters release];
263
264     [super dealloc];
265 }
266
267 @end
268
269 @implementation WebHTMLView (WebHTMLViewFileInternal)
270
271 - (DOMRange *)_documentRange
272 {
273     return [[[self _bridge] DOMDocument] _documentRange];
274 }
275
276 - (BOOL)_imageExistsAtPaths:(NSArray *)paths
277 {
278     NSArray *imageMIMETypes = [WebFrameBridge supportedImageResourceMIMETypes];
279     NSEnumerator *enumerator = [paths objectEnumerator];
280     NSString *path;
281     
282     while ((path = [enumerator nextObject]) != nil) {
283         NSString *MIMEType = WKGetMIMETypeForExtension([path pathExtension]);
284         if ([imageMIMETypes containsObject:MIMEType]) {
285             return YES;
286         }
287     }
288     
289     return NO;
290 }
291
292 - (WebDataSource *)_dataSource
293 {
294     return _private->dataSource;
295 }
296
297 - (WebFrameBridge *)_bridge
298 {
299     return [_private->dataSource _bridge];
300 }
301
302 - (WebView *)_webView
303 {
304     return [_private->dataSource _webView];
305 }
306
307 - (WebFrameView *)_frameView
308 {
309     return [[_private->dataSource webFrame] frameView];
310 }
311
312 - (DOMDocumentFragment *)_documentFragmentWithPaths:(NSArray *)paths
313 {
314     DOMDocumentFragment *fragment;
315     NSArray *imageMIMETypes = [WebFrameBridge supportedImageResourceMIMETypes];
316     NSEnumerator *enumerator = [paths objectEnumerator];
317     WebDataSource *dataSource = [self _dataSource];
318     NSMutableArray *domNodes = [[NSMutableArray alloc] init];
319     NSString *path;
320     
321     while ((path = [enumerator nextObject]) != nil) {
322         NSString *MIMEType = WKGetMIMETypeForExtension([path pathExtension]);
323         if ([imageMIMETypes containsObject:MIMEType]) {
324             WebResource *resource = [[WebResource alloc] initWithData:[NSData dataWithContentsOfFile:path]
325                                                                   URL:[NSURL fileURLWithPath:path]
326                                                              MIMEType:MIMEType 
327                                                      textEncodingName:nil
328                                                             frameName:nil];
329             if (resource) {
330                 [domNodes addObject:[dataSource _imageElementWithImageResource:resource]];
331                 [resource release];
332             }
333         } else {
334             // Non-image file types
335             NSString *url = [[[NSURL fileURLWithPath:path] _webkit_canonicalize] _web_userVisibleString];
336             [domNodes addObject:[[[self _bridge] DOMDocument] createTextNode: url]];
337         }
338     }
339     
340     fragment = [[self _bridge] documentFragmentWithNodesAsParagraphs:domNodes]; 
341     
342     [domNodes release];
343     
344     return [fragment firstChild] != nil ? fragment : nil;
345 }
346
347 + (NSArray *)_excludedElementsForAttributedStringConversion
348 {
349     static NSArray *elements = nil;
350     if (elements == nil) {
351         elements = [[NSArray alloc] initWithObjects:
352             // Omit style since we want style to be inline so the fragment can be easily inserted.
353             @"style",
354             // Omit xml so the result is not XHTML.
355             @"xml", 
356             // Omit tags that will get stripped when converted to a fragment anyway.
357             @"doctype", @"html", @"head", @"body",
358             // Omit deprecated tags.
359             @"applet", @"basefont", @"center", @"dir", @"font", @"isindex", @"menu", @"s", @"strike", @"u",
360             // Omit object so no file attachments are part of the fragment.
361             @"object", nil];
362     }
363     return elements;
364 }
365
366 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
367                                                inContext:(DOMRange *)context
368                                           allowPlainText:(BOOL)allowPlainText
369                                           chosePlainText:(BOOL *)chosePlainText
370 {
371     NSArray *types = [pasteboard types];
372     *chosePlainText = NO;
373
374     if ([types containsObject:WebArchivePboardType]) {
375         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
376         if (archive) {
377             DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithArchive:archive];
378             [archive release];
379             if (fragment) {
380                 return fragment;
381             }
382         }
383     }
384     
385     if ([types containsObject:NSFilenamesPboardType]) {
386         DOMDocumentFragment *fragment = [self _documentFragmentWithPaths:[pasteboard propertyListForType:NSFilenamesPboardType]];
387         if (fragment != nil) {
388             return fragment;
389         }
390     }
391     
392     NSURL *URL;
393     
394     if ([types containsObject:NSHTMLPboardType]) {
395         NSString *HTMLString = [pasteboard stringForType:NSHTMLPboardType];
396         // This is a hack to make Microsoft's HTML pasteboard data work. See 3778785.
397         if ([HTMLString hasPrefix:@"Version:"]) {
398             NSRange range = [HTMLString rangeOfString:@"<html" options:NSCaseInsensitiveSearch];
399             if (range.location != NSNotFound) {
400                 HTMLString = [HTMLString substringFromIndex:range.location];
401             }
402         }
403         if ([HTMLString length] != 0) {
404             return [[self _bridge] documentFragmentWithMarkupString:HTMLString baseURLString:nil];
405         }
406     }
407         
408     NSAttributedString *string = nil;
409     if ([types containsObject:NSRTFDPboardType]) {
410         string = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
411     }
412     if (string == nil && [types containsObject:NSRTFPboardType]) {
413         string = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
414     }
415     if (string != nil) {
416         NSDictionary *documentAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
417             [[self class] _excludedElementsForAttributedStringConversion], NSExcludedElementsDocumentAttribute,
418             self, @"WebResourceHandler", nil];
419         NSArray *subresources;
420         DOMDocumentFragment *fragment = [string _documentFromRange:NSMakeRange(0, [string length]) 
421                                                           document:[[self _bridge] DOMDocument] 
422                                                 documentAttributes:documentAttributes
423                                                       subresources:&subresources];
424         [documentAttributes release];
425         [string release];
426         return fragment;
427     }
428     
429     if ([types containsObject:NSTIFFPboardType]) {
430         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSTIFFPboardType]
431                                                               URL:[NSURL _web_uniqueWebDataURLWithRelativeString:@"/image.tiff"]
432                                                          MIMEType:@"image/tiff" 
433                                                  textEncodingName:nil
434                                                         frameName:nil];
435         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
436         [resource release];
437         return fragment;
438     }
439     
440     if ([types containsObject:NSPICTPboardType]) {
441         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPICTPboardType]
442                                                               URL:[NSURL _web_uniqueWebDataURLWithRelativeString:@"/image.pict"]
443                                                          MIMEType:@"image/pict" 
444                                                  textEncodingName:nil
445                                                         frameName:nil];
446         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
447         [resource release];
448         return fragment;
449     }    
450     
451     if ((URL = [NSURL URLFromPasteboard:pasteboard])) {
452         DOMDocument* document = [[self _bridge] DOMDocument];
453         ASSERT(document);
454         if (document) {
455             DOMHTMLAnchorElement* anchor = (DOMHTMLAnchorElement*)[document createElement:@"a"];
456             NSString *URLString = [URL _web_userVisibleString];
457             NSString *URLTitleString = [pasteboard stringForType:WebURLNamePboardType];
458             DOMText* text = [document createTextNode:URLTitleString];
459             [anchor setHref:URLString];
460             [anchor appendChild:text];
461             DOMDocumentFragment* fragment = [document createDocumentFragment];
462             [fragment appendChild:anchor];
463             if ([URLString length] > 0)
464                 return fragment;
465         }
466     }
467     
468     if (allowPlainText && [types containsObject:NSStringPboardType]) {
469         *chosePlainText = YES;
470         return [[self _bridge] documentFragmentWithText:[pasteboard stringForType:NSStringPboardType]
471                                               inContext:context];
472     }
473     
474     return nil;
475 }
476
477 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard
478 {
479     NSArray *types = [pasteboard types];
480     
481     if ([types containsObject:NSStringPboardType])
482         return [pasteboard stringForType:NSStringPboardType];
483     
484     NSAttributedString *attributedString = nil;
485     NSString *string;
486
487     if ([types containsObject:NSRTFDPboardType])
488         attributedString = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
489     if (attributedString == nil && [types containsObject:NSRTFPboardType])
490         attributedString = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
491     if (attributedString != nil) {
492         string = [[attributedString string] copy];
493         [attributedString release];
494         return [string autorelease];
495     }
496     
497     if ([types containsObject:NSFilenamesPboardType]) {
498         string = [[pasteboard propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"];
499         if (string != nil)
500             return string;
501     }
502     
503     NSURL *URL;
504     
505     if ((URL = [NSURL URLFromPasteboard:pasteboard])) {
506         string = [URL _web_userVisibleString];
507         if ([string length] > 0)
508             return string;
509     }
510     
511     return nil;
512 }
513
514 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText
515 {
516     DOMRange *range = [self _selectedRange];
517     BOOL chosePlainText;
518     DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard
519         inContext:range allowPlainText:allowPlainText chosePlainText:&chosePlainText];
520     WebFrameBridge *bridge = [self _bridge];
521     if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:[self _selectedRange] givenAction:WebViewInsertActionPasted]) {
522         [bridge replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:chosePlainText];
523     }
524 }
525
526 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard
527 {
528     NSString *text = [self _plainTextFromPasteboard:pasteboard];
529     if ([self _shouldReplaceSelectionWithText:text givenAction:WebViewInsertActionPasted])
530         [[self _bridge] replaceSelectionWithText:text selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard]];
531 }
532
533 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
534 {
535     WebView *webView = [self _webView];
536     DOMNode *child = [fragment firstChild];
537     if ([fragment lastChild] == child && [child isKindOfClass:[DOMCharacterData class]])
538         return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:[(DOMCharacterData *)child data] replacingDOMRange:range givenAction:action];
539     return [[webView _editingDelegateForwarder] webView:webView shouldInsertNode:fragment replacingDOMRange:range givenAction:action];
540 }
541
542 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
543 {
544     WebView *webView = [self _webView];
545     return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:range givenAction:action];
546 }
547
548 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action
549 {
550     return [self _shouldInsertText:text replacingDOMRange:[self _selectedRange] givenAction:action];
551 }
552
553 // Calculate the vertical size of the view that fits on a single page
554 - (float)_calculatePrintHeight
555 {
556     // Obtain the print info object for the current operation
557     NSPrintInfo *pi = [[NSPrintOperation currentOperation] printInfo];
558     
559     // Calculate the page height in points
560     NSSize paperSize = [pi paperSize];
561     return paperSize.height - [pi topMargin] - [pi bottomMargin];
562 }
563
564 - (void)_updateTextSizeMultiplier
565 {
566     [[self _bridge] setTextSizeMultiplier:[[self _webView] textSizeMultiplier]];    
567 }
568
569 - (DOMRange *)_selectedRange
570 {
571     return [[self _bridge] selectedDOMRange];
572 }
573
574 - (BOOL)_shouldDeleteRange:(DOMRange *)range
575 {
576     if (range == nil || [range collapsed])
577         return NO;
578     
579     if (![[self _bridge] canDeleteRange:range])
580         return NO;
581         
582     WebView *webView = [self _webView];
583     return [[webView _editingDelegateForwarder] webView:webView shouldDeleteDOMRange:range];
584 }
585
586 - (void)_deleteRange:(DOMRange *)range 
587             killRing:(BOOL)killRing 
588              prepend:(BOOL)prepend 
589        smartDeleteOK:(BOOL)smartDeleteOK 
590       deletionAction:(WebDeletionAction)deletionAction
591          granularity:(WebBridgeSelectionGranularity)granularity
592 {
593     WebFrameBridge *bridge = [self _bridge];
594     BOOL smartDelete = smartDeleteOK ? [self _canSmartCopyOrDelete] : NO;
595
596     BOOL startNewKillRingSequence = _private->startNewKillRingSequence;
597
598     if (killRing) {
599         if (startNewKillRingSequence) {
600             _NSNewKillRingSequence();
601         }
602         NSString *string = [bridge stringForRange:range];
603         if (prepend) {
604             _NSPrependToKillRing(string);
605         } else {
606             _NSAppendToKillRing(string);
607         }
608         startNewKillRingSequence = NO;
609     }
610
611     switch (deletionAction) {
612         case deleteSelectionAction:
613             [bridge setSelectedDOMRange:range affinity:NSSelectionAffinityDownstream closeTyping:YES];
614             [bridge deleteSelectionWithSmartDelete:smartDelete];
615             break;
616         case deleteKeyAction:
617             [bridge setSelectedDOMRange:range affinity:NSSelectionAffinityDownstream closeTyping:(granularity != WebBridgeSelectByCharacter)];
618             [bridge deleteKeyPressedWithSmartDelete:smartDelete granularity:granularity];
619             break;
620         case forwardDeleteKeyAction:
621             [bridge setSelectedDOMRange:range affinity:NSSelectionAffinityDownstream closeTyping:(granularity != WebBridgeSelectByCharacter)];
622             [bridge forwardDeleteKeyPressedWithSmartDelete:smartDelete granularity:granularity];
623             break;
624     }
625
626     _private->startNewKillRingSequence = startNewKillRingSequence;
627 }
628
629 - (void)_deleteSelection
630 {
631     [self _deleteRange:[self _selectedRange]
632               killRing:YES 
633                prepend:NO
634          smartDeleteOK:YES
635         deletionAction:deleteSelectionAction
636            granularity:WebBridgeSelectByCharacter];
637 }
638
639 - (BOOL)_canSmartReplaceWithPasteboard:(NSPasteboard *)pasteboard
640 {
641     return [[self _webView] smartInsertDeleteEnabled] && [[pasteboard types] containsObject:WebSmartPastePboardType];
642 }
643
644 - (NSView *)_hitViewForEvent:(NSEvent *)event
645 {
646     // Usually, we hack AK's hitTest method to catch all events at the topmost WebHTMLView.  
647     // Callers of this method, however, want to query the deepest view instead.
648     forceNSViewHitTest = YES;
649     NSView *hitView = [[[self window] contentView] hitTest:[event locationInWindow]];
650     forceNSViewHitTest = NO;    
651     return hitView;
652 }
653
654 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString
655 {
656     // Put HTML on the pasteboard.
657     if ([types containsObject:WebArchivePboardType]) {
658         WebArchive *archive = [WebArchiver archiveSelectionInFrame:[self _frame]];
659         [pasteboard setData:[archive data] forType:WebArchivePboardType];
660     }
661     
662     // Put the attributed string on the pasteboard (RTF/RTFD format).
663     if ([types containsObject:NSRTFDPboardType]) {
664         if (attributedString == nil) {
665             attributedString = [self selectedAttributedString];
666         }        
667         NSData *RTFDData = [attributedString RTFDFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
668         [pasteboard setData:RTFDData forType:NSRTFDPboardType];
669     }        
670     if ([types containsObject:NSRTFPboardType]) {
671         if (attributedString == nil) {
672             attributedString = [self selectedAttributedString];
673         }
674         if ([attributedString containsAttachments]) {
675             attributedString = [attributedString _web_attributedStringByStrippingAttachmentCharacters];
676         }
677         NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
678         [pasteboard setData:RTFData forType:NSRTFPboardType];
679     }
680     
681     // Put plain string on the pasteboard.
682     if ([types containsObject:NSStringPboardType]) {
683         // Map &nbsp; to a plain old space because this is better for source code, other browsers do it,
684         // and because HTML forces you to do this any time you want two spaces in a row.
685         NSMutableString *s = [[self selectedString] mutableCopy];
686         const unichar NonBreakingSpaceCharacter = 0xA0;
687         NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&NonBreakingSpaceCharacter length:1];
688         [s replaceOccurrencesOfString:NonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
689         [pasteboard setString:s forType:NSStringPboardType];
690         [s release];
691     }
692     
693     if ([self _canSmartCopyOrDelete] && [types containsObject:WebSmartPastePboardType]) {
694         [pasteboard setData:nil forType:WebSmartPastePboardType];
695     }
696 }
697
698 - (void)_setMouseDownEvent:(NSEvent *)event
699 {
700     ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
701
702     if (event == _private->mouseDownEvent)
703         return;
704
705     [event retain];
706     [_private->mouseDownEvent release];
707     _private->mouseDownEvent = event;
708
709     [_private->firstResponderTextViewAtMouseDownTime release];
710     
711     // The only code that checks this ivar only cares about NSTextViews. The code used to be more general,
712     // but it caused reference cycles leading to world leaks (see 4557386). We should be able to eliminate
713     // firstResponderTextViewAtMouseDownTime entirely when all the form controls are native widgets, because 
714     // the only caller (in WebCore) will be unnecessary.
715     if (event) {
716         NSResponder *firstResponder = [[self window] firstResponder];
717         if ([firstResponder isKindOfClass:[NSTextView class]])
718             _private->firstResponderTextViewAtMouseDownTime = [firstResponder retain];
719         else
720             _private->firstResponderTextViewAtMouseDownTime = nil;
721     } else
722         _private->firstResponderTextViewAtMouseDownTime = nil;
723 }
724
725 @end
726
727 @implementation WebHTMLView (WebPrivate)
728
729 + (NSArray *)supportedMIMETypes
730 {
731     return [WebHTMLRepresentation supportedMIMETypes];
732 }
733
734 + (NSArray *)supportedImageMIMETypes
735 {
736     return [WebHTMLRepresentation supportedImageMIMETypes];
737 }
738
739 + (NSArray *)supportedNonImageMIMETypes
740 {
741     return [WebHTMLRepresentation supportedNonImageMIMETypes];
742 }
743
744 + (NSArray *)unsupportedTextMIMETypes
745 {
746     return [NSArray arrayWithObjects:
747         @"text/calendar",       // iCal
748         @"text/x-calendar",
749         @"text/x-vcalendar",
750         @"text/vcalendar",
751         @"text/vcard",          // vCard
752         @"text/x-vcard",
753         @"text/directory",
754         @"text/ldif",           // Netscape Address Book
755         @"text/qif",            // Quicken
756         @"text/x-qif",
757         @"text/x-csv",          // CSV (for Address Book and Microsoft Outlook)
758         @"text/x-vcf",          // vCard type used in Sun affinity app
759         @"text/rtf",            // Rich Text Format
760         nil];
761 }
762
763 + (void)_postFlagsChangedEvent:(NSEvent *)flagsChangedEvent
764 {
765     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
766         location:[[flagsChangedEvent window] convertScreenToBase:[NSEvent mouseLocation]]
767         modifierFlags:[flagsChangedEvent modifierFlags]
768         timestamp:[flagsChangedEvent timestamp]
769         windowNumber:[flagsChangedEvent windowNumber]
770         context:[flagsChangedEvent context]
771         eventNumber:0 clickCount:0 pressure:0];
772
773     // Pretend it's a mouse move.
774     [[NSNotificationCenter defaultCenter]
775         postNotificationName:WKMouseMovedNotification() object:self
776         userInfo:[NSDictionary dictionaryWithObject:fakeEvent forKey:@"NSEvent"]];
777 }
778
779 - (void)_updateMouseoverWithFakeEvent
780 {
781     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
782         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
783         modifierFlags:[[NSApp currentEvent] modifierFlags]
784         timestamp:[NSDate timeIntervalSinceReferenceDate]
785         windowNumber:[[self window] windowNumber]
786         context:[[NSApp currentEvent] context]
787         eventNumber:0 clickCount:0 pressure:0];
788     
789     [self _updateMouseoverWithEvent:fakeEvent];
790 }
791
792 - (void)_frameOrBoundsChanged
793 {
794     if (!NSEqualSizes(_private->lastLayoutSize, [(NSClipView *)[self superview] documentVisibleRect].size)) {
795         [self setNeedsLayout:YES];
796         [self setNeedsDisplay:YES];
797         [_private->compController endRevertingChange:NO moveLeft:NO];
798     }
799
800     NSPoint origin = [[self superview] bounds].origin;
801     if (!NSEqualPoints(_private->lastScrollPosition, origin)) {
802         [[self _bridge] sendScrollEvent];
803         [_private->compController endRevertingChange:NO moveLeft:NO];
804         
805         WebView *webView = [self _webView];
806         [[webView _UIDelegateForwarder] webView:webView didScrollDocumentInFrameView:[self _frameView]];
807     }
808     _private->lastScrollPosition = origin;
809
810     SEL selector = @selector(_updateMouseoverWithFakeEvent);
811     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:selector object:nil];
812     [self performSelector:selector withObject:nil afterDelay:0];
813 }
814
815 - (void)_setAsideSubviews
816 {
817     ASSERT(!_private->subviewsSetAside);
818     ASSERT(_private->savedSubviews == nil);
819     _private->savedSubviews = _subviews;
820     _subviews = nil;
821     _private->subviewsSetAside = YES;
822  }
823  
824  - (void)_restoreSubviews
825  {
826     ASSERT(_private->subviewsSetAside);
827     ASSERT(_subviews == nil);
828     _subviews = _private->savedSubviews;
829     _private->savedSubviews = nil;
830     _private->subviewsSetAside = NO;
831 }
832
833 // This is called when we are about to draw, but before our dirty rect is propagated to our ancestors.
834 // That's the perfect time to do a layout, except that ideally we'd want to be sure that we're dirty
835 // before doing it. As a compromise, when we're opaque we do the layout only when actually asked to
836 // draw, but when we're transparent we do the layout at this stage so views behind us know that they
837 // need to be redrawn (in case the layout causes some things to get dirtied).
838 - (void)_propagateDirtyRectsToOpaqueAncestors
839 {
840     if (![[self _webView] drawsBackground]) {
841         [self _web_layoutIfNeededRecursive];
842     }
843     [super _propagateDirtyRectsToOpaqueAncestors];
844 }
845
846 // Don't let AppKit even draw subviews. We take care of that.
847 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView
848 {
849     // This helps when we print as part of a larger print process.
850     // If the WebHTMLView itself is what we're printing, then we will never have to do this.
851     BOOL wasInPrintingMode = _private->printing;
852     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
853     if (wasInPrintingMode != isPrinting) {
854         if (isPrinting) {
855             [self _web_setPrintingModeRecursive];
856         } else {
857             [self _web_clearPrintingModeRecursive];
858         }
859     }
860
861     [self _web_layoutIfNeededRecursive: rect testDirtyRect:YES];
862     [_subviews makeObjectsPerformSelector:@selector(_propagateDirtyRectsToOpaqueAncestors)];
863
864     [self _setAsideSubviews];
865     [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect isVisibleRect:isVisibleRect
866         rectIsVisibleRectForView:visibleView topView:topView];
867     [self _restoreSubviews];
868
869     if (wasInPrintingMode != isPrinting) {
870         if (wasInPrintingMode) {
871             [self _web_setPrintingModeRecursive];
872         } else {
873             [self _web_clearPrintingModeRecursive];
874         }
875     }
876 }
877
878 // Don't let AppKit even draw subviews. We take care of that.
879 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect
880 {
881     BOOL needToSetAsideSubviews = !_private->subviewsSetAside;
882
883     BOOL wasInPrintingMode = _private->printing;
884     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
885
886     if (needToSetAsideSubviews) {
887         // This helps when we print as part of a larger print process.
888         // If the WebHTMLView itself is what we're printing, then we will never have to do this.
889         if (wasInPrintingMode != isPrinting) {
890             if (isPrinting) {
891                 [self _web_setPrintingModeRecursive];
892             } else {
893                 [self _web_clearPrintingModeRecursive];
894             }
895         }
896
897         NSRect boundsBeforeLayout = [self bounds];
898         [self _web_layoutIfNeededRecursive: visRect testDirtyRect:NO];
899
900         // If layout changes the view's bounds, then we need to recompute the visRect.
901         // That's because the visRect passed to us was based on the bounds at the time
902         // we were called. This method is only displayed to draw "all", so it's safe
903         // to just call visibleRect to compute the entire rectangle.
904         if (!NSEqualRects(boundsBeforeLayout, [self bounds])) {
905             visRect = [self visibleRect];
906         }
907
908         [self _setAsideSubviews];
909     }
910     
911     [super _recursiveDisplayAllDirtyWithLockFocus:needsLockFocus visRect:visRect];
912     
913     if (needToSetAsideSubviews) {
914         if (wasInPrintingMode != isPrinting) {
915             if (wasInPrintingMode) {
916                 [self _web_setPrintingModeRecursive];
917             } else {
918                 [self _web_clearPrintingModeRecursive];
919             }
920         }
921
922         [self _restoreSubviews];
923     }
924 }
925
926 - (WebHTMLView *)_topHTMLView
927 {
928     WebHTMLView *view = (WebHTMLView *)[[[[_private->dataSource _webView] mainFrame] frameView] documentView];
929     ASSERT([view isKindOfClass:[WebHTMLView class]]);
930     return view;
931 }
932
933 - (BOOL)_isTopHTMLView
934 {
935     return self == [self _topHTMLView];
936 }
937
938 - (BOOL)_insideAnotherHTMLView
939 {
940     return self != [self _topHTMLView];
941 }
942
943 - (void)scrollPoint:(NSPoint)point
944 {
945     // Since we can't subclass NSTextView to do what we want, we have to second guess it here.
946     // If we get called during the handling of a key down event, we assume the call came from
947     // NSTextView, and ignore it and use our own code to decide how to page up and page down
948     // We are smarter about how far to scroll, and we have "superview scrolling" logic.
949     NSEvent *event = [[self window] currentEvent];
950     if ([event type] == NSKeyDown) {
951         const unichar pageUp = NSPageUpFunctionKey;
952         if ([[event characters] rangeOfString:[NSString stringWithCharacters:&pageUp length:1]].length == 1) {
953             [self tryToPerform:@selector(scrollPageUp:) with:nil];
954             return;
955         }
956         const unichar pageDown = NSPageDownFunctionKey;
957         if ([[event characters] rangeOfString:[NSString stringWithCharacters:&pageDown length:1]].length == 1) {
958             [self tryToPerform:@selector(scrollPageDown:) with:nil];
959             return;
960         }
961     }
962     
963     [super scrollPoint:point];
964 }
965
966 - (NSView *)hitTest:(NSPoint)point
967 {
968     // WebHTMLView objects handle all events for objects inside them.
969     // To get those events, we prevent hit testing from AppKit.
970
971     // But there are three exceptions to this:
972     //   1) For right mouse clicks and control clicks we don't yet have an implementation
973     //      that works for nested views, so we let the hit testing go through the
974     //      standard NSView code path (needs to be fixed, see bug 4361618).
975     //   2) Java depends on doing a hit test inside it's mouse moved handling,
976     //      so we let the hit testing go through the standard NSView code path
977     //      when the current event is a mouse move (except when we are calling
978     //      from _updateMouseoverWithEvent, so we have to use a global,
979     //      forceWebHTMLViewHitTest, for that)
980     //   3) The acceptsFirstMouse: and shouldDelayWindowOrderingForEvent: methods
981     //      both need to figure out which view to check with inside the WebHTMLView.
982     //      They use a global to change the behavior of hitTest: so they can get the
983     //      right view. The global is forceNSViewHitTest and the method they use to
984     //      do the hit testing is _hitViewForEvent:. (But this does not work correctly
985     //      when there is HTML overlapping the view, see bug 4361626)
986     //   4) NSAccessibilityHitTest relies on this for checking the cursor position.
987     //      Our check for that is whether the event is NSFlagsChanged.  This works
988     //      for VoiceOver's cntl-opt-f5 command (move focus to item under cursor)
989     //      and Dictionary's cmd-cntl-D (open dictionary popup for item under cursor).
990     //      This is of course a hack.
991
992     BOOL captureHitsOnSubviews;
993     if (forceNSViewHitTest)
994         captureHitsOnSubviews = NO;
995     else if (forceWebHTMLViewHitTest)
996         captureHitsOnSubviews = YES;
997     else {
998         NSEvent *event = [[self window] currentEvent];
999         captureHitsOnSubviews = !([event type] == NSMouseMoved
1000             || [event type] == NSRightMouseDown
1001             || ([event type] == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask) != 0)
1002             || [event type] == NSFlagsChanged);
1003     }
1004
1005     if (!captureHitsOnSubviews)
1006         return [super hitTest:point];
1007     if ([[self superview] mouse:point inRect:[self frame]])
1008         return self;
1009     return nil;
1010 }
1011
1012 static WebHTMLView *lastHitView = nil;
1013
1014 - (void)_clearLastHitViewIfSelf
1015 {
1016     if (lastHitView == self) {
1017         lastHitView = nil;
1018     }
1019 }
1020
1021 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
1022 {
1023     ASSERT(_private->trackingRectOwner == nil);
1024     _private->trackingRectOwner = owner;
1025     _private->trackingRectUserData = data;
1026     return TRACKING_RECT_TAG;
1027 }
1028
1029 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
1030 {
1031     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
1032     ASSERT(_private->trackingRectOwner == nil);
1033     _private->trackingRectOwner = owner;
1034     _private->trackingRectUserData = data;
1035     return TRACKING_RECT_TAG;
1036 }
1037
1038 - (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count
1039 {
1040     ASSERT(count == 1);
1041     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
1042     ASSERT(_private->trackingRectOwner == nil);
1043     _private->trackingRectOwner = owner;
1044     _private->trackingRectUserData = userDataList[0];
1045     trackingNums[0] = TRACKING_RECT_TAG;
1046 }
1047
1048 - (void)removeTrackingRect:(NSTrackingRectTag)tag
1049 {
1050     if (tag == 0)
1051         return;
1052     
1053     if (_private && (tag == TRACKING_RECT_TAG)) {
1054         _private->trackingRectOwner = nil;
1055         return;
1056     }
1057     
1058     if (_private && (tag == _private->lastToolTipTag)) {
1059         [super removeTrackingRect:tag];
1060         _private->lastToolTipTag = 0;
1061         return;
1062     }
1063     
1064     // If any other tracking rect is being removed, we don't know how it was created
1065     // and it's possible there's a leak involved (see 3500217)
1066     ASSERT_NOT_REACHED();
1067 }
1068
1069 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count
1070 {
1071     int i;
1072     for (i = 0; i < count; ++i) {
1073         int tag = tags[i];
1074         if (tag == 0)
1075             continue;
1076         ASSERT(tag == TRACKING_RECT_TAG);
1077         if (_private != nil) {
1078             _private->trackingRectOwner = nil;
1079         }
1080     }
1081 }
1082
1083 - (void)_sendToolTipMouseExited
1084 {
1085     // Nothing matters except window, trackingNumber, and userData.
1086     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited
1087         location:NSMakePoint(0, 0)
1088         modifierFlags:0
1089         timestamp:0
1090         windowNumber:[[self window] windowNumber]
1091         context:NULL
1092         eventNumber:0
1093         trackingNumber:TRACKING_RECT_TAG
1094         userData:_private->trackingRectUserData];
1095     [_private->trackingRectOwner mouseExited:fakeEvent];
1096 }
1097
1098 - (void)_sendToolTipMouseEntered
1099 {
1100     // Nothing matters except window, trackingNumber, and userData.
1101     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered
1102         location:NSMakePoint(0, 0)
1103         modifierFlags:0
1104         timestamp:0
1105         windowNumber:[[self window] windowNumber]
1106         context:NULL
1107         eventNumber:0
1108         trackingNumber:TRACKING_RECT_TAG
1109         userData:_private->trackingRectUserData];
1110     [_private->trackingRectOwner mouseEntered:fakeEvent];
1111 }
1112
1113 - (void)_setToolTip:(NSString *)string
1114 {
1115     NSString *toolTip = [string length] == 0 ? nil : string;
1116     NSString *oldToolTip = _private->toolTip;
1117     if ((toolTip == nil || oldToolTip == nil) ? toolTip == oldToolTip : [toolTip isEqualToString:oldToolTip]) {
1118         return;
1119     }
1120     if (oldToolTip) {
1121         [self _sendToolTipMouseExited];
1122         [oldToolTip release];
1123     }
1124     _private->toolTip = [toolTip copy];
1125     if (toolTip) {
1126         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
1127         [self removeAllToolTips];
1128         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
1129         _private->lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL];
1130         [self _sendToolTipMouseEntered];
1131     }
1132 }
1133
1134 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
1135 {
1136     return [[_private->toolTip copy] autorelease];
1137 }
1138
1139 - (void)_updateMouseoverWithEvent:(NSEvent *)event
1140 {
1141     if (_private->closed)
1142         return;
1143
1144     NSView *contentView = [[event window] contentView];
1145     NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil];
1146     
1147     forceWebHTMLViewHitTest = YES;
1148     NSView *hitView = [contentView hitTest:locationForHitTest];
1149     forceWebHTMLViewHitTest = NO;
1150     
1151     WebHTMLView *view = nil;
1152     if ([hitView isKindOfClass:[WebHTMLView class]]) 
1153         view = (WebHTMLView *)hitView; 
1154
1155     if (view)
1156         [view retain];
1157
1158     if (lastHitView != view && lastHitView != nil) {
1159         // If we are moving out of a view (or frame), let's pretend the mouse moved
1160         // all the way out of that view. But we have to account for scrolling, because
1161         // khtml doesn't understand our clipping.
1162         NSRect visibleRect = [[[[lastHitView _frame] frameView] _scrollView] documentVisibleRect];
1163         float yScroll = visibleRect.origin.y;
1164         float xScroll = visibleRect.origin.x;
1165
1166         event = [NSEvent mouseEventWithType:NSMouseMoved
1167                          location:NSMakePoint(-1 - xScroll, -1 - yScroll )
1168                          modifierFlags:[[NSApp currentEvent] modifierFlags]
1169                          timestamp:[NSDate timeIntervalSinceReferenceDate]
1170                          windowNumber:[[view window] windowNumber]
1171                          context:[[NSApp currentEvent] context]
1172                          eventNumber:0 clickCount:0 pressure:0];
1173         [[lastHitView _bridge] mouseMoved:event];
1174     }
1175
1176     lastHitView = view;
1177
1178     if (view) {
1179         [[view _bridge] mouseMoved:event];
1180
1181         NSPoint point = [view convertPoint:[event locationInWindow] fromView:nil];
1182         NSDictionary *element = [view elementAtPoint:point];
1183
1184         // Have the web view send a message to the delegate so it can do status bar display.
1185         [[view _webView] _mouseDidMoveOverElement:element modifierFlags:[event modifierFlags]];
1186
1187         // Set a tool tip; it won't show up right away but will if the user pauses.
1188         NSString *newToolTip = nil;
1189         if (_private->showsURLsInToolTips) {
1190             DOMHTMLElement *domElement = [element objectForKey:WebElementDOMNodeKey];
1191             if ([domElement isKindOfClass:[DOMHTMLInputElement class]]) {
1192                 if ([[(DOMHTMLInputElement *)domElement type] isEqualToString:@"submit"])
1193                     newToolTip = [[(DOMHTMLInputElement *) domElement form] action];
1194             }
1195             if (newToolTip == nil)
1196                 newToolTip = [[element objectForKey:WebElementLinkURLKey] _web_userVisibleString];
1197         }
1198         if (newToolTip == nil)
1199             newToolTip = [element objectForKey:WebElementTitleKey];
1200         [view _setToolTip:newToolTip];
1201
1202         [view release];
1203     }
1204 }
1205
1206 + (NSArray *)_insertablePasteboardTypes
1207 {
1208     static NSArray *types = nil;
1209     if (!types) {
1210         types = [[NSArray alloc] initWithObjects:WebArchivePboardType, NSHTMLPboardType,
1211             NSFilenamesPboardType, NSTIFFPboardType, NSPICTPboardType, NSURLPboardType, 
1212             NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, NSColorPboardType, nil];
1213     }
1214     return types;
1215 }
1216
1217 + (NSArray *)_selectionPasteboardTypes
1218 {
1219     // FIXME: We should put data for NSHTMLPboardType on the pasteboard but Microsoft Excel doesn't like our format of HTML (3640423).
1220     return [NSArray arrayWithObjects:WebArchivePboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, nil];
1221 }
1222
1223 - (NSImage *)_dragImageForLinkElement:(NSDictionary *)element
1224 {
1225     NSURL *linkURL = [element objectForKey: WebElementLinkURLKey];
1226
1227     BOOL drawURLString = YES;
1228     BOOL clipURLString = NO, clipLabelString = NO;
1229     
1230     NSString *label = [element objectForKey: WebElementLinkLabelKey];
1231     NSString *urlString = [linkURL _web_userVisibleString];
1232     
1233     if (!label) {
1234         drawURLString = NO;
1235         label = urlString;
1236     }
1237     
1238     NSFont *labelFont = [[NSFontManager sharedFontManager] convertFont:[NSFont systemFontOfSize:DRAG_LINK_LABEL_FONT_SIZE]
1239                                                    toHaveTrait:NSBoldFontMask];
1240     NSFont *urlFont = [NSFont systemFontOfSize: DRAG_LINK_URL_FONT_SIZE];
1241     NSSize labelSize;
1242     labelSize.width = [label _web_widthWithFont: labelFont];
1243     labelSize.height = [labelFont ascender] - [labelFont descender];
1244     if (labelSize.width > MAX_DRAG_LABEL_WIDTH){
1245         labelSize.width = MAX_DRAG_LABEL_WIDTH;
1246         clipLabelString = YES;
1247     }
1248     
1249     NSSize imageSize, urlStringSize;
1250     imageSize.width = labelSize.width + DRAG_LABEL_BORDER_X * 2.0f;
1251     imageSize.height = labelSize.height + DRAG_LABEL_BORDER_Y * 2.0f;
1252     if (drawURLString) {
1253         urlStringSize.width = [urlString _web_widthWithFont: urlFont];
1254         urlStringSize.height = [urlFont ascender] - [urlFont descender];
1255         imageSize.height += urlStringSize.height;
1256         if (urlStringSize.width > MAX_DRAG_LABEL_WIDTH) {
1257             imageSize.width = MAX(MAX_DRAG_LABEL_WIDTH + DRAG_LABEL_BORDER_X * 2.0f, MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP);
1258             clipURLString = YES;
1259         } else {
1260             imageSize.width = MAX(labelSize.width + DRAG_LABEL_BORDER_X * 2.0f, urlStringSize.width + DRAG_LABEL_BORDER_X * 2.0f);
1261         }
1262     }
1263     NSImage *dragImage = [[[NSImage alloc] initWithSize: imageSize] autorelease];
1264     [dragImage lockFocus];
1265     
1266     [[NSColor colorWithCalibratedRed: 0.7f green: 0.7f blue: 0.7f alpha: 0.8f] set];
1267     
1268     // Drag a rectangle with rounded corners/
1269     NSBezierPath *path = [NSBezierPath bezierPath];
1270     [path appendBezierPathWithOvalInRect: NSMakeRect(0.0f, 0.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1271     [path appendBezierPathWithOvalInRect: NSMakeRect(0, imageSize.height - DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1272     [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)];
1273     [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS * 2.0f, 0.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1274     
1275     [path appendBezierPathWithRect: NSMakeRect(DRAG_LABEL_RADIUS, 0.0f, imageSize.width - DRAG_LABEL_RADIUS * 2.0f, imageSize.height)];
1276     [path appendBezierPathWithRect: NSMakeRect(0.0f, DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS + 10.0f, imageSize.height - 2.0f * DRAG_LABEL_RADIUS)];
1277     [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)];
1278     [path fill];
1279         
1280     NSColor *topColor = [NSColor colorWithCalibratedWhite:0.0f alpha:0.75f];
1281     NSColor *bottomColor = [NSColor colorWithCalibratedWhite:1.0f alpha:0.5f];
1282     if (drawURLString) {
1283         if (clipURLString)
1284             urlString = [WebStringTruncator centerTruncateString: urlString toWidth:imageSize.width - (DRAG_LABEL_BORDER_X * 2.0f) withFont:urlFont];
1285
1286         [urlString _web_drawDoubledAtPoint:NSMakePoint(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y - [urlFont descender]) 
1287              withTopColor:topColor bottomColor:bottomColor font:urlFont];
1288     }
1289
1290     if (clipLabelString)
1291         label = [WebStringTruncator rightTruncateString: label toWidth:imageSize.width - (DRAG_LABEL_BORDER_X * 2.0f) withFont:labelFont];
1292     [label _web_drawDoubledAtPoint:NSMakePoint (DRAG_LABEL_BORDER_X, imageSize.height - DRAG_LABEL_BORDER_Y_OFFSET - [labelFont pointSize])
1293              withTopColor:topColor bottomColor:bottomColor font:labelFont];
1294     
1295     [dragImage unlockFocus];
1296     
1297     return dragImage;
1298 }
1299
1300 - (BOOL)_startDraggingImage:(NSImage *)wcDragImage at:(NSPoint)wcDragLoc operation:(NSDragOperation)op event:(NSEvent *)mouseDraggedEvent sourceIsDHTML:(BOOL)srcIsDHTML DHTMLWroteData:(BOOL)dhtmlWroteData
1301 {
1302     WebHTMLView *topHTMLView = [self _topHTMLView];
1303     if (self != topHTMLView) {
1304         [topHTMLView _setMouseDownEvent:_private->mouseDownEvent];
1305         BOOL result = [topHTMLView _startDraggingImage:wcDragImage at:wcDragLoc operation:op event:mouseDraggedEvent sourceIsDHTML:srcIsDHTML DHTMLWroteData:dhtmlWroteData];
1306         [topHTMLView _setMouseDownEvent:nil];
1307         return result;
1308     }
1309
1310     NSPoint mouseDownPoint = [self convertPoint:[_private->mouseDownEvent locationInWindow] fromView:nil];
1311     NSDictionary *element = [self elementAtPoint:mouseDownPoint allowShadowContent:YES];
1312
1313     NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1314     NSURL *imageURL = [element objectForKey:WebElementImageURLKey];
1315     BOOL isSelected = [[element objectForKey:WebElementIsSelectedKey] boolValue];
1316
1317     [_private->draggingImageURL release];
1318     _private->draggingImageURL = nil;
1319
1320     NSPoint mouseDraggedPoint = [self convertPoint:[mouseDraggedEvent locationInWindow] fromView:nil];
1321     _private->webCoreDragOp = op;     // will be DragNone if WebCore doesn't care
1322     NSImage *dragImage = nil;
1323     NSPoint dragLoc = { 0, 0 }; // quiet gcc 4.0 warning
1324
1325     // We allow WebCore to override the drag image, even if its a link, image or text we're dragging.
1326     // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp.
1327     // We could verify that ActionDHTML is allowed, although WebCore does claim to respect the action.
1328     if (wcDragImage) {
1329         dragImage = wcDragImage;
1330         // wcDragLoc is the cursor position relative to the lower-left corner of the image.
1331         // We add in the Y dimension because we are a flipped view, so adding moves the image down.
1332         if (linkURL)
1333             // see HACK below
1334             dragLoc = NSMakePoint(mouseDraggedPoint.x - wcDragLoc.x, mouseDraggedPoint.y + wcDragLoc.y);
1335         else
1336             dragLoc = NSMakePoint(mouseDownPoint.x - wcDragLoc.x, mouseDownPoint.y + wcDragLoc.y);
1337         _private->dragOffset = wcDragLoc;
1338     }
1339     
1340     WebView *webView = [self _webView];
1341     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
1342     BOOL startedDrag = YES;  // optimism - we almost always manage to start the drag
1343
1344     // note per kwebster, the offset arg below is always ignored in positioning the image
1345     DOMNode *node = [element objectForKey:WebElementDOMNodeKey];
1346     WebHTMLView *innerHTMLView = (WebHTMLView *)[[[[node ownerDocument] webFrame] frameView] documentView];
1347     ASSERT([innerHTMLView isKindOfClass:[WebHTMLView class]]);
1348     if (imageURL != nil
1349             && [node isKindOfClass:[DOMElement class]]
1350             && [(DOMElement *)node image]
1351             && (_private->dragSourceActionMask & WebDragSourceActionImage)) {
1352         id source = self;
1353         if (!dhtmlWroteData) {
1354             // Select the image when it is dragged. This allows the image to be moved via MoveSelectionCommandImpl and this matches NSTextView's behavior.
1355             ASSERT(node != nil);
1356             [webView setSelectedDOMRange:[[node ownerDocument] _createRangeWithNode:node] affinity:NSSelectionAffinityDownstream];
1357             _private->draggingImageURL = [imageURL retain];
1358             
1359             WebArchive *archive;
1360             
1361             // If the image element comes from an ImageDocument, we don't want to 
1362             // create a web archive from the image element.
1363             if ([[self _bridge] canSaveAsWebArchive])
1364                 archive = [node webArchive];
1365             else
1366                 archive = [WebArchiver archiveMainResourceForFrame:[self _frame]];
1367             
1368             source = [pasteboard _web_declareAndWriteDragImageForElement:(DOMElement *)node
1369                                                                      URL:linkURL ? linkURL : imageURL
1370                                                                    title:[element objectForKey:WebElementImageAltStringKey]
1371                                                                  archive:archive
1372                                                                   source:self];
1373         }
1374         [[webView _UIDelegateForwarder] webView:webView willPerformDragSourceAction:WebDragSourceActionImage fromPoint:mouseDownPoint withPasteboard:pasteboard];
1375         if (dragImage == nil)
1376             [self _web_DragImageForElement:(DOMElement *)node
1377                                       rect:[self convertRect:[[element objectForKey:WebElementImageRectKey] rectValue] fromView:innerHTMLView]
1378                                      event:_private->mouseDownEvent
1379                                 pasteboard:pasteboard
1380                                     source:source
1381                                     offset:&_private->dragOffset];
1382         else
1383             [self dragImage:dragImage
1384                          at:dragLoc
1385                      offset:NSZeroSize
1386                       event:_private->mouseDownEvent
1387                  pasteboard:pasteboard
1388                      source:source
1389                   slideBack:YES];
1390     } else if (linkURL && (_private->dragSourceActionMask & WebDragSourceActionLink)) {
1391         if (!dhtmlWroteData) {
1392             NSArray *types = [NSPasteboard _web_writableTypesForURL];
1393             [pasteboard declareTypes:types owner:self];
1394             [pasteboard _web_writeURL:linkURL andTitle:[element objectForKey:WebElementLinkLabelKey] types:types];            
1395         }
1396         [[webView _UIDelegateForwarder] webView:webView willPerformDragSourceAction:WebDragSourceActionLink fromPoint:mouseDownPoint withPasteboard:pasteboard];
1397         if (dragImage == nil) {
1398             dragImage = [self _dragImageForLinkElement:element];
1399             NSSize offset = NSMakeSize([dragImage size].width / 2, -DRAG_LABEL_BORDER_Y);
1400             dragLoc = NSMakePoint(mouseDraggedPoint.x - offset.width, mouseDraggedPoint.y - offset.height);
1401             _private->dragOffset.x = offset.width;
1402             _private->dragOffset.y = -offset.height;        // inverted because we are flipped
1403         }
1404         // HACK:  We should pass the mouseDown event instead of the mouseDragged!  This hack gets rid of
1405         // a flash of the image at the mouseDown location when the drag starts.
1406         [self dragImage:dragImage
1407                      at:dragLoc
1408                  offset:NSZeroSize
1409                   event:mouseDraggedEvent
1410              pasteboard:pasteboard
1411                  source:self
1412               slideBack:YES];
1413     } else if (isSelected && (_private->dragSourceActionMask & WebDragSourceActionSelection)) {
1414         if (!dhtmlWroteData)
1415             [innerHTMLView _writeSelectionToPasteboard:pasteboard];
1416         [[webView _UIDelegateForwarder] webView:webView willPerformDragSourceAction:WebDragSourceActionSelection fromPoint:mouseDownPoint withPasteboard:pasteboard];
1417         if (dragImage == nil) {
1418             dragImage = [innerHTMLView _selectionDraggingImage];
1419             NSRect draggingRect = [self convertRect:[innerHTMLView _selectionDraggingRect] fromView:innerHTMLView];
1420             dragLoc = NSMakePoint(NSMinX(draggingRect), NSMaxY(draggingRect));
1421             _private->dragOffset.x = mouseDownPoint.x - dragLoc.x;
1422             _private->dragOffset.y = dragLoc.y - mouseDownPoint.y;        // inverted because we are flipped
1423         }
1424         [self dragImage:dragImage
1425                      at:dragLoc
1426                  offset:NSZeroSize
1427                   event:_private->mouseDownEvent
1428              pasteboard:pasteboard
1429                  source:self
1430               slideBack:YES];
1431     } else if (srcIsDHTML) {
1432         ASSERT(_private->dragSourceActionMask & WebDragSourceActionDHTML);
1433         [[webView _UIDelegateForwarder] webView:webView willPerformDragSourceAction:WebDragSourceActionDHTML fromPoint:mouseDownPoint withPasteboard:pasteboard];
1434         if (dragImage == nil) {
1435             // WebCore should have given us an image, but we'll make one up
1436             // FIXME: Oops! I removed this image from WebKit. Is this a dead code path?
1437             NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"missing_image" ofType:@"tiff"];
1438             dragImage = [[[NSImage alloc] initWithContentsOfFile:imagePath] autorelease];
1439             NSSize imageSize = [dragImage size];
1440             dragLoc = NSMakePoint(mouseDownPoint.x - imageSize.width / 2, mouseDownPoint.y + imageSize.height / 2);
1441             _private->dragOffset.x = imageSize.width / 2;
1442             _private->dragOffset.y = imageSize.height / 2;
1443         }
1444         [self dragImage:dragImage
1445                      at:dragLoc
1446                  offset:NSZeroSize
1447                   event:_private->mouseDownEvent
1448              pasteboard:pasteboard
1449                  source:self
1450               slideBack:YES];
1451     } else {
1452         // Only way I know if to get here is if the original element clicked on in the mousedown is no longer
1453         // under the mousedown point, so linkURL, imageURL and isSelected are all false/nil.
1454         startedDrag = NO;
1455     }
1456     return startedDrag;
1457 }
1458
1459 - (void)_handleAutoscrollForMouseDragged:(NSEvent *)event
1460 {
1461     [self autoscroll:event];
1462     [self _startAutoscrollTimer:event];
1463 }
1464
1465 - (BOOL)_mayStartDragAtEventLocation:(NSPoint)location
1466 {
1467     WebHTMLView *topHTMLView = [self _topHTMLView];
1468     if (self != topHTMLView)
1469         return [topHTMLView _mayStartDragAtEventLocation:location];
1470
1471     NSPoint mouseDownPoint = [self convertPoint:location fromView:nil];
1472     NSDictionary *mouseDownElement = [self elementAtPoint:mouseDownPoint allowShadowContent:YES];
1473
1474     ASSERT([self _webView]);
1475
1476     if ([mouseDownElement objectForKey:WebElementImageKey]
1477             && [mouseDownElement objectForKey:WebElementImageURLKey]
1478             && [[[self _webView] preferences] loadsImagesAutomatically]
1479             && (_private->dragSourceActionMask & WebDragSourceActionImage))
1480         return YES;
1481     
1482     if ([mouseDownElement objectForKey:WebElementLinkURLKey]
1483             && (_private->dragSourceActionMask & WebDragSourceActionLink))
1484         return YES;
1485     
1486     if ([[mouseDownElement objectForKey:WebElementIsSelectedKey] boolValue]
1487             && (_private->dragSourceActionMask & WebDragSourceActionSelection))
1488         return YES;
1489     
1490     return NO;
1491 }
1492
1493 - (WebPluginController *)_pluginController
1494 {
1495     return _private->pluginController;
1496 }
1497
1498 - (void)_web_setPrintingModeRecursive
1499 {
1500     [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
1501     [super _web_setPrintingModeRecursive];
1502 }
1503
1504 - (void)_web_clearPrintingModeRecursive
1505 {
1506     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
1507     [super _web_clearPrintingModeRecursive];
1508 }
1509
1510 - (void)_layoutIfNeeded
1511 {
1512     ASSERT(!_private->subviewsSetAside);
1513
1514     if ([[self _bridge] needsLayout])
1515         _private->needsLayout = YES;
1516     if (_private->needsToApplyStyles || _private->needsLayout)
1517         [self layout];
1518 }
1519
1520 - (void)_web_layoutIfNeededRecursive
1521 {
1522     [self _layoutIfNeeded];
1523     [super _web_layoutIfNeededRecursive];
1524 }
1525
1526 - (void)_web_layoutIfNeededRecursive:(NSRect)displayRect testDirtyRect:(bool)testDirtyRect
1527 {
1528     ASSERT(!_private->subviewsSetAside);
1529
1530     displayRect = NSIntersectionRect(displayRect, [self bounds]);
1531     if (testDirtyRect) {
1532         NSRect dirtyRect = [self _dirtyRect];
1533         displayRect = NSIntersectionRect(displayRect, dirtyRect);
1534     }
1535     if (!NSIsEmptyRect(displayRect))
1536         [self _layoutIfNeeded];
1537
1538     [super _web_layoutIfNeededRecursive:displayRect testDirtyRect:NO];
1539 }
1540
1541 - (void)_startAutoscrollTimer: (NSEvent *)triggerEvent
1542 {
1543     if (_private->autoscrollTimer == nil) {
1544         _private->autoscrollTimer = [[NSTimer scheduledTimerWithTimeInterval:AUTOSCROLL_INTERVAL
1545             target:self selector:@selector(_autoscroll) userInfo:nil repeats:YES] retain];
1546         _private->autoscrollTriggerEvent = [triggerEvent retain];
1547     }
1548 }
1549
1550 // FIXME: _selectionRect is deprecated in favor of selectionRect, which is in protocol WebDocumentSelection.
1551 // We can't remove this yet because it's still in use by Mail.
1552 - (NSRect)_selectionRect
1553 {
1554     return [self selectionRect];
1555 }
1556
1557 - (void)_stopAutoscrollTimer
1558 {
1559     NSTimer *timer = _private->autoscrollTimer;
1560     _private->autoscrollTimer = nil;
1561     [_private->autoscrollTriggerEvent release];
1562     _private->autoscrollTriggerEvent = nil;
1563     [timer invalidate];
1564     [timer release];
1565 }
1566
1567 - (void)_autoscroll
1568 {
1569     // Guarantee that the autoscroll timer is invalidated, even if we don't receive
1570     // a mouse up event.
1571     BOOL isStillDown = CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft);   
1572     if (!isStillDown){
1573         [self _stopAutoscrollTimer];
1574         return;
1575     }
1576
1577     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
1578         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
1579         modifierFlags:[[NSApp currentEvent] modifierFlags]
1580         timestamp:[NSDate timeIntervalSinceReferenceDate]
1581         windowNumber:[[self window] windowNumber]
1582         context:[[NSApp currentEvent] context]
1583         eventNumber:0 clickCount:0 pressure:0];
1584     [self mouseDragged:fakeEvent];
1585 }
1586
1587 - (BOOL)_canCopy
1588 {
1589     // Copying can be done regardless of whether you can edit.
1590     return [self _hasSelection];
1591 }
1592
1593 - (BOOL)_canCut
1594 {
1595     return [self _hasSelection] && [self _isEditable];
1596 }
1597
1598 - (BOOL)_canDelete
1599 {
1600     return [self _hasSelection] && [self _isEditable];
1601 }
1602
1603 - (BOOL)_canPaste
1604 {
1605     return [self _hasSelectionOrInsertionPoint] && [self _isEditable];
1606 }
1607
1608 - (BOOL)_canEdit
1609 {
1610     return [self _hasSelectionOrInsertionPoint] && [self _isEditable];
1611 }
1612
1613 - (BOOL)_canEditRichly
1614 {
1615     return [self _canEdit] && [[self _bridge] isSelectionRichlyEditable];
1616 }
1617
1618 - (BOOL)_canAlterCurrentSelection
1619 {
1620     return [self _hasSelectionOrInsertionPoint] && [self _isEditable];
1621 }
1622
1623 - (BOOL)_hasSelection
1624 {
1625     return [[self _bridge] selectionState] == WebSelectionStateRange;
1626 }
1627
1628 - (BOOL)_hasSelectionOrInsertionPoint
1629 {
1630     return [[self _bridge] selectionState] != WebSelectionStateNone;
1631 }
1632
1633 - (BOOL)_hasInsertionPoint
1634 {
1635     return [[self _bridge] selectionState] == WebSelectionStateCaret;
1636 }
1637
1638 - (BOOL)_isEditable
1639 {
1640     return [[self _webView] isEditable] || [[self _bridge] isSelectionEditable];
1641 }
1642
1643 - (BOOL)_isSelectionMisspelled
1644 {
1645     NSString *selectedString = [self selectedString];
1646     unsigned length = [selectedString length];
1647     if (length == 0) {
1648         return NO;
1649     }
1650     NSRange range = [[NSSpellChecker sharedSpellChecker] checkSpellingOfString:selectedString
1651                                                                     startingAt:0
1652                                                                       language:nil
1653                                                                           wrap:NO
1654                                                         inSpellDocumentWithTag:[[self _webView] spellCheckerDocumentTag]
1655                                                                      wordCount:NULL];
1656     return range.length == length;
1657 }
1658
1659 - (NSArray *)_guessesForMisspelledSelection
1660 {
1661     ASSERT([[self selectedString] length] != 0);
1662     return [[NSSpellChecker sharedSpellChecker] guessesForWord:[self selectedString]];
1663 }
1664
1665 - (void)_changeSpellingFromMenu:(id)sender
1666 {
1667     ASSERT([[self selectedString] length] != 0);
1668     if ([self _shouldReplaceSelectionWithText:[sender title] givenAction:WebViewInsertActionPasted]) {
1669         [[self _bridge] replaceSelectionWithText:[sender title] selectReplacement:YES smartReplace:NO];
1670     }
1671 }
1672
1673 - (void)_ignoreSpellingFromMenu:(id)sender
1674 {
1675     ASSERT([[self selectedString] length] != 0);
1676     [[NSSpellChecker sharedSpellChecker] ignoreWord:[self selectedString] inSpellDocumentWithTag:[[self _webView] spellCheckerDocumentTag]];
1677 }
1678
1679 - (void)_learnSpellingFromMenu:(id)sender
1680 {
1681     ASSERT([[self selectedString] length] != 0);
1682     [[NSSpellChecker sharedSpellChecker] learnWord:[self selectedString]];
1683 }
1684
1685 - (void)_lookUpInDictionaryFromMenu:(id)sender
1686 {
1687     // This should only be called when there's a selection, but play it safe.
1688     if (![self _hasSelection]) {
1689         return;
1690     }
1691     
1692     // Soft link to dictionary-display function to avoid linking another framework (ApplicationServices/LangAnalysis)
1693     static OSStatus (*__dictionaryServiceWindowShow)(id inWordString, NSRect inWordBoundary, UInt16 inLineDirection) = NULL;
1694     static const struct mach_header *frameworkImageHeader = NULL;
1695     static BOOL lookedForFunction = NO;
1696     if (!lookedForFunction) {
1697         __dictionaryServiceWindowShow = _NSSoftLinkingGetFrameworkFuncPtr(@"ApplicationServices", @"LangAnalysis", "_DCMDictionaryServiceWindowShow", &frameworkImageHeader);
1698         lookedForFunction = YES;
1699     }
1700     if (!__dictionaryServiceWindowShow) {
1701         LOG_ERROR("Couldn't find _DCMDictionaryServiceWindowShow"); 
1702         return;
1703     }
1704     
1705     // FIXME: must check for right-to-left here
1706     NSWritingDirection writingDirection = NSWritingDirectionLeftToRight;
1707     
1708     NSAttributedString *attrString = [self selectedAttributedString];
1709     // FIXME: the dictionary API expects the rect for the first line of selection. Passing
1710     // the rect for the entire selection, as we do here, positions the pop-up window near
1711     // the bottom of the selection rather than at the selected word.
1712     NSRect rect = [self convertRect:[[self _bridge] visibleSelectionRect] toView:nil];
1713     rect.origin = [[self window] convertBaseToScreen:rect.origin];
1714     NSData *data = [attrString RTFFromRange:NSMakeRange(0, [attrString length]) documentAttributes:nil];
1715     (void)__dictionaryServiceWindowShow(data, rect, (writingDirection == NSWritingDirectionRightToLeft) ? 1 : 0);
1716 }
1717
1718 - (BOOL)_transparentBackground
1719 {
1720     return _private->transparentBackground;
1721 }
1722
1723 - (void)_setTransparentBackground:(BOOL)f
1724 {
1725     _private->transparentBackground = f;
1726 }
1727
1728 - (NSImage *)_selectionDraggingImage
1729 {
1730     if ([self _hasSelection]) {
1731         NSImage *dragImage = [[self _bridge] selectionImageForcingWhiteText:NO];
1732         [dragImage _web_dissolveToFraction:WebDragImageAlpha];
1733         return dragImage;
1734     }
1735     return nil;
1736 }
1737
1738 - (NSRect)_selectionDraggingRect
1739 {
1740     // Mail currently calls this method. We can eliminate it when Mail no longer calls it.
1741     return [self selectionImageRect];
1742 }
1743
1744 - (BOOL)_canIncreaseSelectionListLevel
1745 {
1746     return ([self _canEditRichly] && [[self _bridge] canIncreaseSelectionListLevel]);
1747 }
1748
1749 - (BOOL)_canDecreaseSelectionListLevel
1750 {
1751     return ([self _canEditRichly] && [[self _bridge] canDecreaseSelectionListLevel]);
1752 }
1753
1754 - (DOMNode *)_increaseSelectionListLevel
1755 {
1756     if (![self _canEditRichly])
1757         return nil;
1758         
1759     WebFrameBridge *bridge = [self _bridge];
1760     return [bridge increaseSelectionListLevel];
1761 }
1762
1763 - (DOMNode *)_increaseSelectionListLevelOrdered
1764 {
1765     if (![self _canEditRichly])
1766         return nil;
1767         
1768     WebFrameBridge *bridge = [self _bridge];
1769     return [bridge increaseSelectionListLevelOrdered];
1770 }
1771
1772 - (DOMNode *)_increaseSelectionListLevelUnordered
1773 {
1774     if (![self _canEditRichly])
1775         return nil;
1776         
1777     WebFrameBridge *bridge = [self _bridge];
1778     return [bridge increaseSelectionListLevelUnordered];
1779 }
1780
1781 - (void)_decreaseSelectionListLevel
1782 {
1783     if (![self _canEditRichly])
1784         return;
1785         
1786     WebFrameBridge *bridge = [self _bridge];
1787     [bridge decreaseSelectionListLevel];
1788 }
1789
1790 - (void)_setHighlighter:(id<WebHTMLHighlighter>)highlighter ofType:(NSString*)type
1791 {
1792     if (!_private->highlighters)
1793         _private->highlighters = [[NSMutableDictionary alloc] init];
1794     [_private->highlighters setObject:highlighter forKey:type];
1795 }
1796
1797 - (void)_removeHighlighterOfType:(NSString*)type
1798 {
1799     [_private->highlighters removeObjectForKey:type];
1800 }
1801
1802 - (BOOL)_web_firstResponderCausesFocusDisplay
1803 {
1804     return [self _web_firstResponderIsSelfOrDescendantView] || [[self window] firstResponder] == [self _frameView];
1805 }
1806
1807 - (void)_updateActiveState
1808 {
1809     // This method does the job of updating the view based on the view's firstResponder-ness and
1810     // the window key-ness of the window containing this view. This involves four kinds of 
1811     // drawing updates right now, all handled in WebCore in response to the call over the bridge. 
1812     // 
1813     // The four display attributes are as follows:
1814     // 
1815     // 1. The background color used to draw behind selected content (active | inactive color)
1816     // 2. Caret blinking (blinks | does not blink)
1817     // 3. The drawing of a focus ring around links in web pages.
1818     // 4. Changing the tint of controls from clear to aqua/graphite and vice versa
1819     //
1820     // Also, this is responsible for letting the bridge know if the window has gained or lost focus
1821     // so we can send focus and blur events.
1822
1823     NSWindow *window = [self window];
1824     BOOL windowIsKey = [window isKeyWindow];
1825     BOOL windowOrSheetIsKey = windowIsKey || [[window attachedSheet] isKeyWindow];
1826
1827     BOOL isActive = !_private->resigningFirstResponder && windowIsKey && (_private->descendantBecomingFirstResponder || [self _web_firstResponderCausesFocusDisplay]);
1828     
1829     [[self _bridge] setWindowHasFocus:windowOrSheetIsKey];
1830     [[self _bridge] setIsActive:isActive];
1831 }
1832
1833 - (unsigned)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag
1834 {
1835     return [[self _bridge] markAllMatchesForText:string caseSensitive:caseFlag];
1836 }
1837
1838 - (void)setMarkedTextMatchesAreHighlighted:(BOOL)newValue
1839 {
1840     [[self _bridge] setMarkedTextMatchesAreHighlighted:newValue];
1841 }
1842
1843 - (BOOL)markedTextMatchesAreHighlighted
1844 {
1845     return [[self _bridge] markedTextMatchesAreHighlighted];
1846 }
1847
1848 - (void)unmarkAllTextMatches
1849 {
1850     return [[self _bridge] unmarkAllTextMatches];
1851 }
1852
1853 - (NSArray *)rectsForTextMatches
1854 {
1855     return [[self _bridge] rectsForTextMatches];
1856 }
1857
1858 - (void)_writeSelectionToPasteboard:(NSPasteboard *)pasteboard
1859 {
1860     ASSERT([self _hasSelection]);
1861     NSArray *types = [self pasteboardTypesForSelection];
1862
1863     // Don't write RTFD to the pasteboard when the copied attributed string has no attachments.
1864     NSAttributedString *attributedString = [self selectedAttributedString];
1865     NSMutableArray *mutableTypes = nil;
1866     if (![attributedString containsAttachments]) {
1867         mutableTypes = [types mutableCopy];
1868         [mutableTypes removeObject:NSRTFDPboardType];
1869         types = mutableTypes;
1870     }
1871
1872     [pasteboard declareTypes:types owner:nil];
1873     [self _writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard cachedAttributedString:attributedString];
1874     [mutableTypes release];
1875 }
1876
1877 - (void)close
1878 {
1879     if (_private->closed)
1880         return;
1881     [self _clearLastHitViewIfSelf];
1882     // FIXME: This is slow; should remove individual observers instead.
1883     [[NSNotificationCenter defaultCenter] removeObserver:self];
1884     [_private->pluginController destroyAllPlugins];
1885     // remove tooltips before clearing _private so removeTrackingRect: will work correctly
1886     [self removeAllToolTips];
1887     _private->closed = YES;
1888 }
1889
1890 @end
1891
1892 @implementation NSView (WebHTMLViewFileInternal)
1893
1894 - (void)_web_setPrintingModeRecursive
1895 {
1896     [_subviews makeObjectsPerformSelector:@selector(_web_setPrintingModeRecursive)];
1897 }
1898
1899 - (void)_web_clearPrintingModeRecursive
1900 {
1901     [_subviews makeObjectsPerformSelector:@selector(_web_clearPrintingModeRecursive)];
1902 }
1903
1904 - (void)_web_layoutIfNeededRecursive
1905 {
1906     [_subviews makeObjectsPerformSelector:@selector(_web_layoutIfNeededRecursive)];
1907 }
1908
1909 - (void)_web_layoutIfNeededRecursive: (NSRect)rect testDirtyRect:(bool)testDirtyRect
1910 {
1911     unsigned index, count;
1912     for (index = 0, count = [(NSArray *)_subviews count]; index < count; index++) {
1913         NSView *subview = [_subviews objectAtIndex:index];
1914         NSRect dirtiedSubviewRect = [subview convertRect: rect fromView: self];
1915         [subview _web_layoutIfNeededRecursive: dirtiedSubviewRect testDirtyRect:testDirtyRect];
1916     }
1917 }
1918
1919 @end
1920
1921 @implementation NSMutableDictionary (WebHTMLViewFileInternal)
1922
1923 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key
1924 {
1925     if (object == nil) {
1926         [self removeObjectForKey:key];
1927     } else {
1928         [self setObject:object forKey:key];
1929     }
1930 }
1931
1932 @end
1933
1934 // The following is a workaround for
1935 // <rdar://problem/3429631> window stops getting mouse moved events after first tooltip appears
1936 // The trick is to define a category on NSToolTipPanel that implements setAcceptsMouseMovedEvents:.
1937 // Since the category will be searched before the real class, we'll prevent the flag from being
1938 // set on the tool tip panel.
1939
1940 @interface NSToolTipPanel : NSPanel
1941 @end
1942
1943 @interface NSToolTipPanel (WebHTMLViewFileInternal)
1944 @end
1945
1946 @implementation NSToolTipPanel (WebHTMLViewFileInternal)
1947
1948 - (void)setAcceptsMouseMovedEvents:(BOOL)flag
1949 {
1950     // Do nothing, preventing the tool tip panel from trying to accept mouse-moved events.
1951 }
1952
1953 @end
1954
1955 @interface NSArray (WebHTMLView)
1956 - (void)_web_makePluginViewsPerformSelector:(SEL)selector withObject:(id)object;
1957 @end
1958
1959 @implementation WebHTMLView
1960
1961 + (void)initialize
1962 {
1963     [NSApp registerServicesMenuSendTypes:[[self class] _selectionPasteboardTypes] 
1964                              returnTypes:[[self class] _insertablePasteboardTypes]];
1965     _NSInitializeKillRing();
1966 }
1967
1968 - (void)_resetCachedWebPreferences:(NSNotification *)ignored
1969 {
1970     WebPreferences *preferences = [[self _webView] preferences];
1971     // Check for nil because we might not yet have an associated webView when this is called
1972     if (preferences == nil) {
1973         preferences = [WebPreferences standardPreferences];
1974     }
1975     _private->showsURLsInToolTips = [preferences showsURLsInToolTips];
1976 }
1977
1978 - (id)initWithFrame:(NSRect)frame
1979 {
1980     self = [super initWithFrame:frame];
1981     if (!self)
1982         return nil;
1983     
1984     // Make all drawing go through us instead of subviews.
1985     if (NSAppKitVersionNumber >= 711) {
1986         [self _setDrawsOwnDescendants:YES];
1987     }
1988     
1989     _private = [[WebHTMLViewPrivate alloc] init];
1990
1991     _private->pluginController = [[WebPluginController alloc] initWithDocumentView:self];
1992     _private->needsLayout = YES;
1993     [self _resetCachedWebPreferences:nil];
1994     [[NSNotificationCenter defaultCenter] 
1995             addObserver:self selector:@selector(_resetCachedWebPreferences:) 
1996                    name:WebPreferencesChangedNotification object:nil];
1997     
1998     return self;
1999 }
2000
2001 - (void)dealloc
2002 {
2003     // We can't assert that close has already been called because
2004     // this view can be removed from it's superview, even though
2005     // it could be needed later, so close if needed.
2006     [self close];
2007     [_private release];
2008     _private = nil;
2009     [super dealloc];
2010 }
2011
2012 - (void)finalize
2013 {
2014     // We can't assert that close has already been called because
2015     // this view can be removed from it's superview, even though
2016     // it could be needed later, so close if needed.
2017     [self close];
2018     [super finalize];
2019 }
2020
2021 - (IBAction)takeFindStringFromSelection:(id)sender
2022 {
2023     if (![self _hasSelection]) {
2024         NSBeep();
2025         return;
2026     }
2027
2028     [NSPasteboard _web_setFindPasteboardString:[self selectedString] withOwner:self];
2029 }
2030
2031 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
2032 {
2033     [pasteboard declareTypes:types owner:nil];
2034     [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2035     return YES;
2036 }
2037
2038 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard
2039 {
2040     if ([[self _bridge] isSelectionRichlyEditable])
2041         [self _pasteWithPasteboard:pasteboard allowPlainText:YES];
2042     else
2043         [self _pasteAsPlainTextWithPasteboard:pasteboard];
2044     return YES;
2045 }
2046
2047 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
2048 {
2049     if (sendType != nil && [[self pasteboardTypesForSelection] containsObject:sendType] && [self _hasSelection]) {
2050         return self;
2051     } else if (returnType != nil && [[[self class] _insertablePasteboardTypes] containsObject:returnType] && [self _isEditable]) {
2052         return self;
2053     }
2054     return [[self nextResponder] validRequestorForSendType:sendType returnType:returnType];
2055 }
2056
2057 - (void)selectAll:(id)sender
2058 {
2059     [self selectAll];
2060 }
2061
2062 // jumpToSelection is the old name for what AppKit now calls centerSelectionInVisibleArea. Safari
2063 // was using the old jumpToSelection selector in its menu. Newer versions of Safari will us the
2064 // selector centerSelectionInVisibleArea. We'll leave this old selector in place for two reasons:
2065 // (1) compatibility between older Safari and newer WebKit; (2) other WebKit-based applications
2066 // might be using the jumpToSelection: selector, and we don't want to break them.
2067 - (void)jumpToSelection:(id)sender
2068 {
2069     [self centerSelectionInVisibleArea:sender];
2070 }
2071
2072 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 
2073 {
2074     SEL action = [item action];
2075     WebFrameBridge *bridge = [self _bridge];
2076
2077     if (action == @selector(changeBaseWritingDirection:) // FIXME: check menu item based on writing direction
2078             || action == @selector(changeSpelling:)
2079             || action == @selector(_changeSpellingFromMenu:)
2080             || action == @selector(checkSpelling:)
2081             || action == @selector(complete:)
2082             || action == @selector(deleteBackward:)
2083             || action == @selector(deleteBackwardByDecomposingPreviousCharacter:)
2084             || action == @selector(deleteForward:)
2085             || action == @selector(deleteToBeginningOfLine:)
2086             || action == @selector(deleteToBeginningOfParagraph:)
2087             || action == @selector(deleteToEndOfLine:)
2088             || action == @selector(deleteToEndOfParagraph:)
2089             || action == @selector(deleteToMark:)
2090             || action == @selector(deleteWordBackward:)
2091             || action == @selector(deleteWordForward:)
2092             || action == @selector(insertBacktab:)
2093             || action == @selector(insertLineBreak:)
2094             || action == @selector(insertNewline:)
2095             || action == @selector(insertNewlineIgnoringFieldEditor:)
2096             || action == @selector(insertParagraphSeparator:)
2097             || action == @selector(insertTab:)
2098             || action == @selector(insertTabIgnoringFieldEditor:)
2099             || action == @selector(moveBackward:)
2100             || action == @selector(moveBackwardAndModifySelection:)
2101             || action == @selector(moveDown:)
2102             || action == @selector(moveDownAndModifySelection:)
2103             || action == @selector(moveForward:)
2104             || action == @selector(moveForwardAndModifySelection:)
2105             || action == @selector(moveLeft:)
2106             || action == @selector(moveLeftAndModifySelection:)
2107             || action == @selector(moveParagraphBackwardAndModifySelection:)
2108             || action == @selector(moveParagraphForwardAndModifySelection:)
2109             || action == @selector(moveRight:)
2110             || action == @selector(moveRightAndModifySelection:)
2111             || action == @selector(moveToBeginningOfDocument:)
2112             || action == @selector(moveToBeginningOfDocumentAndModifySelection:)
2113             || action == @selector(moveToBeginningOfSentence:)
2114             || action == @selector(moveToBeginningOfSentenceAndModifySelection:)
2115             || action == @selector(moveToBeginningOfLine:)
2116             || action == @selector(moveToBeginningOfLineAndModifySelection:)
2117             || action == @selector(moveToBeginningOfParagraph:)
2118             || action == @selector(moveToBeginningOfParagraphAndModifySelection:)
2119             || action == @selector(moveToEndOfDocument:)
2120             || action == @selector(moveToEndOfDocumentAndModifySelection:)
2121             || action == @selector(moveToEndOfSentence:)
2122             || action == @selector(moveToEndOfSentenceAndModifySelection:)
2123             || action == @selector(moveToEndOfLine:)
2124             || action == @selector(moveToEndOfLineAndModifySelection:)
2125             || action == @selector(moveToEndOfParagraph:)
2126             || action == @selector(moveToEndOfParagraphAndModifySelection:)
2127             || action == @selector(moveUp:)
2128             || action == @selector(moveUpAndModifySelection:)
2129             || action == @selector(moveWordBackward:)
2130             || action == @selector(moveWordBackwardAndModifySelection:)
2131             || action == @selector(moveWordForward:)
2132             || action == @selector(moveWordForwardAndModifySelection:)
2133             || action == @selector(moveWordLeft:)
2134             || action == @selector(moveWordLeftAndModifySelection:)
2135             || action == @selector(moveWordRight:)
2136             || action == @selector(moveWordRightAndModifySelection:)
2137             || action == @selector(pageDown:)
2138             || action == @selector(pageDownAndModifySelection:)
2139             || action == @selector(pageUp:)
2140             || action == @selector(pageUpAndModifySelection:)
2141             || action == @selector(pasteFont:)
2142             || action == @selector(showGuessPanel:)
2143             || action == @selector(toggleBaseWritingDirection:)
2144             || action == @selector(transpose:)
2145             || action == @selector(yank:)
2146             || action == @selector(yankAndSelect:)) {
2147         return [self _canEdit];
2148     } else if (action == @selector(alignCenter:)
2149             || action == @selector(alignLeft:)
2150             || action == @selector(alignJustified:)
2151             || action == @selector(alignRight:)
2152             || action == @selector(changeAttributes:)
2153             || action == @selector(changeColor:)        
2154             || action == @selector(changeFont:)) {
2155         return [self _canEditRichly];
2156     } else if (action == @selector(capitalizeWord:)
2157                || action == @selector(lowercaseWord:)
2158                || action == @selector(uppercaseWord:)) {
2159         return [self _hasSelection] && [self _isEditable];
2160     } else if (action == @selector(centerSelectionInVisibleArea:)
2161                || action == @selector(jumpToSelection:)
2162                || action == @selector(copyFont:)
2163                || action == @selector(setMark:)) {
2164         return [self _hasSelection] || ([self _isEditable] && [self _hasInsertionPoint]);
2165     } else if (action == @selector(changeDocumentBackgroundColor:)) {
2166         return [[self _webView] isEditable] && [self _canEditRichly];
2167     } else if (action == @selector(copy:)) {
2168         return [bridge mayDHTMLCopy] || [self _canCopy];
2169     } else if (action == @selector(cut:)) {
2170         return [bridge mayDHTMLCut] || [self _canDelete];
2171     } else if (action == @selector(delete:)) {
2172         return [self _canDelete];
2173     } else if (action == @selector(_ignoreSpellingFromMenu:)
2174             || action == @selector(_learnSpellingFromMenu:)
2175             || action == @selector(takeFindStringFromSelection:)) {
2176         return [self _hasSelection];
2177     } else if (action == @selector(paste:) || action == @selector(pasteAsPlainText:)) {
2178         return [bridge mayDHTMLPaste] || [self _canPaste];
2179     } else if (action == @selector(pasteAsRichText:)) {
2180         return [bridge mayDHTMLPaste] || ([self _canPaste] && [[self _bridge] isSelectionRichlyEditable]);
2181     } else if (action == @selector(performFindPanelAction:)) {
2182         // FIXME: Not yet implemented.
2183         return NO;
2184     } else if (action == @selector(selectToMark:)
2185             || action == @selector(swapWithMark:)) {
2186         return [self _hasSelectionOrInsertionPoint] && [[self _bridge] markDOMRange] != nil;
2187     } else if (action == @selector(subscript:)) {
2188         NSMenuItem *menuItem = (NSMenuItem *)item;
2189         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2190             DOMCSSStyleDeclaration *style = [self _emptyStyle];
2191             [style setVerticalAlign:@"sub"];
2192             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
2193         }
2194         return [self _canEditRichly];
2195     } else if (action == @selector(superscript:)) {
2196         NSMenuItem *menuItem = (NSMenuItem *)item;
2197         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2198             DOMCSSStyleDeclaration *style = [self _emptyStyle];
2199             [style setVerticalAlign:@"super"];
2200             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
2201         }
2202         return [self _canEditRichly];
2203     } else if (action == @selector(underline:)) {
2204         NSMenuItem *menuItem = (NSMenuItem *)item;
2205         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2206             DOMCSSStyleDeclaration *style = [self _emptyStyle];
2207             [style setProperty:@"-khtml-text-decorations-in-effect" :@"underline" :@""];
2208             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
2209         }
2210         return [self _canEditRichly];
2211     } else if (action == @selector(unscript:)) {
2212         NSMenuItem *menuItem = (NSMenuItem *)item;
2213         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2214             DOMCSSStyleDeclaration *style = [self _emptyStyle];
2215             [style setVerticalAlign:@"baseline"];
2216             [menuItem setState:[[self _bridge] selectionHasStyle:style]];
2217         }
2218         return [self _canEditRichly];
2219     } else if (action == @selector(_lookUpInDictionaryFromMenu:)) {
2220         return [self _hasSelection];
2221     }
2222     
2223     return YES;
2224 }
2225
2226 - (BOOL)acceptsFirstResponder
2227 {
2228     // Don't accept first responder when we first click on this view.
2229     // We have to pass the event down through WebCore first to be sure we don't hit a subview.
2230     // Do accept first responder at any other time, for example from keyboard events,
2231     // or from calls back from WebCore once we begin mouse-down event handling.
2232     NSEvent *event = [NSApp currentEvent];
2233     if ([event type] == NSLeftMouseDown
2234             && !_private->handlingMouseDownEvent
2235             && NSPointInRect([event locationInWindow], [self convertRect:[self visibleRect] toView:nil])) {
2236         return NO;
2237     }
2238     return YES;
2239 }
2240
2241 - (BOOL)maintainsInactiveSelection
2242 {
2243     // This method helps to determine whether the WebHTMLView should maintain
2244     // an inactive selection when it's not first responder.
2245     // Traditionally, these views have not maintained such selections,
2246     // clearing them when the view was not first responder. However,
2247     // to fix bugs like this one:
2248     // <rdar://problem/3672088>: "Editable WebViews should maintain a selection even 
2249     //                            when they're not firstResponder"
2250     // it was decided to add a switch to act more like an NSTextView.
2251     id nextResponder = [[self window] _newFirstResponderAfterResigning];
2252
2253     // Predict the case where we are losing first responder status only to
2254     // gain it back again.  Want to keep the selection in that case.
2255     if ([nextResponder isKindOfClass:[NSScrollView class]]) {
2256         id contentView = [nextResponder contentView];
2257         if (contentView) {
2258             nextResponder = contentView;
2259         }
2260     }
2261     if ([nextResponder isKindOfClass:[NSClipView class]]) {
2262         id documentView = [nextResponder documentView];
2263         if (documentView) {
2264             nextResponder = documentView;
2265         }
2266     }
2267
2268     if (nextResponder == self)
2269         return YES;
2270
2271     return [[self _webView] maintainsInactiveSelection] || [[self _bridge] isSelectionEditable];
2272 }
2273
2274 - (void)addMouseMovedObserver
2275 {
2276     if (!_private->dataSource || ![self _isTopHTMLView])
2277         return;
2278
2279     // Unless the Dashboard asks us to do this for all windows, keep an observer going only for the key window.
2280     if (!([[self window] isKeyWindow] || [[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows]))
2281         return;
2282
2283     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mouseMovedNotification:)
2284         name:WKMouseMovedNotification() object:nil];
2285     [self _frameOrBoundsChanged];
2286 }
2287
2288 - (void)removeMouseMovedObserver
2289 {
2290     // Don't remove the observer if we're running the Dashboard.
2291     // FIXME: Right for the windowDidResignKey: case, but wrong for the viewWillMoveToWindow: case.
2292     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows])
2293         return;
2294
2295     [[self _webView] _mouseDidMoveOverElement:nil modifierFlags:0];
2296     [[NSNotificationCenter defaultCenter] removeObserver:self
2297         name:WKMouseMovedNotification() object:nil];
2298 }
2299
2300 - (void)addSuperviewObservers
2301 {
2302     // We watch the bounds of our superview, so that we can do a layout when the size
2303     // of the superview changes. This is different from other scrollable things that don't
2304     // need this kind of thing because their layout doesn't change.
2305     
2306     // We need to pay attention to both height and width because our "layout" has to change
2307     // to extend the background the full height of the space and because some elements have
2308     // sizes that are based on the total size of the view.
2309     
2310     NSView *superview = [self superview];
2311     if (superview && [self window]) {
2312         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_frameOrBoundsChanged) 
2313             name:NSViewFrameDidChangeNotification object:superview];
2314         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_frameOrBoundsChanged) 
2315             name:NSViewBoundsDidChangeNotification object:superview];
2316
2317         // In addition to registering for frame/bounds change notifications, call -_frameOrBoundsChanged.
2318         // It will check the current size/scroll against the previous layout's size/scroll.  We need to
2319         // do this here to catch the case where the WebView is laid out at one size, removed from its
2320         // window, resized, and inserted into another window.  Our frame/bounds changed notifications
2321         // will not be sent in that situation, since we only watch for changes while in the view hierarchy.
2322         [self _frameOrBoundsChanged];
2323     }
2324 }
2325
2326 - (void)removeSuperviewObservers
2327 {
2328     NSView *superview = [self superview];
2329     if (superview && [self window]) {
2330         [[NSNotificationCenter defaultCenter] removeObserver:self
2331             name:NSViewFrameDidChangeNotification object:superview];
2332         [[NSNotificationCenter defaultCenter] removeObserver:self
2333             name:NSViewBoundsDidChangeNotification object:superview];
2334     }
2335 }
2336
2337 - (void)addWindowObservers
2338 {
2339     NSWindow *window = [self window];
2340     if (window) {
2341         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeKey:)
2342             name:NSWindowDidBecomeKeyNotification object:nil];
2343         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResignKey:)
2344             name:NSWindowDidResignKeyNotification object:nil];
2345         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillClose:)
2346             name:NSWindowWillCloseNotification object:window];
2347     }
2348 }
2349
2350 - (void)removeWindowObservers
2351 {
2352     NSWindow *window = [self window];
2353     if (window) {
2354         [[NSNotificationCenter defaultCenter] removeObserver:self
2355             name:NSWindowDidBecomeKeyNotification object:nil];
2356         [[NSNotificationCenter defaultCenter] removeObserver:self
2357             name:NSWindowDidResignKeyNotification object:nil];
2358         [[NSNotificationCenter defaultCenter] removeObserver:self
2359             name:NSWindowWillCloseNotification object:window];
2360     }
2361 }
2362
2363 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
2364 {
2365     [self removeSuperviewObservers];
2366 }
2367
2368 - (void)viewDidMoveToSuperview
2369 {
2370     // Do this here in case the text size multiplier changed when a non-HTML
2371     // view was installed.
2372     if ([self superview] != nil) {
2373         [self _updateTextSizeMultiplier];
2374         [self addSuperviewObservers];
2375     }
2376 }
2377
2378 - (void)viewWillMoveToWindow:(NSWindow *)window
2379 {
2380     // Don't do anything if we aren't initialized.  This happens
2381     // when decoding a WebView.  When WebViews are decoded their subviews
2382     // are created by initWithCoder: and so won't be normally
2383     // initialized.  The stub views are discarded by WebView.
2384     if (_private) {
2385         // FIXME: Some of these calls may not work because this view may be already removed from it's superview.
2386         [self removeMouseMovedObserver];
2387         [self removeWindowObservers];
2388         [self removeSuperviewObservers];
2389         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_updateMouseoverWithFakeEvent) object:nil];
2390     
2391         [[self _pluginController] stopAllPlugins];
2392     }
2393 }
2394
2395 - (void)viewDidMoveToWindow
2396 {
2397     // Don't do anything if we aren't initialized.  This happens
2398     // when decoding a WebView.  When WebViews are decoded their subviews
2399     // are created by initWithCoder: and so won't be normally
2400     // initialized.  The stub views are discarded by WebView.
2401     if (_private) {
2402         [self _stopAutoscrollTimer];
2403         if ([self window]) {
2404             _private->lastScrollPosition = [[self superview] bounds].origin;
2405             [self addWindowObservers];
2406             [self addSuperviewObservers];
2407             [self addMouseMovedObserver];
2408
2409             // Schedule this update, rather than making the call right now.
2410             // The reason is that placing the caret in the just-installed view requires
2411             // the HTML/XML document to be available on the WebCore side, but it is not
2412             // at the time this code is running. However, it will be there on the next
2413             // crank of the run loop. Doing this helps to make a blinking caret appear 
2414             // in a new, empty window "automatic".
2415             [self performSelector:@selector(_updateActiveState) withObject:nil afterDelay:0];
2416
2417             [[self _pluginController] startAllPlugins];
2418     
2419             _private->lastScrollPosition = NSZeroPoint;
2420         }
2421     }
2422 }
2423
2424 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
2425 {
2426     [[self subviews] _web_makePluginViewsPerformSelector:@selector(viewWillMoveToHostWindow:) withObject:hostWindow];
2427 }
2428
2429 - (void)viewDidMoveToHostWindow
2430 {
2431     [[self subviews] _web_makePluginViewsPerformSelector:@selector(viewDidMoveToHostWindow) withObject:nil];
2432 }
2433
2434
2435 - (void)addSubview:(NSView *)view
2436 {
2437     [super addSubview:view];
2438
2439     if ([WebPluginController isPlugInView:view]) {
2440         [[self _pluginController] addPlugin:view];
2441     }
2442 }
2443
2444 - (void)willRemoveSubview:(NSView *)subview
2445 {
2446     if ([WebPluginController isPlugInView:subview])
2447         [[self _pluginController] destroyPlugin:subview];
2448     [super willRemoveSubview:subview];
2449 }
2450
2451 - (void)reapplyStyles
2452 {
2453     if (!_private->needsToApplyStyles) {
2454         return;
2455     }
2456     
2457 #ifdef _KWQ_TIMING        
2458     double start = CFAbsoluteTimeGetCurrent();
2459 #endif
2460
2461     [[self _bridge] reapplyStylesForDeviceType:
2462         _private->printing ? WebCoreDevicePrinter : WebCoreDeviceScreen];
2463     
2464 #ifdef _KWQ_TIMING        
2465     double thisTime = CFAbsoluteTimeGetCurrent() - start;
2466     LOG(Timing, "%s apply style seconds = %f", [self URL], thisTime);
2467 #endif
2468
2469     _private->needsToApplyStyles = NO;
2470 }
2471
2472 // Do a layout, but set up a new fixed width for the purposes of doing printing layout.
2473 // minPageWidth==0 implies a non-printing layout
2474 - (void)layoutToMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)adjustViewSize
2475 {
2476     [self reapplyStyles];
2477     
2478     // Ensure that we will receive mouse move events.  Is this the best place to put this?
2479     [[self window] setAcceptsMouseMovedEvents: YES];
2480     WKSetNSWindowShouldPostEventNotifications([self window], YES);
2481
2482     if (!_private->needsLayout) {
2483         return;
2484     }
2485
2486 #ifdef _KWQ_TIMING        
2487     double start = CFAbsoluteTimeGetCurrent();
2488 #endif
2489
2490     LOG(View, "%@ doing layout", self);
2491
2492     if (minPageWidth > 0.0) {
2493         [[self _bridge] forceLayoutWithMinimumPageWidth:minPageWidth maximumPageWidth:maxPageWidth adjustingViewSize:adjustViewSize];
2494     } else {
2495         [[self _bridge] forceLayoutAdjustingViewSize:adjustViewSize];
2496     }
2497     _private->needsLayout = NO;
2498     
2499     if (!_private->printing) {
2500         // get size of the containing dynamic scrollview, so
2501         // appearance and disappearance of scrollbars will not show up
2502         // as a size change
2503         NSSize newLayoutFrameSize = [[[self superview] superview] frame].size;
2504         if (_private->laidOutAtLeastOnce && !NSEqualSizes(_private->lastLayoutFrameSize, newLayoutFrameSize)) {
2505             [[self _bridge] sendResizeEvent];
2506             if ([[self _bridge] needsLayout])
2507                 [[self _bridge] forceLayoutAdjustingViewSize:NO];
2508         }
2509         _private->laidOutAtLeastOnce = YES;
2510         _private->lastLayoutSize = [(NSClipView *)[self superview] documentVisibleRect].size;
2511         _private->lastLayoutFrameSize = newLayoutFrameSize;
2512     }
2513
2514 #ifdef _KWQ_TIMING        
2515     double thisTime = CFAbsoluteTimeGetCurrent() - start;
2516     LOG(Timing, "%s layout seconds = %f", [self URL], thisTime);
2517 #endif
2518 }
2519
2520 - (void)layout
2521 {
2522     [self layoutToMinimumPageWidth:0.0f maximumPageWidth:0.0f adjustingViewSize:NO];
2523 }
2524
2525 - (NSMenu *)menuForEvent:(NSEvent *)event
2526 {
2527     [_private->compController endRevertingChange:NO moveLeft:NO];
2528
2529     _private->handlingMouseDownEvent = YES;
2530     BOOL handledEvent = [[self _bridge] sendContextMenuEvent:event];
2531     _private->handlingMouseDownEvent = NO;
2532     if (handledEvent)
2533         return nil;
2534
2535     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
2536     NSDictionary *element = [self elementAtPoint:point];
2537     return [[self _webView] _menuForElement:element defaultItems:nil];
2538 }
2539
2540 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2541 {
2542     if (![string length])
2543         return NO;
2544
2545     return [[self _bridge] searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag];
2546 }
2547
2548 - (void)deselectText
2549 {
2550     [[self _bridge] deselectText];
2551 }
2552
2553 - (BOOL)isOpaque
2554 {
2555     return [[self _webView] drawsBackground];
2556 }
2557
2558 - (void)setNeedsDisplay:(BOOL)flag
2559 {
2560     LOG(View, "%@ flag = %d", self, (int)flag);
2561     [super setNeedsDisplay: flag];
2562 }
2563
2564 - (void)setNeedsLayout: (BOOL)flag
2565 {
2566     LOG(View, "%@ flag = %d", self, (int)flag);
2567     _private->needsLayout = flag;
2568 }
2569
2570
2571 - (void)setNeedsToApplyStyles: (BOOL)flag
2572 {
2573     LOG(View, "%@ flag = %d", self, (int)flag);
2574     _private->needsToApplyStyles = flag;
2575 }
2576
2577 - (void)drawSingleRect:(NSRect)rect
2578 {
2579     [NSGraphicsContext saveGraphicsState];
2580     NSRectClip(rect);
2581         
2582     ASSERT([[self superview] isKindOfClass:[WebClipView class]]);
2583
2584     [(WebClipView *)[self superview] setAdditionalClip:rect];
2585
2586     NS_DURING {
2587         if ([self _transparentBackground]) {
2588             [[NSColor clearColor] set];
2589             NSRectFill (rect);
2590         }
2591         
2592         [[self _bridge] drawRect:rect];        
2593         WebView *webView = [self _webView];
2594         [[webView _UIDelegateForwarder] webView:webView didDrawRect:[webView convertRect:rect fromView:self]];
2595         [(WebClipView *)[self superview] resetAdditionalClip];
2596
2597         [NSGraphicsContext restoreGraphicsState];
2598     } NS_HANDLER {
2599         [(WebClipView *)[self superview] resetAdditionalClip];
2600         [NSGraphicsContext restoreGraphicsState];
2601         LOG_ERROR("Exception caught while drawing: %@", localException);
2602         [localException raise];
2603     } NS_ENDHANDLER
2604 }
2605
2606 - (void)drawRect:(NSRect)rect
2607 {
2608     LOG(View, "%@ drawing", self);
2609
2610     const NSRect *rects;
2611     WebNSInteger count;
2612     [self getRectsBeingDrawn:&rects count:&count];
2613
2614     BOOL subviewsWereSetAside = _private->subviewsSetAside;
2615     if (subviewsWereSetAside)
2616         [self _restoreSubviews];
2617
2618 #ifdef _KWQ_TIMING
2619     double start = CFAbsoluteTimeGetCurrent();
2620 #endif
2621
2622     // If count == 0 here, use the rect passed in for drawing. This is a workaround for:
2623     // <rdar://problem/3908282> REGRESSION (Mail): No drag image dragging selected text in Blot and Mail
2624     // The reason for the workaround is that this method is called explicitly from the code
2625     // to generate a drag image, and at that time, getRectsBeingDrawn:count: will return a zero count.
2626     const int cRectThreshold = 10;
2627     const float cWastedSpaceThreshold = 0.75f;
2628     BOOL useUnionedRect = (count <= 1) || (count > cRectThreshold);
2629     if (!useUnionedRect) {
2630         // Attempt to guess whether or not we should use the unioned rect or the individual rects.
2631         // We do this by computing the percentage of "wasted space" in the union.  If that wasted space
2632         // is too large, then we will do individual rect painting instead.
2633         float unionPixels = (rect.size.width * rect.size.height);
2634         float singlePixels = 0;
2635         for (int i = 0; i < count; ++i)
2636             singlePixels += rects[i].size.width * rects[i].size.height;
2637         float wastedSpace = 1 - (singlePixels / unionPixels);
2638         if (wastedSpace <= cWastedSpaceThreshold)
2639             useUnionedRect = YES;
2640     }
2641     
2642     if (useUnionedRect)
2643         [self drawSingleRect:rect];
2644     else
2645         for (int i = 0; i < count; ++i)
2646             [self drawSingleRect:rects[i]];
2647
2648 #ifdef _KWQ_TIMING
2649     double thisTime = CFAbsoluteTimeGetCurrent() - start;
2650     LOG(Timing, "%s draw seconds = %f", widget->part()->baseURL().URL().latin1(), thisTime);
2651 #endif
2652
2653     if (subviewsWereSetAside)
2654         [self _setAsideSubviews];
2655 }
2656
2657 // Turn off the additional clip while computing our visibleRect.
2658 - (NSRect)visibleRect
2659 {
2660     if (!([[self superview] isKindOfClass:[WebClipView class]]))
2661         return [super visibleRect];
2662         
2663     WebClipView *clipView = (WebClipView *)[self superview];
2664
2665     BOOL hasAdditionalClip = [clipView hasAdditionalClip];
2666     if (!hasAdditionalClip) {
2667         return [super visibleRect];
2668     }
2669     
2670     NSRect additionalClip = [clipView additionalClip];
2671     [clipView resetAdditionalClip];
2672     NSRect visibleRect = [super visibleRect];
2673     [clipView setAdditionalClip:additionalClip];
2674     return visibleRect;
2675 }
2676
2677 - (BOOL)isFlipped 
2678 {
2679     return YES;
2680 }
2681
2682 - (void)windowDidBecomeKey:(NSNotification *)notification
2683 {
2684     NSWindow *keyWindow = [notification object];
2685
2686     if (keyWindow == [self window])
2687         [self addMouseMovedObserver];
2688
2689     if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet])
2690         [self _updateActiveState];
2691 }
2692
2693 - (void)windowDidResignKey:(NSNotification *)notification
2694 {
2695     NSWindow *formerKeyWindow = [notification object];
2696
2697     if (formerKeyWindow == [self window])
2698         [self removeMouseMovedObserver];
2699
2700     if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) {
2701         [self _updateActiveState];
2702         [_private->compController endRevertingChange:NO moveLeft:NO];
2703     }
2704 }
2705
2706 - (void)windowWillClose:(NSNotification *)notification
2707 {
2708     [_private->compController endRevertingChange:NO moveLeft:NO];
2709     [[self _pluginController] destroyAllPlugins];
2710 }
2711
2712 - (void)scrollWheel:(NSEvent *)event
2713 {
2714     [self retain];
2715     
2716     if (![[self _bridge] sendScrollWheelEvent:event]) {
2717         [[self nextResponder] scrollWheel:event];
2718     }    
2719     
2720     [self release];
2721 }
2722
2723 - (BOOL)_isSelectionEvent:(NSEvent *)event
2724 {
2725     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
2726     return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsSelectedKey] boolValue];
2727 }
2728
2729 - (BOOL)acceptsFirstMouse:(NSEvent *)event
2730 {
2731     NSView *hitView = [self _hitViewForEvent:event];
2732     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
2733     
2734     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysAcceptsFirstMouse])
2735         return YES;
2736     
2737     if (hitHTMLView != nil) {
2738         [hitHTMLView _setMouseDownEvent:event];
2739         [[hitHTMLView _bridge] setActivationEventNumber:[event eventNumber]];
2740         BOOL result = [hitHTMLView _isSelectionEvent:event] ? [[hitHTMLView _bridge] eventMayStartDrag:event] : NO;
2741         [hitHTMLView _setMouseDownEvent:nil];
2742         return result;
2743     } else
2744         return [hitView acceptsFirstMouse:event];
2745 }
2746
2747 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
2748 {
2749     NSView *hitView = [self _hitViewForEvent:event];
2750     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
2751     if (hitHTMLView != nil) {
2752         [hitHTMLView _setMouseDownEvent:event];
2753         BOOL result = [hitHTMLView _isSelectionEvent:event] ? [[hitHTMLView _bridge] eventMayStartDrag:event] : NO;
2754         [hitHTMLView _setMouseDownEvent:nil];
2755         return result;
2756     } else
2757         return [hitView shouldDelayWindowOrderingForEvent:event];
2758 }
2759
2760 - (void)mouseDown:(NSEvent *)event
2761 {
2762     [self retain];
2763
2764     _private->handlingMouseDownEvent = YES;
2765
2766     // Record the mouse down position so we can determine drag hysteresis.
2767     [self _setMouseDownEvent:event];
2768
2769     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
2770     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
2771         goto done;
2772
2773     [_private->compController endRevertingChange:NO moveLeft:NO];
2774
2775     // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here.
2776     // We don't want to pass them along to KHTML a second time.
2777     if (!([event modifierFlags] & NSControlKeyMask)) {
2778         _private->ignoringMouseDraggedEvents = NO;
2779
2780         // Don't do any mouseover while the mouse is down.
2781         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_updateMouseoverWithFakeEvent) object:nil];
2782
2783         // Let KHTML get a chance to deal with the event. This will call back to us
2784         // to start the autoscroll timer if appropriate.
2785         [[self _bridge] mouseDown:event];
2786     }
2787
2788 done:
2789     [_private->firstResponderTextViewAtMouseDownTime release];
2790     _private->firstResponderTextViewAtMouseDownTime = nil;
2791
2792     _private->handlingMouseDownEvent = NO;
2793     
2794     [self release];
2795 }
2796
2797 - (void)dragImage:(NSImage *)dragImage
2798                at:(NSPoint)at
2799            offset:(NSSize)offset
2800             event:(NSEvent *)event
2801        pasteboard:(NSPasteboard *)pasteboard
2802            source:(id)source
2803         slideBack:(BOOL)slideBack
2804 {
2805     [self _stopAutoscrollTimer];
2806
2807     WebHTMLView *topHTMLView = [self _topHTMLView];
2808     if (self != topHTMLView) {
2809         [topHTMLView dragImage:dragImage at:[self convertPoint:at toView:topHTMLView]
2810             offset:offset event:event pasteboard:pasteboard source:source slideBack:slideBack];
2811         return;
2812     }
2813
2814     WebView *webView = [self _webView];
2815
2816     _private->initiatedDrag = YES;
2817     [webView _setInitiatedDrag:YES];
2818
2819     // Retain this view during the drag because it may be released before the drag ends.
2820     [self retain];
2821
2822     id UIDelegate = [webView UIDelegate];
2823     // If a delegate takes over the drag but never calls draggedImage: endedAt:, we'll leak the WebHTMLView.
2824     if ([UIDelegate respondsToSelector:@selector(webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:)])
2825         [UIDelegate webView:webView dragImage:dragImage at:at offset:offset event:event pasteboard:pasteboard source:source slideBack:slideBack forView:self];
2826     else
2827         [super dragImage:dragImage at:at offset:offset event:event pasteboard:pasteboard source:source slideBack:slideBack];
2828 }
2829
2830 - (void)mouseDragged:(NSEvent *)event
2831 {
2832     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
2833     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
2834         return;
2835
2836     [self retain];
2837
2838     if (!_private->ignoringMouseDraggedEvents)
2839         [[self _bridge] mouseDragged:event];
2840
2841     [self release];
2842 }
2843
2844 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
2845 {
2846     ASSERT([self _isTopHTMLView]);
2847
2848     if (_private->webCoreDragOp == NSDragOperationNone)
2849         return NSDragOperationGeneric | NSDragOperationCopy;
2850     return _private->webCoreDragOp;
2851 }
2852
2853 - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenLoc
2854 {
2855     ASSERT([self _isTopHTMLView]);
2856
2857     NSPoint windowImageLoc = [[self window] convertScreenToBase:screenLoc];
2858     NSPoint windowMouseLoc = NSMakePoint(windowImageLoc.x + _private->dragOffset.x, windowImageLoc.y + _private->dragOffset.y);
2859     [[self _bridge] dragSourceMovedTo:windowMouseLoc];
2860 }
2861
2862 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
2863 {
2864     ASSERT(![self _webView] || [self _isTopHTMLView]);
2865
2866     NSPoint windowImageLoc = [[self window] convertScreenToBase:aPoint];
2867     NSPoint windowMouseLoc = NSMakePoint(windowImageLoc.x + _private->dragOffset.x, windowImageLoc.y + _private->dragOffset.y);
2868     [[self _bridge] dragSourceEndedAt:windowMouseLoc operation:operation];
2869
2870     _private->initiatedDrag = NO;
2871     [[self _webView] _setInitiatedDrag:NO];
2872     
2873     // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event.
2874     _private->ignoringMouseDraggedEvents = YES;
2875     
2876     // Once the dragging machinery kicks in, we no longer get mouse drags or the up event.
2877     // WebCore expects to get balanced down/up's, so we must fake up a mouseup.
2878     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
2879                                             location:windowMouseLoc
2880                                        modifierFlags:[[NSApp currentEvent] modifierFlags]
2881                                            timestamp:[NSDate timeIntervalSinceReferenceDate]
2882                                         windowNumber:[[self window] windowNumber]
2883                                              context:[[NSApp currentEvent] context]
2884                                          eventNumber:0 clickCount:0 pressure:0];
2885     [self mouseUp:fakeEvent]; // This will also update the mouseover state.
2886     
2887     // Balance the previous retain from when the drag started.
2888     [self release];
2889 }
2890
2891 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
2892 {
2893     ASSERT([self _isTopHTMLView]);
2894     ASSERT(_private->draggingImageURL);
2895
2896     NSFileWrapper *wrapper = [[self _dataSource] _fileWrapperForURL:_private->draggingImageURL];
2897     if (wrapper == nil) {
2898         LOG_ERROR("Failed to create image file. Did the source image change while dragging? (<rdar://problem/4244861>)");
2899         return nil;
2900     }
2901
2902     // FIXME: Report an error if we fail to create a file.
2903     NSString *path = [[dropDestination path] stringByAppendingPathComponent:[wrapper preferredFilename]];
2904     path = [[NSFileManager defaultManager] _webkit_pathWithUniqueFilenameForPath:path];
2905     if (![wrapper writeToFile:path atomically:NO updateFilenames:YES])
2906         LOG_ERROR("Failed to create image file via -[NSFileWrapper writeToFile:atomically:updateFilenames:]");
2907
2908     return [NSArray arrayWithObject:[path lastPathComponent]];
2909 }
2910
2911 - (void)mouseUp:(NSEvent *)event
2912 {
2913     [self _setMouseDownEvent:nil];
2914
2915     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
2916     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
2917         return;
2918
2919     [self retain];
2920
2921     [self _stopAutoscrollTimer];
2922     [[self _bridge] mouseUp:event];
2923     [self _updateMouseoverWithFakeEvent];
2924
2925     [self release];
2926 }
2927
2928 - (void)mouseMovedNotification:(NSNotification *)notification
2929 {
2930     [self _updateMouseoverWithEvent:[[notification userInfo] objectForKey:@"NSEvent"]];
2931 }
2932
2933 // returning YES from this method is the way we tell AppKit that it is ok for this view
2934 // to be in the key loop even when "tab to all controls" is not on.
2935 - (BOOL)needsPanelToBecomeKey
2936 {
2937     return YES;
2938 }
2939
2940 - (NSView *)nextValidKeyView
2941 {
2942     NSView *view = nil;
2943     BOOL lookInsideWebFrameViews = YES;
2944     if ([self isHiddenOrHasHiddenAncestor]) {
2945         lookInsideWebFrameViews = NO;
2946     } else if ([self _frame] == [[self _webView] mainFrame]) {
2947         // Check for case where first responder is last frame in a frameset, and we are
2948         // the top-level documentView.
2949         NSResponder *firstResponder = [[self window] firstResponder];
2950         if ((firstResponder != self) && [firstResponder isKindOfClass:[WebHTMLView class]] && ([(NSView *)firstResponder nextKeyView] == nil)) {
2951             lookInsideWebFrameViews = NO;
2952         }
2953     }
2954     
2955     if (lookInsideWebFrameViews) {
2956         view = [[self _bridge] nextKeyViewInsideWebFrameViews];
2957     }
2958     
2959     if (view == nil) {
2960         view = [super nextValidKeyView];
2961         // If there's no next view wired up, we must be in the last subframe, or we are
2962         // being called at an unusual time when the views have not yet been wired together.
2963         // There's no direct link to the next valid key view; get it from the bridge.
2964         // Note that view == self here when nextKeyView returns nil, due to AppKit oddness.
2965         // We'll check for both nil and self in case the AppKit oddness goes away.
2966         // WebFrameView has this same kind of logic for the previousValidKeyView case.
2967         if (view == nil || view == self) {
2968             view = [[self _bridge] nextValidKeyViewOutsideWebFrameViews];
2969         }
2970     }
2971         
2972     return view;
2973 }
2974
2975 - (NSView *)previousValidKeyView
2976 {
2977     NSView *view = nil;
2978     if (![self isHiddenOrHasHiddenAncestor])
2979         view = [[self _bridge] previousKeyViewInsideWebFrameViews];
2980     if (view == nil)
2981         view = [super previousValidKeyView];
2982     return view;
2983 }
2984
2985 - (BOOL)becomeFirstResponder
2986 {
2987     NSView *view = nil;
2988     if (![[self _webView] _isPerformingProgrammaticFocus] && !_private->willBecomeFirstResponderForNodeFocus) {
2989         switch ([[self window] keyViewSelectionDirection]) {
2990             case NSDirectSelection:
2991                 break;
2992             case NSSelectingNext:
2993                 view = [[self _bridge] nextKeyViewInsideWebFrameViews];
2994                 break;
2995             case NSSelectingPrevious:
2996                 view = [[self _bridge] previousKeyViewInsideWebFrameViews];
2997                 break;
2998         }
2999     }
3000     _private->willBecomeFirstResponderForNodeFocus = NO;
3001     if (view)
3002         [[self window] makeFirstResponder:view];
3003     [self _updateActiveState];
3004     [self _updateFontPanel];
3005     _private->startNewKillRingSequence = YES;
3006     return YES;
3007 }
3008
3009 - (BOOL)resignFirstResponder
3010 {
3011     BOOL resign = [super resignFirstResponder];
3012     if (resign) {
3013         [_private->compController endRevertingChange:NO moveLeft:NO];
3014         _private->resigningFirstResponder = YES;
3015         if (![self maintainsInactiveSelection]) { 
3016             if ([[self _webView] _isPerformingProgrammaticFocus])
3017                 [self deselectText];
3018             else
3019                 [self deselectAll];
3020         }
3021         [self _updateActiveState];
3022         _private->resigningFirstResponder = NO;
3023         _private->willBecomeFirstResponderForNodeFocus = NO;
3024     }
3025     return resign;
3026 }
3027
3028 - (void)setDataSource:(WebDataSource *)dataSource 
3029 {
3030     ASSERT(!_private->dataSource);
3031     _private->dataSource = [dataSource retain];
3032     [_private->pluginController setDataSource:dataSource];
3033     [self addMouseMovedObserver];
3034 }
3035
3036 - (void)dataSourceUpdated:(WebDataSource *)dataSource
3037 {
3038 }
3039
3040 // This is an override of an NSControl method that wants to repaint the entire view when the window resigns/becomes
3041 // key.  WebHTMLView is an NSControl only because it hosts NSCells that are painted by WebCore's Aqua theme
3042 // renderer (and those cells must be hosted by an enclosing NSControl in order to paint properly).
3043 - (void)updateCell:(NSCell*)cell
3044 {
3045 }
3046
3047 // Does setNeedsDisplay:NO as a side effect when printing is ending.
3048 // pageWidth != 0 implies we will relayout to a new width
3049 - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize
3050 {
3051     WebFrame *frame = [self _frame];
3052     NSArray *subframes = [frame childFrames];
3053     unsigned n = [subframes count];
3054     unsigned i;
3055     for (i = 0; i != n; ++i) {
3056         WebFrame *subframe = [subframes objectAtIndex:i];
3057         WebFrameView *frameView = [subframe frameView];
3058         if ([[subframe dataSource] _isDocumentHTML]) {
3059             [(WebHTMLView *)[frameView documentView] _setPrinting:printing minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:adjustViewSize];
3060         }
3061     }
3062
3063     if (printing != _private->printing) {
3064         [_private->pageRects release];
3065         _private->pageRects = nil;
3066         _private->printing = printing;
3067         [self setNeedsToApplyStyles:YES];
3068         [self setNeedsLayout:YES];
3069         [self layoutToMinimumPageWidth:minPageWidth maximumPageWidth:maxPageWidth adjustingViewSize:adjustViewSize];
3070         if (!printing) {
3071             // Can't do this when starting printing or nested printing won't work, see 3491427.
3072             [self setNeedsDisplay:NO];
3073         }
3074     }
3075 }
3076
3077 - (BOOL)canPrintHeadersAndFooters
3078 {
3079     return YES;
3080 }
3081
3082 // This is needed for the case where the webview is embedded in the view that's being printed.
3083 // It shouldn't be called when the webview is being printed directly.
3084 - (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit
3085 {
3086     // This helps when we print as part of a larger print process.
3087     // If the WebHTMLView itself is what we're printing, then we will never have to do this.
3088     BOOL wasInPrintingMode = _private->printing;
3089     if (!wasInPrintingMode)
3090         [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
3091
3092     [[self _bridge] adjustPageHeightNew:newBottom top:oldTop bottom:oldBottom limit:bottomLimit];
3093     
3094     if (!wasInPrintingMode)
3095         [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
3096 }
3097
3098 - (float)_availablePaperWidthForPrintOperation:(NSPrintOperation *)printOperation
3099 {
3100     NSPrintInfo *printInfo = [printOperation printInfo];
3101     return [printInfo paperSize].width - [printInfo leftMargin] - [printInfo rightMargin];
3102 }
3103
3104 - (float)_scaleFactorForPrintOperation:(NSPrintOperation *)printOperation
3105 {
3106     float viewWidth = NSWidth([self bounds]);
3107     if (viewWidth < 1) {
3108         LOG_ERROR("%@ has no width when printing", self);
3109         return 1.0f;
3110     }
3111
3112     float userScaleFactor = [printOperation _web_pageSetupScaleFactor];
3113     float maxShrinkToFitScaleFactor = 1.0f / PrintingMaximumShrinkFactor;
3114     float shrinkToFitScaleFactor = [self _availablePaperWidthForPrintOperation:printOperation]/viewWidth;
3115     return userScaleFactor * MAX(maxShrinkToFitScaleFactor, shrinkToFitScaleFactor);
3116 }
3117
3118 // FIXME 3491344: This is a secret AppKit-internal method that we need to override in order
3119 // to get our shrink-to-fit to work with a custom pagination scheme. We can do this better
3120 // if AppKit makes it SPI/API.
3121 - (float)_provideTotalScaleFactorForPrintOperation:(NSPrintOperation *)printOperation 
3122 {
3123     return [self _scaleFactorForPrintOperation:printOperation];
3124 }
3125
3126 // This is used for Carbon printing. At some point we might want to make this public API.
3127 - (void)setPageWidthForPrinting:(float)pageWidth
3128 {
3129     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
3130     [self _setPrinting:YES minimumPageWidth:pageWidth maximumPageWidth:pageWidth adjustViewSize:YES];
3131 }
3132
3133 - (void)_endPrintMode
3134 {
3135     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:YES];
3136     [[self window] setAutodisplay:YES];
3137 }
3138
3139 - (void)_delayedEndPrintMode:(NSPrintOperation *)initiatingOperation
3140 {
3141     ASSERT_ARG(initiatingOperation, initiatingOperation != nil);
3142     NSPrintOperation *currentOperation = [NSPrintOperation currentOperation];
3143     if (initiatingOperation == currentOperation) {
3144         // The print operation is still underway. We don't expect this to ever happen, hence the assert, but we're
3145         // being extra paranoid here since the printing code is so fragile. Delay the cleanup
3146         // further.
3147         ASSERT_NOT_REACHED();
3148         [self performSelector:@selector(_delayedEndPrintMode:) withObject:initiatingOperation afterDelay:0];
3149     } else if ([currentOperation view] == self) {
3150         // A new print job has started, but it is printing the same WebHTMLView again. We don't expect
3151         // this to ever happen, hence the assert, but we're being extra paranoid here since the printing code is so
3152         // fragile. Do nothing, because we don't want to break the print job currently in progress, and
3153         // the print job currently in progress is responsible for its own cleanup.
3154         ASSERT_NOT_REACHED();
3155     } else {
3156         // The print job that kicked off this delayed call has finished, and this view is not being
3157         // printed again. We expect that no other print job has started. Since this delayed call wasn't
3158         // cancelled, beginDocument and endDocument must not have been called, and we need to clean up
3159         // the print mode here.
3160         ASSERT(currentOperation == nil);
3161         [self _endPrintMode];
3162     }
3163 }
3164
3165 // Return the number of pages available for printing
3166 - (BOOL)knowsPageRange:(NSRangePointer)range
3167 {
3168     // Must do this explicit display here, because otherwise the view might redisplay while the print
3169     // sheet was up, using printer fonts (and looking different).
3170     [self displayIfNeeded];
3171     [[self window] setAutodisplay:NO];
3172     
3173     // If we are a frameset just print with the layout we have onscreen, otherwise relayout
3174     // according to the paper size
3175     float minLayoutWidth = 0.0f;
3176     float maxLayoutWidth = 0.0f;
3177     if (![[self _bridge] isFrameSet]) {
3178         float paperWidth = [self _availablePaperWidthForPrintOperation:[NSPrintOperation currentOperation]];
3179         minLayoutWidth = paperWidth * PrintingMinimumShrinkFactor;
3180         maxLayoutWidth = paperWidth * PrintingMaximumShrinkFactor;
3181     }
3182     [self _setPrinting:YES minimumPageWidth:minLayoutWidth maximumPageWidth:maxLayoutWidth adjustViewSize:YES]; // will relayout
3183     NSPrintOperation *printOperation = [NSPrintOperation currentOperation];
3184     // Certain types of errors, including invalid page ranges, can cause beginDocument and
3185     // endDocument to be skipped after we've put ourselves in print mode (see 4145905). In those cases
3186     // we need to get out of print mode without relying on any more callbacks from the printing mechanism.
3187     // If we get as far as beginDocument without trouble, then this delayed request will be cancelled.
3188     // If not cancelled, this delayed call will be invoked in the next pass through the main event loop,
3189     // which is after beginDocument and endDocument would be called.
3190     [self performSelector:@selector(_delayedEndPrintMode:) withObject:printOperation afterDelay:0];
3191     [[self _webView] _adjustPrintingMarginsForHeaderAndFooter];
3192     
3193     // There is a theoretical chance that someone could do some drawing between here and endDocument,
3194     // if something caused setNeedsDisplay after this point. If so, it's not a big tragedy, because
3195     // you'd simply see the printer fonts on screen. As of this writing, this does not happen with Safari.
3196
3197     range->location = 1;
3198     float totalScaleFactor = [self _scaleFactorForPrintOperation:printOperation];
3199     float userScaleFactor = [printOperation _web_pageSetupScaleFactor];
3200     [_private->pageRects release];
3201     NSArray *newPageRects = [[self _bridge] computePageRectsWithPrintWidthScaleFactor:userScaleFactor
3202                                                                           printHeight:floorf([self _calculatePrintHeight]/totalScaleFactor)];
3203     // AppKit gets all messed up if you give it a zero-length page count (see 3576334), so if we
3204     // hit that case we'll pass along a degenerate 1 pixel square to print. This will print
3205     // a blank page (with correct-looking header and footer if that option is on), which matches
3206     // the behavior of IE and Camino at least.
3207     if ([newPageRects count] == 0)
3208         newPageRects = [NSArray arrayWithObject:[NSValue valueWithRect:NSMakeRect(0, 0, 1, 1)]];
3209     _private->pageRects = [newPageRects retain];
3210     
3211     range->length = [_private->pageRects count];
3212     
3213     return YES;
3214 }
3215
3216 // Return the drawing rectangle for a particular page number
3217 - (NSRect)rectForPage:(int)page
3218 {
3219     return [[_private->pageRects objectAtIndex:page - 1] rectValue];
3220 }
3221
3222 - (void)drawPageBorderWithSize:(NSSize)borderSize
3223 {
3224     ASSERT(NSEqualSizes(borderSize, [[[NSPrintOperation currentOperation] printInfo] paperSize]));    
3225     [[self _webView] _drawHeaderAndFooter];
3226 }
3227
3228 - (void)beginDocument
3229 {
3230     NS_DURING
3231         // From now on we'll get a chance to call _endPrintMode in either beginDocument or
3232         // endDocument, so we can cancel the "just in case" pending call.
3233         [NSObject cancelPreviousPerformRequestsWithTarget:self
3234                                                  selector:@selector(_delayedEndPrintMode:)
3235                                                    object:[NSPrintOperation currentOperation]];
3236         [super beginDocument];
3237     NS_HANDLER
3238         // Exception during [super beginDocument] means that endDocument will not get called,
3239         // so we need to clean up our "print mode" here.
3240         [self _endPrintMode];
3241     NS_ENDHANDLER
3242 }
3243
3244 - (void)endDocument
3245 {
3246     [super endDocument];
3247     // Note sadly at this point [NSGraphicsContext currentContextDrawingToScreen] is still NO 
3248     [self _endPrintMode];
3249 }
3250
3251 - (BOOL)_interceptEditingKeyEvent:(NSEvent *)event
3252 {   
3253     // Use WebView's tabKeyCyclesThroughElements state to determine whether or not
3254     // to process tab key events. The idea here is that tabKeyCyclesThroughElements
3255     // will be YES when this WebView is being used in a browser, and we desire the
3256     // behavior where tab moves to the next element in tab order. If tabKeyCyclesThroughElements
3257     // is NO, it is likely that the WebView is being embedded as the whole view, as in Mail,
3258     // and tabs should input tabs as expected in a text editor. Using Option-Tab always cycles
3259     // through elements.
3260
3261     if ([[self _webView] tabKeyCyclesThroughElements] && [event _web_isTabKeyEvent]) 
3262         return NO;
3263
3264     if (![[self _webView] tabKeyCyclesThroughElements] && [event _web_isOptionTabKeyEvent])
3265         return NO;
3266
3267     // Now process the key normally
3268     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
3269     return YES;
3270 }
3271
3272 - (void)keyDown:(NSEvent *)event
3273 {
3274     [self retain];
3275
3276     BOOL callSuper = NO;
3277
3278     _private->keyDownEvent = event;
3279
3280     WebFrameBridge *bridge = [self _bridge];
3281     if ([bridge interceptKeyEvent:event toView:self]) {
3282         // WebCore processed a key event, bail on any outstanding complete: UI
3283         [_private->compController endRevertingChange:YES moveLeft:NO];
3284     } else if (_private->compController && [_private->compController filterKeyDown:event]) {
3285         // Consumed by complete: popup window
3286     } else {
3287         // We're going to process a key event, bail on any outstanding complete: UI
3288         [_private->compController endRevertingChange:YES moveLeft:NO];
3289         BOOL handledKey = [self _canEdit] && [self _interceptEditingKeyEvent:event];
3290         if (!handledKey)
3291             callSuper = YES;
3292     }
3293     if (callSuper)
3294         [super keyDown:event];
3295     else
3296         [NSCursor setHiddenUntilMouseMoves:YES];
3297
3298     _private->keyDownEvent = nil;
3299     
3300     [self release];
3301 }
3302
3303 - (void)keyUp:(NSEvent *)event
3304 {
3305     [self retain];
3306     if (![[self _bridge] interceptKeyEvent:event toView:self])
3307         [super keyUp:event];    
3308     [self release];
3309 }
3310
3311 - (id)accessibilityAttributeValue:(NSString*)attributeName
3312 {
3313     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
3314         id accTree = [[self _bridge] accessibilityTree];
3315         if (accTree)
3316             return [NSArray arrayWithObject:accTree];
3317         return nil;
3318     }
3319     return [super accessibilityAttributeValue:attributeName];
3320 }
3321
3322 - (id)accessibilityFocusedUIElement
3323 {
3324     id accTree = [[self _bridge] accessibilityTree];
3325     if (accTree)
3326         return [accTree accessibilityFocusedUIElement];
3327     return self;
3328 }
3329
3330 - (id)accessibilityHitTest:(NSPoint)point
3331 {
3332     id accTree = [[self _bridge] accessibilityTree];
3333     if (accTree) {
3334         NSPoint windowCoord = [[self window] convertScreenToBase:point];
3335         return [accTree accessibilityHitTest:[self convertPoint:windowCoord fromView:nil]];
3336     }
3337     return self;
3338 }
3339
3340 - (id)_accessibilityParentForSubview:(NSView *)subview
3341 {
3342     id accTree = [[self _bridge] accessibilityTree];
3343     if (!accTree)
3344         return self;
3345     id parent = [accTree _accessibilityParentForSubview:subview];
3346     if (!parent)
3347         return self;
3348     return parent;
3349 }
3350
3351 - (void)centerSelectionInVisibleArea:(id)sender
3352 {
3353     [[self _bridge] centerSelectionInVisibleArea];
3354 }
3355
3356 - (void)_alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebBridgeSelectionDirection)direction granularity:(WebBridgeSelectionGranularity)granularity
3357 {
3358     if (![self _canAlterCurrentSelection])
3359         return;
3360         
3361     WebFrameBridge *bridge = [self _bridge];
3362     DOMRange *proposedRange = [bridge rangeByAlteringCurrentSelection:alteration direction:direction granularity:granularity];
3363     WebView *webView = [self _webView];
3364     if ([[webView _editingDelegateForwarder] webView:webView shouldChangeSelectedDOMRange:[self _selectedRange] toDOMRange:proposedRange affinity:[bridge selectionAffinity] stillSelecting:NO]) {
3365         [bridge alterCurrentSelection:alteration direction:direction granularity:granularity];
3366     }
3367 }
3368
3369 - (void)_alterCurrentSelection:(WebSelectionAlteration)alteration verticalDistance:(float)verticalDistance
3370 {
3371     if (![self _canAlterCurrentSelection])
3372         return;
3373         
3374     WebFrameBridge *bridge = [self _bridge];
3375     DOMRange *proposedRange = [bridge rangeByAlteringCurrentSelection:alteration verticalDistance:verticalDistance];
3376     WebView *webView = [self _webView];
3377     if ([[webView _editingDelegateForwarder] webView:webView shouldChangeSelectedDOMRange:[self _selectedRange] toDOMRange:proposedRange affinity:[bridge selectionAffinity] stillSelecting:NO]) {
3378         [bridge alterCurrentSelection:alteration verticalDistance:verticalDistance];
3379     }
3380 }
3381
3382 - (void)moveBackward:(id)sender
3383 {
3384     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectBackward granularity:WebBridgeSelectByCharacter];
3385 }
3386
3387 - (void)moveBackwardAndModifySelection:(id)sender
3388 {
3389     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectBackward granularity:WebBridgeSelectByCharacter];
3390 }
3391
3392 - (void)moveDown:(id)sender
3393 {
3394     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectForward granularity:WebBridgeSelectByLine];
3395 }
3396
3397 - (void)moveDownAndModifySelection:(id)sender
3398 {
3399     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectForward granularity:WebBridgeSelectByLine];
3400 }
3401
3402 - (void)moveForward:(id)sender
3403 {
3404     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectForward granularity:WebBridgeSelectByCharacter];
3405 }
3406
3407 - (void)moveForwardAndModifySelection:(id)sender
3408 {
3409     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectForward granularity:WebBridgeSelectByCharacter];
3410 }
3411
3412 - (void)moveLeft:(id)sender
3413 {
3414     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectLeft granularity:WebBridgeSelectByCharacter];
3415 }
3416
3417 - (void)moveLeftAndModifySelection:(id)sender
3418 {
3419     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectLeft granularity:WebBridgeSelectByCharacter];
3420 }
3421
3422 - (void)moveRight:(id)sender
3423 {
3424     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectRight granularity:WebBridgeSelectByCharacter];
3425 }
3426
3427 - (void)moveRightAndModifySelection:(id)sender
3428 {
3429     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectRight granularity:WebBridgeSelectByCharacter];
3430 }
3431
3432 - (void)moveToBeginningOfDocument:(id)sender
3433 {
3434     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectBackward granularity:WebBridgeSelectToDocumentBoundary];
3435 }
3436
3437 - (void)moveToBeginningOfDocumentAndModifySelection:(id)sender
3438 {
3439     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectBackward granularity:WebBridgeSelectToDocumentBoundary];
3440 }
3441
3442 - (void)moveToBeginningOfSentence:(id)sender
3443 {
3444     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectBackward granularity:WebBridgeSelectToSentenceBoundary];
3445 }
3446
3447 - (void)moveToBeginningOfSentenceAndModifySelection:(id)sender
3448 {
3449     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectBackward granularity:WebBridgeSelectToSentenceBoundary];
3450 }
3451
3452 - (void)moveToBeginningOfLine:(id)sender
3453 {
3454     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectBackward granularity:WebBridgeSelectToLineBoundary];
3455 }
3456
3457 - (void)moveToBeginningOfLineAndModifySelection:(id)sender
3458 {
3459     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectBackward granularity:WebBridgeSelectToLineBoundary];
3460 }
3461
3462 - (void)moveToBeginningOfParagraph:(id)sender
3463 {
3464     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectBackward granularity:WebBridgeSelectToParagraphBoundary];
3465 }
3466
3467 - (void)moveToBeginningOfParagraphAndModifySelection:(id)sender
3468 {
3469     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectBackward granularity:WebBridgeSelectToParagraphBoundary];
3470 }
3471
3472 - (void)moveToEndOfDocument:(id)sender
3473 {
3474     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectForward granularity:WebBridgeSelectToDocumentBoundary];
3475 }
3476
3477 - (void)moveToEndOfDocumentAndModifySelection:(id)sender
3478 {
3479     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectForward granularity:WebBridgeSelectToDocumentBoundary];
3480 }
3481
3482 - (void)moveToEndOfSentence:(id)sender
3483 {
3484     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectForward granularity:WebBridgeSelectToSentenceBoundary];
3485 }
3486
3487 - (void)moveToEndOfSentenceAndModifySelection:(id)sender
3488 {
3489     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectForward granularity:WebBridgeSelectToSentenceBoundary];
3490 }
3491
3492 - (void)moveToEndOfLine:(id)sender
3493 {
3494     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectForward granularity:WebBridgeSelectToLineBoundary];
3495 }
3496
3497 - (void)moveToEndOfLineAndModifySelection:(id)sender
3498 {
3499     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectForward granularity:WebBridgeSelectToLineBoundary];
3500 }
3501
3502 - (void)moveToEndOfParagraph:(id)sender
3503 {
3504     [self _alterCurrentSelection:WebSelectByMoving direction:WebBridgeSelectForward granularity:WebBridgeSelectToParagraphBoundary];
3505 }
3506
3507 - (void)moveToEndOfParagraphAndModifySelection:(id)sender
3508 {
3509     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectForward granularity:WebBridgeSelectToParagraphBoundary];
3510 }
3511
3512 - (void)moveParagraphBackwardAndModifySelection:(id)sender
3513 {
3514     [self _alterCurrentSelection:WebSelectByExtending direction:WebBridgeSelectBackward granularity:WebBridgeSelectByParagraph];
3515 }
3516
3517 - (void)moveParagraphForwardAndModifySelection:(id)sender
3518 {