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