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