Home | History | Annotate | Download | only in WebView
      1 /*
      2  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      3  *           (C) 2006, 2007 Graham Dennis (graham.dennis (at) gmail.com)
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #import "WebHTMLView.h"
     31 
     32 #import "DOMCSSStyleDeclarationInternal.h"
     33 #import "DOMDocumentFragmentInternal.h"
     34 #import "DOMDocumentInternal.h"
     35 #import "DOMNodeInternal.h"
     36 #import "DOMRangeInternal.h"
     37 #import "WebArchive.h"
     38 #import "WebClipView.h"
     39 #import "WebDOMOperationsInternal.h"
     40 #import "WebDataSourceInternal.h"
     41 #import "WebDefaultUIDelegate.h"
     42 #import "WebDelegateImplementationCaching.h"
     43 #import "WebDocumentInternal.h"
     44 #import "WebDynamicScrollBarsView.h"
     45 #import "WebEditingDelegate.h"
     46 #import "WebElementDictionary.h"
     47 #import "WebFrameInternal.h"
     48 #import "WebFramePrivate.h"
     49 #import "WebFrameViewInternal.h"
     50 #import "WebHTMLRepresentationPrivate.h"
     51 #import "WebHTMLViewInternal.h"
     52 #import "WebKitLogging.h"
     53 #import "WebKitNSStringExtras.h"
     54 #import "WebKitVersionChecks.h"
     55 #import "WebLocalizableStrings.h"
     56 #import "WebNSAttributedStringExtras.h"
     57 #import "WebNSEventExtras.h"
     58 #import "WebNSFileManagerExtras.h"
     59 #import "WebNSImageExtras.h"
     60 #import "WebNSObjectExtras.h"
     61 #import "WebNSPasteboardExtras.h"
     62 #import "WebNSPrintOperationExtras.h"
     63 #import "WebNSURLExtras.h"
     64 #import "WebNSViewExtras.h"
     65 #import "WebNetscapePluginView.h"
     66 #import "WebNodeHighlight.h"
     67 #import "WebPluginController.h"
     68 #import "WebPreferences.h"
     69 #import "WebPreferencesPrivate.h"
     70 #import "WebResourcePrivate.h"
     71 #import "WebStringTruncator.h"
     72 #import "WebTextCompletionController.h"
     73 #import "WebTypesInternal.h"
     74 #import "WebUIDelegatePrivate.h"
     75 #import "WebViewInternal.h"
     76 #import <AppKit/NSAccessibility.h>
     77 #import <ApplicationServices/ApplicationServices.h>
     78 #import <WebCore/CSSMutableStyleDeclaration.h>
     79 #import <WebCore/CachedImage.h>
     80 #import <WebCore/CachedResourceClient.h>
     81 #import <WebCore/ColorMac.h>
     82 #import <WebCore/ContextMenu.h>
     83 #import <WebCore/ContextMenuController.h>
     84 #import <WebCore/Document.h>
     85 #import <WebCore/DocumentFragment.h>
     86 #import <WebCore/DragController.h>
     87 #import <WebCore/Editor.h>
     88 #import <WebCore/EditorDeleteAction.h>
     89 #import <WebCore/Element.h>
     90 #import <WebCore/EventHandler.h>
     91 #import <WebCore/ExceptionHandlers.h>
     92 #import <WebCore/FloatRect.h>
     93 #import <WebCore/FocusController.h>
     94 #import <WebCore/Frame.h>
     95 #import <WebCore/FrameLoader.h>
     96 #import <WebCore/FrameView.h>
     97 #import <WebCore/HTMLNames.h>
     98 #import <WebCore/HitTestResult.h>
     99 #import <WebCore/Image.h>
    100 #import <WebCore/KeyboardEvent.h>
    101 #import <WebCore/LegacyWebArchive.h>
    102 #import <WebCore/MIMETypeRegistry.h>
    103 #import <WebCore/Page.h>
    104 #import <WebCore/PlatformKeyboardEvent.h>
    105 #import <WebCore/Range.h>
    106 #import <WebCore/RuntimeApplicationChecks.h>
    107 #import <WebCore/SelectionController.h>
    108 #import <WebCore/SharedBuffer.h>
    109 #import <WebCore/SimpleFontData.h>
    110 #import <WebCore/Text.h>
    111 #import <WebCore/WebCoreObjCExtras.h>
    112 #import <WebCore/WebFontCache.h>
    113 #import <WebCore/markup.h>
    114 #import <WebKit/DOM.h>
    115 #import <WebKit/DOMExtensions.h>
    116 #import <WebKit/DOMPrivate.h>
    117 #import <WebKitSystemInterface.h>
    118 #import <dlfcn.h>
    119 #import <limits>
    120 #import <runtime/InitializeThreading.h>
    121 
    122 #if USE(ACCELERATED_COMPOSITING)
    123 #import <QuartzCore/QuartzCore.h>
    124 #endif
    125 
    126 using namespace WebCore;
    127 using namespace HTMLNames;
    128 using namespace WTF;
    129 using namespace std;
    130 
    131 @interface NSWindow (BorderViewAccess)
    132 - (NSView*)_web_borderView;
    133 @end
    134 
    135 @implementation NSWindow (BorderViewAccess)
    136 - (NSView*)_web_borderView
    137 {
    138     return _borderView;
    139 }
    140 @end
    141 
    142 @interface WebResponderChainSink : NSResponder {
    143     NSResponder* _lastResponderInChain;
    144     BOOL _receivedUnhandledCommand;
    145 }
    146 - (id)initWithResponderChain:(NSResponder *)chain;
    147 - (void)detach;
    148 - (BOOL)receivedUnhandledCommand;
    149 @end
    150 
    151 static IMP oldSetCursorIMP = NULL;
    152 
    153 #ifdef BUILDING_ON_TIGER
    154 
    155 static IMP oldResetCursorRectsIMP = NULL;
    156 static BOOL canSetCursor = YES;
    157 
    158 static void resetCursorRects(NSWindow* self, SEL cmd)
    159 {
    160     NSPoint point = [self mouseLocationOutsideOfEventStream];
    161     NSView* view = [[self _web_borderView] hitTest:point];
    162     if ([view isKindOfClass:[WebHTMLView class]]) {
    163         WebHTMLView *htmlView = (WebHTMLView*)view;
    164         NSPoint localPoint = [htmlView convertPoint:point fromView:nil];
    165         NSDictionary *dict = [htmlView elementAtPoint:localPoint allowShadowContent:NO];
    166         DOMElement *element = [dict objectForKey:WebElementDOMNodeKey];
    167         if (![element isKindOfClass:[DOMHTMLAppletElement class]] && ![element isKindOfClass:[DOMHTMLObjectElement class]] &&
    168             ![element isKindOfClass:[DOMHTMLEmbedElement class]])
    169             canSetCursor = NO;
    170     }
    171     oldResetCursorRectsIMP(self, cmd);
    172     canSetCursor = YES;
    173 }
    174 
    175 static void setCursor(NSCursor* self, SEL cmd)
    176 {
    177     if (canSetCursor)
    178         oldSetCursorIMP(self, cmd);
    179 }
    180 
    181 #else
    182 
    183 static void setCursor(NSWindow* self, SEL cmd, NSPoint point)
    184 {
    185     NSView* view = [[self _web_borderView] hitTest:point];
    186     if ([view isKindOfClass:[WebHTMLView class]]) {
    187         WebHTMLView *htmlView = (WebHTMLView*)view;
    188         NSPoint localPoint = [htmlView convertPoint:point fromView:nil];
    189         NSDictionary *dict = [htmlView elementAtPoint:localPoint allowShadowContent:NO];
    190         DOMElement *element = [dict objectForKey:WebElementDOMNodeKey];
    191         if (![element isKindOfClass:[DOMHTMLAppletElement class]] && ![element isKindOfClass:[DOMHTMLObjectElement class]] &&
    192             ![element isKindOfClass:[DOMHTMLEmbedElement class]])
    193             return;
    194     }
    195     oldSetCursorIMP(self, cmd, point);
    196 }
    197 
    198 #endif
    199 
    200 extern "C" {
    201 
    202 // Need to declare these attribute names because AppKit exports them but does not make them available in API or SPI headers.
    203 
    204 extern NSString *NSMarkedClauseSegmentAttributeName;
    205 extern NSString *NSTextInputReplacementRangeAttributeName;
    206 
    207 }
    208 
    209 @interface NSView (WebNSViewDetails)
    210 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView;
    211 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect;
    212 - (void)_recursive:(BOOL)recurse displayRectIgnoringOpacity:(NSRect)displayRect inContext:(NSGraphicsContext *)context topView:(BOOL)topView;
    213 - (NSRect)_dirtyRect;
    214 - (void)_setDrawsOwnDescendants:(BOOL)drawsOwnDescendants;
    215 - (void)_propagateDirtyRectsToOpaqueAncestors;
    216 - (void)_windowChangedKeyState;
    217 #if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD)
    218 - (void)_updateLayerGeometryFromView;
    219 #endif
    220 @end
    221 
    222 @interface NSApplication (WebNSApplicationDetails)
    223 - (void)speakString:(NSString *)string;
    224 @end
    225 
    226 @interface NSWindow (WebNSWindowDetails)
    227 - (id)_newFirstResponderAfterResigning;
    228 @end
    229 
    230 @interface NSAttributedString (WebNSAttributedStringDetails)
    231 - (id)_initWithDOMRange:(DOMRange *)range;
    232 - (DOMDocumentFragment *)_documentFromRange:(NSRange)range document:(DOMDocument *)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources;
    233 @end
    234 
    235 @interface NSSpellChecker (WebNSSpellCheckerDetails)
    236 - (void)learnWord:(NSString *)word;
    237 @end
    238 
    239 // By imaging to a width a little wider than the available pixels,
    240 // thin pages will be scaled down a little, matching the way they
    241 // print in IE and Camino. This lets them use fewer sheets than they
    242 // would otherwise, which is presumably why other browsers do this.
    243 // Wide pages will be scaled down more than this.
    244 #define PrintingMinimumShrinkFactor     1.25f
    245 
    246 // This number determines how small we are willing to reduce the page content
    247 // in order to accommodate the widest line. If the page would have to be
    248 // reduced smaller to make the widest line fit, we just clip instead (this
    249 // behavior matches MacIE and Mozilla, at least)
    250 #define PrintingMaximumShrinkFactor     2.0f
    251 
    252 // This number determines how short the last printed page of a multi-page print session
    253 // can be before we try to shrink the scale in order to reduce the number of pages, and
    254 // thus eliminate the orphan.
    255 #define LastPrintedPageOrphanRatio      0.1f
    256 
    257 // This number determines the amount the scale factor is adjusted to try to eliminate orphans.
    258 // It has no direct mathematical relationship to LastPrintedPageOrphanRatio, due to variable
    259 // numbers of pages, logic to avoid breaking elements, and CSS-supplied hard page breaks.
    260 #define PrintingOrphanShrinkAdjustment  1.1f
    261 
    262 #define AUTOSCROLL_INTERVAL             0.1f
    263 
    264 #define DRAG_LABEL_BORDER_X             4.0f
    265 //Keep border_y in synch with DragController::LinkDragBorderInset
    266 #define DRAG_LABEL_BORDER_Y             2.0f
    267 #define DRAG_LABEL_RADIUS               5.0f
    268 #define DRAG_LABEL_BORDER_Y_OFFSET              2.0f
    269 
    270 #define MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP        120.0f
    271 #define MAX_DRAG_LABEL_WIDTH                    320.0f
    272 
    273 #define DRAG_LINK_LABEL_FONT_SIZE   11.0f
    274 #define DRAG_LINK_URL_FONT_SIZE   10.0f
    275 
    276 // Any non-zero value will do, but using something recognizable might help us debug some day.
    277 #define TRACKING_RECT_TAG 0xBADFACE
    278 
    279 // FIXME: This constant is copied from AppKit's _NXSmartPaste constant.
    280 #define WebSmartPastePboardType @"NeXT smart paste pasteboard type"
    281 
    282 #define STANDARD_WEIGHT 5
    283 #define MIN_BOLD_WEIGHT 7
    284 #define STANDARD_BOLD_WEIGHT 9
    285 
    286 // Fake URL scheme.
    287 #define WebDataProtocolScheme @"webkit-fake-url"
    288 
    289 // <rdar://problem/4985524> References to WebCoreScrollView as a subview of a WebHTMLView may be present
    290 // in some NIB files, so NSUnarchiver must be still able to look up this now-unused class.
    291 @interface WebCoreScrollView : NSScrollView
    292 @end
    293 
    294 @implementation WebCoreScrollView
    295 @end
    296 
    297 // if YES, do the standard NSView hit test (which can't give the right result when HTML overlaps a view)
    298 static BOOL forceNSViewHitTest;
    299 
    300 // 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])
    301 static BOOL forceWebHTMLViewHitTest;
    302 
    303 static WebHTMLView *lastHitView;
    304 
    305 // We need this to be able to safely reference the CachedImage for the promised drag data
    306 static CachedResourceClient* promisedDataClient()
    307 {
    308     static CachedResourceClient* staticCachedResourceClient = new CachedResourceClient;
    309     return staticCachedResourceClient;
    310 }
    311 
    312 @interface WebHTMLView (WebHTMLViewFileInternal)
    313 - (BOOL)_imageExistsAtPaths:(NSArray *)paths;
    314 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard inContext:(DOMRange *)context allowPlainText:(BOOL)allowPlainText;
    315 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard;
    316 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText;
    317 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard;
    318 - (void)_removeMouseMovedObserverUnconditionally;
    319 - (void)_removeSuperviewObservers;
    320 - (void)_removeWindowObservers;
    321 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
    322 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
    323 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action;
    324 - (float)_calculatePrintHeight;
    325 - (DOMRange *)_selectedRange;
    326 - (BOOL)_shouldDeleteRange:(DOMRange *)range;
    327 - (NSView *)_hitViewForEvent:(NSEvent *)event;
    328 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString;
    329 - (DOMRange *)_documentRange;
    330 - (void)_setMouseDownEvent:(NSEvent *)event;
    331 - (WebHTMLView *)_topHTMLView;
    332 - (BOOL)_isTopHTMLView;
    333 - (void)_web_setPrintingModeRecursive;
    334 - (void)_web_setPrintingModeRecursiveAndAdjustViewSize;
    335 - (void)_web_clearPrintingModeRecursive;
    336 @end
    337 
    338 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    339 
    340 @interface WebHTMLView (WebHTMLViewTextCheckingInternal)
    341 - (void)orderFrontSubstitutionsPanel:(id)sender;
    342 - (BOOL)smartInsertDeleteEnabled;
    343 - (void)setSmartInsertDeleteEnabled:(BOOL)flag;
    344 - (void)toggleSmartInsertDelete:(id)sender;
    345 - (BOOL)isAutomaticQuoteSubstitutionEnabled;
    346 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag;
    347 - (void)toggleAutomaticQuoteSubstitution:(id)sender;
    348 - (BOOL)isAutomaticLinkDetectionEnabled;
    349 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag;
    350 - (void)toggleAutomaticLinkDetection:(id)sender;
    351 - (BOOL)isAutomaticDashSubstitutionEnabled;
    352 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag;
    353 - (void)toggleAutomaticDashSubstitution:(id)sender;
    354 - (BOOL)isAutomaticTextReplacementEnabled;
    355 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag;
    356 - (void)toggleAutomaticTextReplacement:(id)sender;
    357 - (BOOL)isAutomaticSpellingCorrectionEnabled;
    358 - (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag;
    359 - (void)toggleAutomaticSpellingCorrection:(id)sender;
    360 @end
    361 
    362 #endif
    363 
    364 @interface WebHTMLView (WebForwardDeclaration) // FIXME: Put this in a normal category and stop doing the forward declaration trick.
    365 - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize;
    366 @end
    367 
    368 @class NSTextInputContext;
    369 @interface NSResponder (AppKitDetails)
    370 - (NSTextInputContext *)inputContext;
    371 @end
    372 
    373 @interface NSObject (NSTextInputContextDetails)
    374 - (BOOL)wantsToHandleMouseEvents;
    375 - (BOOL)handleMouseEvent:(NSEvent *)event;
    376 @end
    377 
    378 @interface WebHTMLView (WebNSTextInputSupport) <NSTextInput>
    379 - (void)_updateSelectionForInputManager;
    380 @end
    381 
    382 @interface WebHTMLView (WebEditingStyleSupport)
    383 - (DOMCSSStyleDeclaration *)_emptyStyle;
    384 - (NSString *)_colorAsString:(NSColor *)color;
    385 @end
    386 
    387 @interface NSView (WebHTMLViewFileInternal)
    388 - (void)_web_addDescendantWebHTMLViewsToArray:(NSMutableArray *) array;
    389 @end
    390 
    391 @interface NSMutableDictionary (WebHTMLViewFileInternal)
    392 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key;
    393 @end
    394 
    395 struct WebHTMLViewInterpretKeyEventsParameters {
    396     KeyboardEvent* event;
    397     BOOL eventWasHandled;
    398     BOOL shouldSaveCommand;
    399     // The Input Method may consume an event and not tell us, in
    400     // which case we should not bubble the event up the DOM
    401     BOOL consumedByIM;
    402 };
    403 
    404 @interface WebHTMLViewPrivate : NSObject {
    405 @public
    406     BOOL closed;
    407     BOOL needsToApplyStyles;
    408     BOOL ignoringMouseDraggedEvents;
    409     BOOL printing;
    410     BOOL avoidingPrintOrphan;
    411     BOOL observingMouseMovedNotifications;
    412     BOOL observingSuperviewNotifications;
    413     BOOL observingWindowNotifications;
    414 
    415     id savedSubviews;
    416     BOOL subviewsSetAside;
    417 
    418 #if USE(ACCELERATED_COMPOSITING)
    419     NSView *layerHostingView;
    420 #endif
    421 
    422     NSEvent *mouseDownEvent; // Kept after handling the event.
    423     BOOL handlingMouseDownEvent;
    424     NSEvent *keyDownEvent; // Kept after handling the event.
    425 
    426     // A WebHTMLView has a single input context, but we return nil when in non-editable content to avoid making input methods do their work.
    427     // This state is saved each time selection changes, because computing it causes style recalc, which is not always safe to do.
    428     BOOL exposeInputContext;
    429 
    430     NSPoint lastScrollPosition;
    431 
    432     WebPluginController *pluginController;
    433 
    434     NSString *toolTip;
    435     NSToolTipTag lastToolTipTag;
    436     id trackingRectOwner;
    437     void *trackingRectUserData;
    438 
    439     NSTimer *autoscrollTimer;
    440     NSEvent *autoscrollTriggerEvent;
    441 
    442     NSArray *pageRects;
    443 
    444     NSMutableDictionary *highlighters;
    445 
    446 #ifdef BUILDING_ON_TIGER
    447     BOOL nextResponderDisabledOnce;
    448 #endif
    449 
    450     WebTextCompletionController *completionController;
    451 
    452     BOOL transparentBackground;
    453 
    454     WebHTMLViewInterpretKeyEventsParameters* interpretKeyEventsParameters;
    455     BOOL receivedNOOP;
    456 
    457     WebDataSource *dataSource;
    458     WebCore::CachedImage* promisedDragTIFFDataSource;
    459 
    460     CFRunLoopTimerRef updateMouseoverTimer;
    461 
    462     SEL selectorForDoCommandBySelector;
    463 
    464 #ifndef NDEBUG
    465     BOOL enumeratingSubviews;
    466 #endif
    467 }
    468 - (void)clear;
    469 @end
    470 
    471 static NSCellStateValue kit(TriState state)
    472 {
    473     switch (state) {
    474         case FalseTriState:
    475             return NSOffState;
    476         case TrueTriState:
    477             return NSOnState;
    478         case MixedTriState:
    479             return NSMixedState;
    480     }
    481     ASSERT_NOT_REACHED();
    482     return NSOffState;
    483 }
    484 
    485 @implementation WebHTMLViewPrivate
    486 
    487 + (void)initialize
    488 {
    489     JSC::initializeThreading();
    490 #ifndef BUILDING_ON_TIGER
    491     WebCoreObjCFinalizeOnMainThread(self);
    492 #endif
    493 
    494     if (!oldSetCursorIMP) {
    495 #ifdef BUILDING_ON_TIGER
    496         Method setCursorMethod = class_getInstanceMethod([NSCursor class], @selector(set));
    497 #else
    498         Method setCursorMethod = class_getInstanceMethod([NSWindow class], @selector(_setCursorForMouseLocation:));
    499 #endif
    500         ASSERT(setCursorMethod);
    501 
    502         oldSetCursorIMP = method_setImplementation(setCursorMethod, (IMP)setCursor);
    503         ASSERT(oldSetCursorIMP);
    504     }
    505 
    506 #ifdef BUILDING_ON_TIGER
    507     if (!oldResetCursorRectsIMP) {
    508         Method resetCursorRectsMethod = class_getInstanceMethod([NSWindow class], @selector(resetCursorRects));
    509         ASSERT(resetCursorRectsMethod);
    510         oldResetCursorRectsIMP = method_setImplementation(resetCursorRectsMethod, (IMP)resetCursorRects);
    511         ASSERT(oldResetCursorRectsIMP);
    512     }
    513 #endif
    514 
    515 }
    516 
    517 - (void)dealloc
    518 {
    519     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHTMLViewPrivate class], self))
    520         return;
    521 
    522     ASSERT(!autoscrollTimer);
    523     ASSERT(!autoscrollTriggerEvent);
    524     ASSERT(!updateMouseoverTimer);
    525 
    526     [mouseDownEvent release];
    527     [keyDownEvent release];
    528     [pluginController release];
    529     [toolTip release];
    530     [completionController release];
    531     [dataSource release];
    532     [highlighters release];
    533     if (promisedDragTIFFDataSource)
    534         promisedDragTIFFDataSource->removeClient(promisedDataClient());
    535 
    536     [super dealloc];
    537 }
    538 
    539 - (void)finalize
    540 {
    541     ASSERT_MAIN_THREAD();
    542 
    543     if (promisedDragTIFFDataSource)
    544         promisedDragTIFFDataSource->removeClient(promisedDataClient());
    545 
    546     [super finalize];
    547 }
    548 
    549 - (void)clear
    550 {
    551     [mouseDownEvent release];
    552     [keyDownEvent release];
    553     [pluginController release];
    554     [toolTip release];
    555     [completionController release];
    556     [dataSource release];
    557     [highlighters release];
    558     if (promisedDragTIFFDataSource)
    559         promisedDragTIFFDataSource->removeClient(promisedDataClient());
    560 
    561     mouseDownEvent = nil;
    562     keyDownEvent = nil;
    563     pluginController = nil;
    564     toolTip = nil;
    565     completionController = nil;
    566     dataSource = nil;
    567     highlighters = nil;
    568     promisedDragTIFFDataSource = 0;
    569 
    570 #if USE(ACCELERATED_COMPOSITING)
    571     layerHostingView = nil;
    572 #endif
    573 }
    574 
    575 @end
    576 
    577 @implementation WebHTMLView (WebHTMLViewFileInternal)
    578 
    579 - (DOMRange *)_documentRange
    580 {
    581     return [[[self _frame] DOMDocument] _documentRange];
    582 }
    583 
    584 - (BOOL)_imageExistsAtPaths:(NSArray *)paths
    585 {
    586     NSEnumerator *enumerator = [paths objectEnumerator];
    587     NSString *path;
    588 
    589     while ((path = [enumerator nextObject]) != nil) {
    590         NSString *MIMEType = WKGetMIMETypeForExtension([path pathExtension]);
    591         if (MIMETypeRegistry::isSupportedImageResourceMIMEType(MIMEType))
    592             return YES;
    593     }
    594 
    595     return NO;
    596 }
    597 
    598 - (WebDataSource *)_dataSource
    599 {
    600     return _private->dataSource;
    601 }
    602 
    603 - (WebView *)_webView
    604 {
    605     return [_private->dataSource _webView];
    606 }
    607 
    608 - (WebFrameView *)_frameView
    609 {
    610     return [[_private->dataSource webFrame] frameView];
    611 }
    612 
    613 - (DOMDocumentFragment *)_documentFragmentWithPaths:(NSArray *)paths
    614 {
    615     DOMDocumentFragment *fragment;
    616     NSEnumerator *enumerator = [paths objectEnumerator];
    617     NSMutableArray *domNodes = [[NSMutableArray alloc] init];
    618     NSString *path;
    619 
    620     while ((path = [enumerator nextObject]) != nil) {
    621         // Non-image file types; _web_userVisibleString is appropriate here because this will
    622         // be pasted as visible text.
    623         NSString *url = [[[NSURL fileURLWithPath:path] _webkit_canonicalize] _web_userVisibleString];
    624         [domNodes addObject:[[[self _frame] DOMDocument] createTextNode: url]];
    625     }
    626 
    627     fragment = [[self _frame] _documentFragmentWithNodesAsParagraphs:domNodes];
    628 
    629     [domNodes release];
    630 
    631     return [fragment firstChild] != nil ? fragment : nil;
    632 }
    633 
    634 + (NSArray *)_excludedElementsForAttributedStringConversion
    635 {
    636     static NSArray *elements = nil;
    637     if (elements == nil) {
    638         elements = [[NSArray alloc] initWithObjects:
    639             // Omit style since we want style to be inline so the fragment can be easily inserted.
    640             @"style",
    641             // Omit xml so the result is not XHTML.
    642             @"xml",
    643             // Omit tags that will get stripped when converted to a fragment anyway.
    644             @"doctype", @"html", @"head", @"body",
    645             // Omit deprecated tags.
    646             @"applet", @"basefont", @"center", @"dir", @"font", @"isindex", @"menu", @"s", @"strike", @"u",
    647             // Omit object so no file attachments are part of the fragment.
    648             @"object", nil];
    649         CFRetain(elements);
    650     }
    651     return elements;
    652 }
    653 
    654 static NSURL* uniqueURLWithRelativePart(NSString *relativePart)
    655 {
    656     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
    657     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
    658     CFRelease(UUIDRef);
    659     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@/%@", WebDataProtocolScheme, UUIDString, relativePart]];
    660     CFRelease(UUIDString);
    661 
    662     return URL;
    663 }
    664 
    665 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
    666                                                inContext:(DOMRange *)context
    667                                           allowPlainText:(BOOL)allowPlainText
    668 {
    669     NSArray *types = [pasteboard types];
    670     DOMDocumentFragment *fragment = nil;
    671 
    672     if ([types containsObject:WebArchivePboardType] &&
    673         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    674                                                   forType:WebArchivePboardType
    675                                                 inContext:context
    676                                              subresources:0]))
    677         return fragment;
    678 
    679     if ([types containsObject:NSFilenamesPboardType] &&
    680         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    681                                                   forType:NSFilenamesPboardType
    682                                                 inContext:context
    683                                              subresources:0]))
    684         return fragment;
    685 
    686     if ([types containsObject:NSHTMLPboardType] &&
    687         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    688                                                   forType:NSHTMLPboardType
    689                                                 inContext:context
    690                                              subresources:0]))
    691         return fragment;
    692 
    693     if ([types containsObject:NSRTFDPboardType] &&
    694         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    695                                                   forType:NSRTFDPboardType
    696                                                 inContext:context
    697                                              subresources:0]))
    698         return fragment;
    699 
    700     if ([types containsObject:NSRTFPboardType] &&
    701         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    702                                                   forType:NSRTFPboardType
    703                                                 inContext:context
    704                                              subresources:0]))
    705         return fragment;
    706 
    707     if ([types containsObject:NSTIFFPboardType] &&
    708         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    709                                                   forType:NSTIFFPboardType
    710                                                 inContext:context
    711                                              subresources:0]))
    712         return fragment;
    713 
    714     if ([types containsObject:NSPDFPboardType] &&
    715         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    716                                                   forType:NSPDFPboardType
    717                                                 inContext:context
    718                                              subresources:0]))
    719         return fragment;
    720 
    721 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
    722     if ([types containsObject:NSPICTPboardType] &&
    723         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    724                                                   forType:NSPICTPboardType
    725                                                 inContext:context
    726                                              subresources:0]))
    727         return fragment;
    728 #endif
    729 
    730     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
    731     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
    732     if ([types containsObject:(NSString*)kUTTypePNG] &&
    733         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    734                                                   forType:(NSString*)kUTTypePNG
    735                                                 inContext:context
    736                                              subresources:0]))
    737         return fragment;
    738 
    739     if ([types containsObject:NSURLPboardType] &&
    740         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    741                                                   forType:NSURLPboardType
    742                                                 inContext:context
    743                                              subresources:0]))
    744         return fragment;
    745 
    746     if (allowPlainText && [types containsObject:NSStringPboardType] &&
    747         (fragment = [self _documentFragmentFromPasteboard:pasteboard
    748                                                   forType:NSStringPboardType
    749                                                 inContext:context
    750                                              subresources:0])) {
    751         return fragment;
    752     }
    753 
    754     return nil;
    755 }
    756 
    757 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard
    758 {
    759     NSArray *types = [pasteboard types];
    760 
    761     if ([types containsObject:NSStringPboardType])
    762         return [[pasteboard stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping];
    763 
    764     NSAttributedString *attributedString = nil;
    765     NSString *string;
    766 
    767     if ([types containsObject:NSRTFDPboardType])
    768         attributedString = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
    769     if (attributedString == nil && [types containsObject:NSRTFPboardType])
    770         attributedString = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
    771     if (attributedString != nil) {
    772         string = [[attributedString string] copy];
    773         [attributedString release];
    774         return [string autorelease];
    775     }
    776 
    777     if ([types containsObject:NSFilenamesPboardType]) {
    778         string = [[pasteboard propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"];
    779         if (string != nil)
    780             return string;
    781     }
    782 
    783     NSURL *URL;
    784 
    785     if ((URL = [NSURL URLFromPasteboard:pasteboard])) {
    786         string = [URL _web_userVisibleString];
    787         if ([string length] > 0)
    788             return string;
    789     }
    790 
    791     return nil;
    792 }
    793 
    794 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText
    795 {
    796     WebView *webView = [[self _webView] retain];
    797     [webView _setInsertionPasteboard:pasteboard];
    798 
    799     DOMRange *range = [self _selectedRange];
    800 
    801 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
    802     DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
    803     if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionPasted])
    804         [[self _frame] _replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:NO];
    805 #else
    806     // Mail is ignoring the frament passed to the delegate and creates a new one.
    807     // We want to avoid creating the fragment twice.
    808     if (applicationIsAppleMail()) {
    809         if ([self _shouldInsertFragment:nil replacingDOMRange:range givenAction:WebViewInsertActionPasted]) {
    810             DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
    811             if (fragment)
    812                 [[self _frame] _replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:NO];
    813         }
    814     } else {
    815         DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
    816         if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionPasted])
    817             [[self _frame] _replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:NO];
    818     }
    819 #endif
    820     [webView _setInsertionPasteboard:nil];
    821     [webView release];
    822 }
    823 
    824 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard
    825 {
    826     WebView *webView = [[self _webView] retain];
    827     [webView _setInsertionPasteboard:pasteboard];
    828 
    829     NSString *text = [self _plainTextFromPasteboard:pasteboard];
    830     if ([self _shouldReplaceSelectionWithText:text givenAction:WebViewInsertActionPasted])
    831         [[self _frame] _replaceSelectionWithText:text selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard]];
    832 
    833     [webView _setInsertionPasteboard:nil];
    834     [webView release];
    835 }
    836 
    837 - (void)_removeMouseMovedObserverUnconditionally
    838 {
    839     if (!_private || !_private->observingMouseMovedNotifications)
    840         return;
    841 
    842     [[NSNotificationCenter defaultCenter] removeObserver:self name:WKMouseMovedNotification() object:nil];
    843     _private->observingMouseMovedNotifications = false;
    844 }
    845 
    846 - (void)_removeSuperviewObservers
    847 {
    848     if (!_private || !_private->observingSuperviewNotifications)
    849         return;
    850 
    851     NSView *superview = [self superview];
    852     if (!superview || ![self window])
    853         return;
    854 
    855     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    856     [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:superview];
    857     [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:superview];
    858 
    859     _private->observingSuperviewNotifications = false;
    860 }
    861 
    862 - (void)_removeWindowObservers
    863 {
    864     if (!_private->observingWindowNotifications)
    865         return;
    866 
    867     NSWindow *window = [self window];
    868     if (!window)
    869         return;
    870 
    871     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    872     [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
    873     [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
    874     [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:window];
    875 
    876     _private->observingWindowNotifications = false;
    877 }
    878 
    879 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
    880 {
    881     WebView *webView = [self _webView];
    882     DOMNode *child = [fragment firstChild];
    883     if ([fragment lastChild] == child && [child isKindOfClass:[DOMCharacterData class]])
    884         return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:[(DOMCharacterData *)child data] replacingDOMRange:range givenAction:action];
    885     return [[webView _editingDelegateForwarder] webView:webView shouldInsertNode:fragment replacingDOMRange:range givenAction:action];
    886 }
    887 
    888 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
    889 {
    890     WebView *webView = [self _webView];
    891     return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:range givenAction:action];
    892 }
    893 
    894 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action
    895 {
    896     return [self _shouldInsertText:text replacingDOMRange:[self _selectedRange] givenAction:action];
    897 }
    898 
    899 // Calculate the vertical size of the view that fits on a single page
    900 - (float)_calculatePrintHeight
    901 {
    902     // Obtain the print info object for the current operation
    903     NSPrintInfo *pi = [[NSPrintOperation currentOperation] printInfo];
    904 
    905     // Calculate the page height in points
    906     NSSize paperSize = [pi paperSize];
    907     return paperSize.height - [pi topMargin] - [pi bottomMargin];
    908 }
    909 
    910 - (DOMRange *)_selectedRange
    911 {
    912     Frame* coreFrame = core([self _frame]);
    913     return coreFrame ? kit(coreFrame->selection()->toNormalizedRange().get()) : nil;
    914 }
    915 
    916 - (BOOL)_shouldDeleteRange:(DOMRange *)range
    917 {
    918     Frame* coreFrame = core([self _frame]);
    919     return coreFrame && coreFrame->editor()->shouldDeleteRange(core(range));
    920 }
    921 
    922 - (NSView *)_hitViewForEvent:(NSEvent *)event
    923 {
    924     // Usually, we hack AK's hitTest method to catch all events at the topmost WebHTMLView.
    925     // Callers of this method, however, want to query the deepest view instead.
    926     forceNSViewHitTest = YES;
    927     NSView *hitView = [[[self window] contentView] hitTest:[event locationInWindow]];
    928     forceNSViewHitTest = NO;
    929     return hitView;
    930 }
    931 
    932 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString
    933 {
    934     // Put HTML on the pasteboard.
    935     if ([types containsObject:WebArchivePboardType]) {
    936         if (RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::createFromSelection(core([self _frame]))) {
    937             if (RetainPtr<CFDataRef> data = coreArchive ? coreArchive->rawDataRepresentation() : 0)
    938                 [pasteboard setData:(NSData *)data.get() forType:WebArchivePboardType];
    939         }
    940     }
    941 
    942     // Put the attributed string on the pasteboard (RTF/RTFD format).
    943     if ([types containsObject:NSRTFDPboardType]) {
    944         if (attributedString == nil) {
    945             attributedString = [self selectedAttributedString];
    946         }
    947         NSData *RTFDData = [attributedString RTFDFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
    948         [pasteboard setData:RTFDData forType:NSRTFDPboardType];
    949     }
    950     if ([types containsObject:NSRTFPboardType]) {
    951         if (attributedString == nil) {
    952             attributedString = [self selectedAttributedString];
    953         }
    954         if ([attributedString containsAttachments]) {
    955             attributedString = [attributedString _web_attributedStringByStrippingAttachmentCharacters];
    956         }
    957         NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
    958         [pasteboard setData:RTFData forType:NSRTFPboardType];
    959     }
    960 
    961     // Put plain string on the pasteboard.
    962     if ([types containsObject:NSStringPboardType]) {
    963         // Map &nbsp; to a plain old space because this is better for source code, other browsers do it,
    964         // and because HTML forces you to do this any time you want two spaces in a row.
    965         NSMutableString *s = [[self selectedString] mutableCopy];
    966         const unichar NonBreakingSpaceCharacter = 0xA0;
    967         NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&NonBreakingSpaceCharacter length:1];
    968         [s replaceOccurrencesOfString:NonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
    969         [pasteboard setString:s forType:NSStringPboardType];
    970         [s release];
    971     }
    972 
    973     if ([self _canSmartCopyOrDelete] && [types containsObject:WebSmartPastePboardType]) {
    974         [pasteboard setData:nil forType:WebSmartPastePboardType];
    975     }
    976 }
    977 
    978 - (void)_setMouseDownEvent:(NSEvent *)event
    979 {
    980     ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
    981 
    982     if (event == _private->mouseDownEvent)
    983         return;
    984 
    985     [event retain];
    986     [_private->mouseDownEvent release];
    987     _private->mouseDownEvent = event;
    988 }
    989 
    990 - (void)_cancelUpdateMouseoverTimer
    991 {
    992     if (_private->updateMouseoverTimer) {
    993         CFRunLoopTimerInvalidate(_private->updateMouseoverTimer);
    994         CFRelease(_private->updateMouseoverTimer);
    995         _private->updateMouseoverTimer = NULL;
    996     }
    997 }
    998 
    999 - (WebHTMLView *)_topHTMLView
   1000 {
   1001     // FIXME: this can fail if the dataSource is nil, which happens when the WebView is tearing down from the window closing.
   1002     WebHTMLView *view = (WebHTMLView *)[[[[_private->dataSource _webView] mainFrame] frameView] documentView];
   1003     ASSERT(!view || [view isKindOfClass:[WebHTMLView class]]);
   1004     return view;
   1005 }
   1006 
   1007 - (BOOL)_isTopHTMLView
   1008 {
   1009     // FIXME: this should be a cached boolean that doesn't rely on _topHTMLView since that can fail (see _topHTMLView).
   1010     return self == [self _topHTMLView];
   1011 }
   1012 
   1013 - (void)_web_setPrintingModeRecursive
   1014 {
   1015     [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   1016 
   1017 #ifndef NDEBUG
   1018     _private->enumeratingSubviews = YES;
   1019 #endif
   1020 
   1021     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
   1022 
   1023     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
   1024 
   1025     unsigned count = [descendantWebHTMLViews count];
   1026     for (unsigned i = 0; i < count; ++i)
   1027         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   1028 
   1029     [descendantWebHTMLViews release];
   1030 
   1031 #ifndef NDEBUG
   1032     _private->enumeratingSubviews = NO;
   1033 #endif
   1034 }
   1035 
   1036 - (void)_web_clearPrintingModeRecursive
   1037 {
   1038     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   1039 
   1040 #ifndef NDEBUG
   1041     _private->enumeratingSubviews = YES;
   1042 #endif
   1043 
   1044     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
   1045 
   1046     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
   1047 
   1048     unsigned count = [descendantWebHTMLViews count];
   1049     for (unsigned i = 0; i < count; ++i)
   1050         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   1051 
   1052     [descendantWebHTMLViews release];
   1053 
   1054 #ifndef NDEBUG
   1055     _private->enumeratingSubviews = NO;
   1056 #endif
   1057 }
   1058 
   1059 - (void)_web_setPrintingModeRecursiveAndAdjustViewSize
   1060 {
   1061     [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:YES];
   1062 
   1063 #ifndef NDEBUG
   1064     _private->enumeratingSubviews = YES;
   1065 #endif
   1066 
   1067     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
   1068 
   1069     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
   1070 
   1071     unsigned count = [descendantWebHTMLViews count];
   1072     for (unsigned i = 0; i < count; ++i)
   1073         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:YES];
   1074 
   1075     [descendantWebHTMLViews release];
   1076 
   1077 #ifndef NDEBUG
   1078     _private->enumeratingSubviews = NO;
   1079 #endif
   1080 }
   1081 
   1082 @end
   1083 
   1084 @implementation WebHTMLView (WebPrivate)
   1085 
   1086 + (NSArray *)supportedMIMETypes
   1087 {
   1088     return [WebHTMLRepresentation supportedMIMETypes];
   1089 }
   1090 
   1091 + (NSArray *)supportedImageMIMETypes
   1092 {
   1093     return [WebHTMLRepresentation supportedImageMIMETypes];
   1094 }
   1095 
   1096 + (NSArray *)supportedNonImageMIMETypes
   1097 {
   1098     return [WebHTMLRepresentation supportedNonImageMIMETypes];
   1099 }
   1100 
   1101 + (NSArray *)unsupportedTextMIMETypes
   1102 {
   1103     return [NSArray arrayWithObjects:
   1104         @"text/calendar",       // iCal
   1105         @"text/x-calendar",
   1106         @"text/x-vcalendar",
   1107         @"text/vcalendar",
   1108         @"text/vcard",          // vCard
   1109         @"text/x-vcard",
   1110         @"text/directory",
   1111         @"text/ldif",           // Netscape Address Book
   1112         @"text/qif",            // Quicken
   1113         @"text/x-qif",
   1114         @"text/x-csv",          // CSV (for Address Book and Microsoft Outlook)
   1115         @"text/x-vcf",          // vCard type used in Sun affinity app
   1116         @"text/rtf",            // Rich Text Format
   1117         nil];
   1118 }
   1119 
   1120 + (void)_postFlagsChangedEvent:(NSEvent *)flagsChangedEvent
   1121 {
   1122     // This is a workaround for: <rdar://problem/2981619> NSResponder_Private should include notification for FlagsChanged
   1123     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
   1124         location:[[flagsChangedEvent window] convertScreenToBase:[NSEvent mouseLocation]]
   1125         modifierFlags:[flagsChangedEvent modifierFlags]
   1126         timestamp:[flagsChangedEvent timestamp]
   1127         windowNumber:[flagsChangedEvent windowNumber]
   1128         context:[flagsChangedEvent context]
   1129         eventNumber:0 clickCount:0 pressure:0];
   1130 
   1131     // Pretend it's a mouse move.
   1132     [[NSNotificationCenter defaultCenter]
   1133         postNotificationName:WKMouseMovedNotification() object:self
   1134         userInfo:[NSDictionary dictionaryWithObject:fakeEvent forKey:@"NSEvent"]];
   1135 }
   1136 
   1137 - (id)_bridge
   1138 {
   1139     // This method exists to maintain compatibility with Leopard's Dictionary.app, since it
   1140     // calls _bridge to get access to convertNSRangeToDOMRange: and convertDOMRangeToNSRange:.
   1141     // Return the WebFrame, which implements the compatibility methods. <rdar://problem/6002160>
   1142     return [self _frame];
   1143 }
   1144 
   1145 - (void)_updateMouseoverWithFakeEvent
   1146 {
   1147     [self _cancelUpdateMouseoverTimer];
   1148 
   1149     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
   1150         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
   1151         modifierFlags:[[NSApp currentEvent] modifierFlags]
   1152         timestamp:[NSDate timeIntervalSinceReferenceDate]
   1153         windowNumber:[[self window] windowNumber]
   1154         context:[[NSApp currentEvent] context]
   1155         eventNumber:0 clickCount:0 pressure:0];
   1156 
   1157     [self _updateMouseoverWithEvent:fakeEvent];
   1158 }
   1159 
   1160 static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info)
   1161 {
   1162     WebHTMLView *view = (WebHTMLView *)info;
   1163 
   1164     [view _updateMouseoverWithFakeEvent];
   1165 }
   1166 
   1167 - (void)_frameOrBoundsChanged
   1168 {
   1169     NSPoint origin = [[self superview] bounds].origin;
   1170     if (!NSEqualPoints(_private->lastScrollPosition, origin)) {
   1171         if (Frame* coreFrame = core([self _frame])) {
   1172             if (FrameView* coreView = coreFrame->view())
   1173                 coreView->scrollPositionChanged();
   1174         }
   1175 
   1176         [_private->completionController endRevertingChange:NO moveLeft:NO];
   1177 
   1178         WebView *webView = [self _webView];
   1179         [[webView _UIDelegateForwarder] webView:webView didScrollDocumentInFrameView:[self _frameView]];
   1180     }
   1181     _private->lastScrollPosition = origin;
   1182 
   1183     if ([self window] && !_private->closed && !_private->updateMouseoverTimer) {
   1184         CFRunLoopTimerContext context = { 0, self, NULL, NULL, NULL };
   1185 
   1186         // Use a 100ms delay so that the synthetic mouse over update doesn't cause cursor thrashing when pages are loading
   1187         // and scrolling rapidly back to back.
   1188         _private->updateMouseoverTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 0.1, 0, 0, 0,
   1189                                                               _updateMouseoverTimerCallback, &context);
   1190         CFRunLoopAddTimer(CFRunLoopGetCurrent(), _private->updateMouseoverTimer, kCFRunLoopDefaultMode);
   1191     }
   1192 
   1193 #if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD)
   1194     [self _updateLayerHostingViewPosition];
   1195 #endif
   1196 }
   1197 
   1198 - (void)_setAsideSubviews
   1199 {
   1200     ASSERT(!_private->subviewsSetAside);
   1201     ASSERT(_private->savedSubviews == nil);
   1202     _private->savedSubviews = _subviews;
   1203 #if USE(ACCELERATED_COMPOSITING)
   1204     // We need to keep the layer-hosting view in the subviews, otherwise the layers flash.
   1205     if (_private->layerHostingView) {
   1206         NSArray* newSubviews = [[NSArray alloc] initWithObjects:_private->layerHostingView, nil];
   1207         _subviews = newSubviews;
   1208     } else
   1209         _subviews = nil;
   1210 #else
   1211     _subviews = nil;
   1212 #endif
   1213     _private->subviewsSetAside = YES;
   1214  }
   1215 
   1216  - (void)_restoreSubviews
   1217  {
   1218     ASSERT(_private->subviewsSetAside);
   1219 #if USE(ACCELERATED_COMPOSITING)
   1220     if (_private->layerHostingView) {
   1221         [_subviews release];
   1222         _subviews = _private->savedSubviews;
   1223     } else {
   1224         ASSERT(_subviews == nil);
   1225         _subviews = _private->savedSubviews;
   1226     }
   1227 #else
   1228     ASSERT(_subviews == nil);
   1229     _subviews = _private->savedSubviews;
   1230 #endif
   1231     _private->savedSubviews = nil;
   1232     _private->subviewsSetAside = NO;
   1233 }
   1234 
   1235 #ifndef NDEBUG
   1236 
   1237 - (void)didAddSubview:(NSView *)subview
   1238 {
   1239     if (_private->enumeratingSubviews)
   1240         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]));
   1241 }
   1242 
   1243 - (void)willRemoveSubview:(NSView *)subview
   1244 {
   1245     // Have to null-check _private, since this can be called via -dealloc when
   1246     // cleaning up the the layerHostingView.
   1247     if (_private && _private->enumeratingSubviews)
   1248         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]));
   1249 }
   1250 
   1251 #endif
   1252 
   1253 #ifdef BUILDING_ON_TIGER
   1254 
   1255 // This is called when we are about to draw, but before our dirty rect is propagated to our ancestors.
   1256 // That's the perfect time to do a layout, except that ideally we'd want to be sure that we're dirty
   1257 // before doing it. As a compromise, when we're opaque we do the layout only when actually asked to
   1258 // draw, but when we're transparent we do the layout at this stage so views behind us know that they
   1259 // need to be redrawn (in case the layout causes some things to get dirtied).
   1260 - (void)_propagateDirtyRectsToOpaqueAncestors
   1261 {
   1262     if (![[self _webView] drawsBackground])
   1263         [self _web_layoutIfNeededRecursive];
   1264     [super _propagateDirtyRectsToOpaqueAncestors];
   1265 }
   1266 
   1267 #else
   1268 
   1269 - (void)viewWillDraw
   1270 {
   1271     // On window close we will be called when the datasource is nil, then hit an assert in _topHTMLView
   1272     // So check if the dataSource is nil before calling [self _isTopHTMLView], this can be removed
   1273     // once the FIXME in _isTopHTMLView is fixed.
   1274     if (_private->dataSource && [self _isTopHTMLView])
   1275         [self _web_layoutIfNeededRecursive];
   1276     [super viewWillDraw];
   1277 }
   1278 
   1279 #endif
   1280 
   1281 // Don't let AppKit even draw subviews. We take care of that.
   1282 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView
   1283 {
   1284     // This helps when we print as part of a larger print process.
   1285     // If the WebHTMLView itself is what we're printing, then we will never have to do this.
   1286     BOOL wasInPrintingMode = _private->printing;
   1287     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
   1288     if (isPrinting) {
   1289         if (!wasInPrintingMode)
   1290             [self _web_setPrintingModeRecursive];
   1291 #ifndef BUILDING_ON_TIGER
   1292         else
   1293             [self _web_layoutIfNeededRecursive];
   1294 #endif
   1295     } else if (wasInPrintingMode)
   1296         [self _web_clearPrintingModeRecursive];
   1297 
   1298 #ifndef BUILDING_ON_TIGER
   1299     // There are known cases where -viewWillDraw is not called on all views being drawn.
   1300     // See <rdar://problem/6964278> for example. Performing layout at this point prevents us from
   1301     // trying to paint without layout (which WebCore now refuses to do, instead bailing out without
   1302     // drawing at all), but we may still fail to update and regions dirtied by the layout which are
   1303     // not already dirty.
   1304     if ([self _needsLayout]) {
   1305         LOG_ERROR("View needs layout. Either -viewWillDraw wasn't called or layout was invalidated during the display operation. Performing layout now.");
   1306         [self _web_layoutIfNeededRecursive];
   1307     }
   1308 #else
   1309     // Because Tiger does not have viewWillDraw we need to do layout here.
   1310     [self _web_layoutIfNeededRecursive];
   1311     [_subviews makeObjectsPerformSelector:@selector(_propagateDirtyRectsToOpaqueAncestors)];
   1312 #endif
   1313 
   1314     [self _setAsideSubviews];
   1315     [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect isVisibleRect:isVisibleRect rectIsVisibleRectForView:visibleView topView:topView];
   1316     [self _restoreSubviews];
   1317 
   1318     if (wasInPrintingMode != isPrinting) {
   1319         if (wasInPrintingMode)
   1320             [self _web_setPrintingModeRecursive];
   1321         else
   1322             [self _web_clearPrintingModeRecursive];
   1323     }
   1324 }
   1325 
   1326 // Don't let AppKit even draw subviews. We take care of that.
   1327 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect
   1328 {
   1329     BOOL needToSetAsideSubviews = !_private->subviewsSetAside;
   1330 
   1331     BOOL wasInPrintingMode = _private->printing;
   1332     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
   1333 
   1334     if (needToSetAsideSubviews) {
   1335         // This helps when we print as part of a larger print process.
   1336         // If the WebHTMLView itself is what we're printing, then we will never have to do this.
   1337         if (isPrinting) {
   1338             if (!wasInPrintingMode)
   1339                 [self _web_setPrintingModeRecursive];
   1340 #ifndef BUILDING_ON_TIGER
   1341             else
   1342                 [self _web_layoutIfNeededRecursive];
   1343 #endif
   1344         } else if (wasInPrintingMode)
   1345             [self _web_clearPrintingModeRecursive];
   1346 
   1347 #ifdef BUILDING_ON_TIGER
   1348 
   1349         // Because Tiger does not have viewWillDraw we need to do layout here.
   1350         NSRect boundsBeforeLayout = [self bounds];
   1351         if (!NSIsEmptyRect(visRect))
   1352             [self _web_layoutIfNeededRecursive];
   1353 
   1354         // If layout changes the view's bounds, then we need to recompute the visRect.
   1355         // That's because the visRect passed to us was based on the bounds at the time
   1356         // we were called. This method is only displayed to draw "all", so it's safe
   1357         // to just call visibleRect to compute the entire rectangle.
   1358         if (!NSEqualRects(boundsBeforeLayout, [self bounds]))
   1359             visRect = [self visibleRect];
   1360 
   1361 #endif
   1362 
   1363         [self _setAsideSubviews];
   1364     }
   1365 
   1366     [super _recursiveDisplayAllDirtyWithLockFocus:needsLockFocus visRect:visRect];
   1367 
   1368     if (needToSetAsideSubviews) {
   1369         if (wasInPrintingMode != isPrinting) {
   1370             if (wasInPrintingMode)
   1371                 [self _web_setPrintingModeRecursive];
   1372             else
   1373                 [self _web_clearPrintingModeRecursive];
   1374         }
   1375 
   1376         [self _restoreSubviews];
   1377     }
   1378 }
   1379 
   1380 // Don't let AppKit even draw subviews. We take care of that.
   1381 - (void)_recursive:(BOOL)recurse displayRectIgnoringOpacity:(NSRect)displayRect inContext:(NSGraphicsContext *)context topView:(BOOL)topView
   1382 {
   1383 #ifdef BUILDING_ON_TIGER
   1384     // Because Tiger does not have viewWillDraw we need to do layout here.
   1385     [self _web_layoutIfNeededRecursive];
   1386 #endif
   1387 
   1388     [self _setAsideSubviews];
   1389     [super _recursive:recurse displayRectIgnoringOpacity:displayRect inContext:context topView:topView];
   1390     [self _restoreSubviews];
   1391 }
   1392 
   1393 - (BOOL)_insideAnotherHTMLView
   1394 {
   1395     return self != [self _topHTMLView];
   1396 }
   1397 
   1398 - (NSView *)hitTest:(NSPoint)point
   1399 {
   1400     // WebHTMLView objects handle all events for objects inside them.
   1401     // To get those events, we prevent hit testing from AppKit.
   1402 
   1403     // But there are three exceptions to this:
   1404     //   1) For right mouse clicks and control clicks we don't yet have an implementation
   1405     //      that works for nested views, so we let the hit testing go through the
   1406     //      standard NSView code path (needs to be fixed, see bug 4361618).
   1407     //   2) Java depends on doing a hit test inside it's mouse moved handling,
   1408     //      so we let the hit testing go through the standard NSView code path
   1409     //      when the current event is a mouse move (except when we are calling
   1410     //      from _updateMouseoverWithEvent, so we have to use a global,
   1411     //      forceWebHTMLViewHitTest, for that)
   1412     //   3) The acceptsFirstMouse: and shouldDelayWindowOrderingForEvent: methods
   1413     //      both need to figure out which view to check with inside the WebHTMLView.
   1414     //      They use a global to change the behavior of hitTest: so they can get the
   1415     //      right view. The global is forceNSViewHitTest and the method they use to
   1416     //      do the hit testing is _hitViewForEvent:. (But this does not work correctly
   1417     //      when there is HTML overlapping the view, see bug 4361626)
   1418     //   4) NSAccessibilityHitTest relies on this for checking the cursor position.
   1419     //      Our check for that is whether the event is NSFlagsChanged.  This works
   1420     //      for VoiceOver's Control-Option-F5 command (move focus to item under cursor)
   1421     //      and Dictionary's Command-Control-D (open dictionary popup for item under cursor).
   1422     //      This is of course a hack.
   1423 
   1424     if (_private->closed)
   1425         return nil;
   1426 
   1427     BOOL captureHitsOnSubviews;
   1428     if (forceNSViewHitTest)
   1429         captureHitsOnSubviews = NO;
   1430     else if (forceWebHTMLViewHitTest)
   1431         captureHitsOnSubviews = YES;
   1432     else {
   1433         NSEvent *event = [[self window] currentEvent];
   1434         captureHitsOnSubviews = !([event type] == NSMouseMoved
   1435             || [event type] == NSRightMouseDown
   1436             || ([event type] == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask) != 0)
   1437             || [event type] == NSFlagsChanged);
   1438     }
   1439 
   1440     if (!captureHitsOnSubviews) {
   1441         NSView* hitView = [super hitTest:point];
   1442 #if USE(ACCELERATED_COMPOSITING)
   1443         if (_private && hitView == _private->layerHostingView)
   1444             hitView = self;
   1445 #endif
   1446         return hitView;
   1447     }
   1448     if ([[self superview] mouse:point inRect:[self frame]])
   1449         return self;
   1450     return nil;
   1451 }
   1452 
   1453 - (void)_clearLastHitViewIfSelf
   1454 {
   1455     if (lastHitView == self)
   1456         lastHitView = nil;
   1457 }
   1458 
   1459 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
   1460 {
   1461     ASSERT(_private->trackingRectOwner == nil);
   1462     _private->trackingRectOwner = owner;
   1463     _private->trackingRectUserData = data;
   1464     return TRACKING_RECT_TAG;
   1465 }
   1466 
   1467 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
   1468 {
   1469     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
   1470     ASSERT(_private->trackingRectOwner == nil);
   1471     _private->trackingRectOwner = owner;
   1472     _private->trackingRectUserData = data;
   1473     return TRACKING_RECT_TAG;
   1474 }
   1475 
   1476 - (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count
   1477 {
   1478     ASSERT(count == 1);
   1479     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
   1480     ASSERT(_private->trackingRectOwner == nil);
   1481     _private->trackingRectOwner = owner;
   1482     _private->trackingRectUserData = userDataList[0];
   1483     trackingNums[0] = TRACKING_RECT_TAG;
   1484 }
   1485 
   1486 - (void)removeTrackingRect:(NSTrackingRectTag)tag
   1487 {
   1488     if (tag == 0)
   1489         return;
   1490 
   1491     if (_private && (tag == TRACKING_RECT_TAG)) {
   1492         _private->trackingRectOwner = nil;
   1493         return;
   1494     }
   1495 
   1496     if (_private && (tag == _private->lastToolTipTag)) {
   1497         [super removeTrackingRect:tag];
   1498         _private->lastToolTipTag = 0;
   1499         return;
   1500     }
   1501 
   1502     // If any other tracking rect is being removed, we don't know how it was created
   1503     // and it's possible there's a leak involved (see 3500217)
   1504     ASSERT_NOT_REACHED();
   1505 }
   1506 
   1507 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count
   1508 {
   1509     int i;
   1510     for (i = 0; i < count; ++i) {
   1511         int tag = tags[i];
   1512         if (tag == 0)
   1513             continue;
   1514         ASSERT(tag == TRACKING_RECT_TAG);
   1515         if (_private != nil) {
   1516             _private->trackingRectOwner = nil;
   1517         }
   1518     }
   1519 }
   1520 
   1521 - (void)_sendToolTipMouseExited
   1522 {
   1523     // Nothing matters except window, trackingNumber, and userData.
   1524     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited
   1525         location:NSMakePoint(0, 0)
   1526         modifierFlags:0
   1527         timestamp:0
   1528         windowNumber:[[self window] windowNumber]
   1529         context:NULL
   1530         eventNumber:0
   1531         trackingNumber:TRACKING_RECT_TAG
   1532         userData:_private->trackingRectUserData];
   1533     [_private->trackingRectOwner mouseExited:fakeEvent];
   1534 }
   1535 
   1536 - (void)_sendToolTipMouseEntered
   1537 {
   1538     // Nothing matters except window, trackingNumber, and userData.
   1539     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered
   1540         location:NSMakePoint(0, 0)
   1541         modifierFlags:0
   1542         timestamp:0
   1543         windowNumber:[[self window] windowNumber]
   1544         context:NULL
   1545         eventNumber:0
   1546         trackingNumber:TRACKING_RECT_TAG
   1547         userData:_private->trackingRectUserData];
   1548     [_private->trackingRectOwner mouseEntered:fakeEvent];
   1549 }
   1550 
   1551 - (void)_setToolTip:(NSString *)string
   1552 {
   1553     NSString *toolTip = [string length] == 0 ? nil : string;
   1554     NSString *oldToolTip = _private->toolTip;
   1555     if ((toolTip == nil || oldToolTip == nil) ? toolTip == oldToolTip : [toolTip isEqualToString:oldToolTip]) {
   1556         return;
   1557     }
   1558     if (oldToolTip) {
   1559         [self _sendToolTipMouseExited];
   1560         [oldToolTip release];
   1561     }
   1562     _private->toolTip = [toolTip copy];
   1563     if (toolTip) {
   1564         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
   1565         [self removeAllToolTips];
   1566         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
   1567         _private->lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL];
   1568         [self _sendToolTipMouseEntered];
   1569     }
   1570 }
   1571 
   1572 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
   1573 {
   1574     return [[_private->toolTip copy] autorelease];
   1575 }
   1576 
   1577 - (void)_updateMouseoverWithEvent:(NSEvent *)event
   1578 {
   1579     if (_private->closed)
   1580         return;
   1581 
   1582     NSView *contentView = [[event window] contentView];
   1583     NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil];
   1584 
   1585     forceWebHTMLViewHitTest = YES;
   1586     NSView *hitView = [contentView hitTest:locationForHitTest];
   1587     forceWebHTMLViewHitTest = NO;
   1588 
   1589     WebHTMLView *view = nil;
   1590     if ([hitView isKindOfClass:[WebHTMLView class]] && ![[(WebHTMLView *)hitView _webView] isHoverFeedbackSuspended])
   1591         view = (WebHTMLView *)hitView;
   1592 
   1593     if (view)
   1594         [view retain];
   1595 
   1596     if (lastHitView != view && lastHitView && [lastHitView _frame]) {
   1597         // If we are moving out of a view (or frame), let's pretend the mouse moved
   1598         // all the way out of that view. But we have to account for scrolling, because
   1599         // WebCore doesn't understand our clipping.
   1600         NSRect visibleRect = [[[[lastHitView _frame] frameView] _scrollView] documentVisibleRect];
   1601         float yScroll = visibleRect.origin.y;
   1602         float xScroll = visibleRect.origin.x;
   1603 
   1604         NSEvent *event = [NSEvent mouseEventWithType:NSMouseMoved
   1605             location:NSMakePoint(-1 - xScroll, -1 - yScroll)
   1606             modifierFlags:[[NSApp currentEvent] modifierFlags]
   1607             timestamp:[NSDate timeIntervalSinceReferenceDate]
   1608             windowNumber:[[view window] windowNumber]
   1609             context:[[NSApp currentEvent] context]
   1610             eventNumber:0 clickCount:0 pressure:0];
   1611         if (Frame* lastHitCoreFrame = core([lastHitView _frame]))
   1612             lastHitCoreFrame->eventHandler()->mouseMoved(event);
   1613     }
   1614 
   1615     lastHitView = view;
   1616 
   1617     if (view) {
   1618         if (Frame* coreFrame = core([view _frame]))
   1619             coreFrame->eventHandler()->mouseMoved(event);
   1620 
   1621         [view release];
   1622     }
   1623 }
   1624 
   1625 // keep in sync with WebPasteboardHelper::insertablePasteboardTypes
   1626 + (NSArray *)_insertablePasteboardTypes
   1627 {
   1628     static NSArray *types = nil;
   1629     if (!types) {
   1630         types = [[NSArray alloc] initWithObjects:WebArchivePboardType, NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPDFPboardType,
   1631 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
   1632             NSPICTPboardType,
   1633 #endif
   1634             NSURLPboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, NSColorPboardType, kUTTypePNG, nil];
   1635         CFRetain(types);
   1636     }
   1637     return types;
   1638 }
   1639 
   1640 + (NSArray *)_selectionPasteboardTypes
   1641 {
   1642     // FIXME: We should put data for NSHTMLPboardType on the pasteboard but Microsoft Excel doesn't like our format of HTML (3640423).
   1643     return [NSArray arrayWithObjects:WebArchivePboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, nil];
   1644 }
   1645 
   1646 - (NSImage *)_dragImageForURL:(NSString*)urlString withLabel:(NSString*)label
   1647 {
   1648     BOOL drawURLString = YES;
   1649     BOOL clipURLString = NO, clipLabelString = NO;
   1650 
   1651     if (!label) {
   1652         drawURLString = NO;
   1653         label = urlString;
   1654     }
   1655 
   1656     NSFont *labelFont = [[NSFontManager sharedFontManager] convertFont:[NSFont systemFontOfSize:DRAG_LINK_LABEL_FONT_SIZE]
   1657                                                            toHaveTrait:NSBoldFontMask];
   1658     NSFont *urlFont = [NSFont systemFontOfSize: DRAG_LINK_URL_FONT_SIZE];
   1659     NSSize labelSize;
   1660     labelSize.width = [label _web_widthWithFont: labelFont];
   1661     labelSize.height = [labelFont ascender] - [labelFont descender];
   1662     if (labelSize.width > MAX_DRAG_LABEL_WIDTH){
   1663         labelSize.width = MAX_DRAG_LABEL_WIDTH;
   1664         clipLabelString = YES;
   1665     }
   1666 
   1667     NSSize imageSize, urlStringSize;
   1668     imageSize.width = labelSize.width + DRAG_LABEL_BORDER_X * 2.0f;
   1669     imageSize.height = labelSize.height + DRAG_LABEL_BORDER_Y * 2.0f;
   1670     if (drawURLString) {
   1671         urlStringSize.width = [urlString _web_widthWithFont: urlFont];
   1672         urlStringSize.height = [urlFont ascender] - [urlFont descender];
   1673         imageSize.height += urlStringSize.height;
   1674         if (urlStringSize.width > MAX_DRAG_LABEL_WIDTH) {
   1675             imageSize.width = max(MAX_DRAG_LABEL_WIDTH + DRAG_LABEL_BORDER_X * 2, MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP);
   1676             clipURLString = YES;
   1677         } else {
   1678             imageSize.width = max(labelSize.width + DRAG_LABEL_BORDER_X * 2, urlStringSize.width + DRAG_LABEL_BORDER_X * 2);
   1679         }
   1680     }
   1681     NSImage *dragImage = [[[NSImage alloc] initWithSize: imageSize] autorelease];
   1682     [dragImage lockFocus];
   1683 
   1684     [[NSColor colorWithDeviceRed: 0.7f green: 0.7f blue: 0.7f alpha: 0.8f] set];
   1685 
   1686     // Drag a rectangle with rounded corners/
   1687     NSBezierPath *path = [NSBezierPath bezierPath];
   1688     [path appendBezierPathWithOvalInRect: NSMakeRect(0.0f, 0.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
   1689     [path appendBezierPathWithOvalInRect: NSMakeRect(0, imageSize.height - DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
   1690     [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS * 2.0f, imageSize.height - DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
   1691     [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS * 2.0f, 0.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
   1692 
   1693     [path appendBezierPathWithRect: NSMakeRect(DRAG_LABEL_RADIUS, 0.0f, imageSize.width - DRAG_LABEL_RADIUS * 2.0f, imageSize.height)];
   1694     [path appendBezierPathWithRect: NSMakeRect(0.0f, DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS + 10.0f, imageSize.height - 2.0f * DRAG_LABEL_RADIUS)];
   1695     [path appendBezierPathWithRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS - 20.0f, DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS + 20.0f, imageSize.height - 2.0f * DRAG_LABEL_RADIUS)];
   1696     [path fill];
   1697 
   1698     NSColor *topColor = [NSColor colorWithDeviceWhite:0.0f alpha:0.75f];
   1699     NSColor *bottomColor = [NSColor colorWithDeviceWhite:1.0f alpha:0.5f];
   1700     if (drawURLString) {
   1701         if (clipURLString)
   1702             urlString = [WebStringTruncator centerTruncateString: urlString toWidth:imageSize.width - (DRAG_LABEL_BORDER_X * 2.0f) withFont:urlFont];
   1703 
   1704         [urlString _web_drawDoubledAtPoint:NSMakePoint(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y - [urlFont descender])
   1705                               withTopColor:topColor bottomColor:bottomColor font:urlFont];
   1706     }
   1707 
   1708     if (clipLabelString)
   1709         label = [WebStringTruncator rightTruncateString: label toWidth:imageSize.width - (DRAG_LABEL_BORDER_X * 2.0f) withFont:labelFont];
   1710     [label _web_drawDoubledAtPoint:NSMakePoint (DRAG_LABEL_BORDER_X, imageSize.height - DRAG_LABEL_BORDER_Y_OFFSET - [labelFont pointSize])
   1711                       withTopColor:topColor bottomColor:bottomColor font:labelFont];
   1712 
   1713     [dragImage unlockFocus];
   1714 
   1715     return dragImage;
   1716 }
   1717 
   1718 - (NSImage *)_dragImageForLinkElement:(NSDictionary *)element
   1719 {
   1720     NSURL *linkURL = [element objectForKey: WebElementLinkURLKey];
   1721 
   1722     NSString *label = [element objectForKey: WebElementLinkLabelKey];
   1723     NSString *urlString = [linkURL _web_userVisibleString];
   1724     return [self _dragImageForURL:urlString withLabel:label];
   1725 }
   1726 
   1727 - (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
   1728 {
   1729     [self setPromisedDragTIFFDataSource:0];
   1730 }
   1731 
   1732 - (void)pasteboard:(NSPasteboard *)pasteboard provideDataForType:(NSString *)type
   1733 {
   1734     if ([type isEqual:NSRTFDPboardType] && [[pasteboard types] containsObject:WebArchivePboardType]) {
   1735         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
   1736         [pasteboard _web_writePromisedRTFDFromArchive:archive containsImage:[[pasteboard types] containsObject:NSTIFFPboardType]];
   1737         [archive release];
   1738     } else if ([type isEqual:NSTIFFPboardType] && [self promisedDragTIFFDataSource]) {
   1739         if (Image* image = [self promisedDragTIFFDataSource]->image())
   1740             [pasteboard setData:(NSData *)image->getTIFFRepresentation() forType:NSTIFFPboardType];
   1741         [self setPromisedDragTIFFDataSource:0];
   1742     }
   1743 }
   1744 
   1745 - (void)_handleAutoscrollForMouseDragged:(NSEvent *)event
   1746 {
   1747     [self autoscroll:event];
   1748     [self _startAutoscrollTimer:event];
   1749 }
   1750 
   1751 - (WebPluginController *)_pluginController
   1752 {
   1753     return _private->pluginController;
   1754 }
   1755 
   1756 - (void)_layoutForPrinting
   1757 {
   1758     // Set printing mode temporarily so we can adjust the size of the view. This will allow
   1759     // AppKit's pagination code to use the correct height for the page content. Leaving printing
   1760     // mode on indefinitely would interfere with Mail's printing mechanism (at least), so we just
   1761     // turn it off again after adjusting the size.
   1762     [self _web_setPrintingModeRecursiveAndAdjustViewSize];
   1763     [self _web_clearPrintingModeRecursive];
   1764 }
   1765 
   1766 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
   1767 {
   1768     if (!pasteString || !rangeToReplace || ![[self _webView] smartInsertDeleteEnabled]) {
   1769         if (beforeString)
   1770             *beforeString = nil;
   1771         if (afterString)
   1772             *afterString = nil;
   1773         return;
   1774     }
   1775 
   1776     [[self _frame] _smartInsertForString:pasteString replacingRange:rangeToReplace beforeString:beforeString afterString:afterString];
   1777 }
   1778 
   1779 - (BOOL)_canSmartReplaceWithPasteboard:(NSPasteboard *)pasteboard
   1780 {
   1781     return [[self _webView] smartInsertDeleteEnabled] && [[pasteboard types] containsObject:WebSmartPastePboardType];
   1782 }
   1783 
   1784 - (void)_startAutoscrollTimer:(NSEvent *)triggerEvent
   1785 {
   1786     if (_private->autoscrollTimer == nil) {
   1787         _private->autoscrollTimer = [[NSTimer scheduledTimerWithTimeInterval:AUTOSCROLL_INTERVAL
   1788             target:self selector:@selector(_autoscroll) userInfo:nil repeats:YES] retain];
   1789         _private->autoscrollTriggerEvent = [triggerEvent retain];
   1790     }
   1791 }
   1792 
   1793 // FIXME: _selectionRect is deprecated in favor of selectionRect, which is in protocol WebDocumentSelection.
   1794 // We can't remove this yet because it's still in use by Mail.
   1795 - (NSRect)_selectionRect
   1796 {
   1797     return [self selectionRect];
   1798 }
   1799 
   1800 - (void)_stopAutoscrollTimer
   1801 {
   1802     NSTimer *timer = _private->autoscrollTimer;
   1803     _private->autoscrollTimer = nil;
   1804     [_private->autoscrollTriggerEvent release];
   1805     _private->autoscrollTriggerEvent = nil;
   1806     [timer invalidate];
   1807     [timer release];
   1808 }
   1809 
   1810 - (void)_autoscroll
   1811 {
   1812     // Guarantee that the autoscroll timer is invalidated, even if we don't receive
   1813     // a mouse up event.
   1814     BOOL isStillDown = CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft);
   1815     if (!isStillDown){
   1816         [self _stopAutoscrollTimer];
   1817         return;
   1818     }
   1819 
   1820     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
   1821         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
   1822         modifierFlags:[[NSApp currentEvent] modifierFlags]
   1823         timestamp:[NSDate timeIntervalSinceReferenceDate]
   1824         windowNumber:[[self window] windowNumber]
   1825         context:[[NSApp currentEvent] context]
   1826         eventNumber:0 clickCount:0 pressure:0];
   1827     [self mouseDragged:fakeEvent];
   1828 }
   1829 
   1830 - (BOOL)_canEdit
   1831 {
   1832     Frame* coreFrame = core([self _frame]);
   1833     return coreFrame && coreFrame->editor()->canEdit();
   1834 }
   1835 
   1836 - (BOOL)_canEditRichly
   1837 {
   1838     Frame* coreFrame = core([self _frame]);
   1839     return coreFrame && coreFrame->editor()->canEditRichly();
   1840 }
   1841 
   1842 - (BOOL)_canAlterCurrentSelection
   1843 {
   1844     return [self _hasSelectionOrInsertionPoint] && [self _isEditable];
   1845 }
   1846 
   1847 - (BOOL)_hasSelection
   1848 {
   1849     Frame* coreFrame = core([self _frame]);
   1850     return coreFrame && coreFrame->selection()->isRange();
   1851 }
   1852 
   1853 - (BOOL)_hasSelectionOrInsertionPoint
   1854 {
   1855     Frame* coreFrame = core([self _frame]);
   1856     return coreFrame && coreFrame->selection()->isCaretOrRange();
   1857 }
   1858 
   1859 - (BOOL)_hasInsertionPoint
   1860 {
   1861     Frame* coreFrame = core([self _frame]);
   1862     return coreFrame && coreFrame->selection()->isCaret();
   1863 }
   1864 
   1865 - (BOOL)_isEditable
   1866 {
   1867     Frame* coreFrame = core([self _frame]);
   1868     return coreFrame && coreFrame->selection()->isContentEditable();
   1869 }
   1870 
   1871 - (BOOL)_transparentBackground
   1872 {
   1873     return _private->transparentBackground;
   1874 }
   1875 
   1876 - (void)_setTransparentBackground:(BOOL)f
   1877 {
   1878     _private->transparentBackground = f;
   1879 }
   1880 
   1881 - (NSImage *)_selectionDraggingImage
   1882 {
   1883     if ([self _hasSelection]) {
   1884         NSImage *dragImage = core([self _frame])->selectionImage();
   1885         [dragImage _web_dissolveToFraction:WebDragImageAlpha];
   1886         return dragImage;
   1887     }
   1888     return nil;
   1889 }
   1890 
   1891 - (NSRect)_selectionDraggingRect
   1892 {
   1893     // Mail currently calls this method. We can eliminate it when Mail no longer calls it.
   1894     return [self selectionRect];
   1895 }
   1896 
   1897 - (DOMNode *)_insertOrderedList
   1898 {
   1899     Frame* coreFrame = core([self _frame]);
   1900     return coreFrame ? kit(coreFrame->editor()->insertOrderedList().get()) : nil;
   1901 }
   1902 
   1903 - (DOMNode *)_insertUnorderedList
   1904 {
   1905     Frame* coreFrame = core([self _frame]);
   1906     return coreFrame ? kit(coreFrame->editor()->insertUnorderedList().get()) : nil;
   1907 }
   1908 
   1909 - (BOOL)_canIncreaseSelectionListLevel
   1910 {
   1911     Frame* coreFrame = core([self _frame]);
   1912     return coreFrame && coreFrame->editor()->canIncreaseSelectionListLevel();
   1913 }
   1914 
   1915 - (BOOL)_canDecreaseSelectionListLevel
   1916 {
   1917     Frame* coreFrame = core([self _frame]);
   1918     return coreFrame && coreFrame->editor()->canDecreaseSelectionListLevel();
   1919 }
   1920 
   1921 - (DOMNode *)_increaseSelectionListLevel
   1922 {
   1923     Frame* coreFrame = core([self _frame]);
   1924     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevel().get()) : nil;
   1925 }
   1926 
   1927 - (DOMNode *)_increaseSelectionListLevelOrdered
   1928 {
   1929     Frame* coreFrame = core([self _frame]);
   1930     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevelOrdered().get()) : nil;
   1931 }
   1932 
   1933 - (DOMNode *)_increaseSelectionListLevelUnordered
   1934 {
   1935     Frame* coreFrame = core([self _frame]);
   1936     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevelUnordered().get()) : nil;
   1937 }
   1938 
   1939 - (void)_decreaseSelectionListLevel
   1940 {
   1941     Frame* coreFrame = core([self _frame]);
   1942     if (coreFrame)
   1943         coreFrame->editor()->decreaseSelectionListLevel();
   1944 }
   1945 
   1946 - (void)_setHighlighter:(id<WebHTMLHighlighter>)highlighter ofType:(NSString*)type
   1947 {
   1948     if (!_private->highlighters)
   1949         _private->highlighters = [[NSMutableDictionary alloc] init];
   1950     [_private->highlighters setObject:highlighter forKey:type];
   1951 }
   1952 
   1953 - (void)_removeHighlighterOfType:(NSString*)type
   1954 {
   1955     [_private->highlighters removeObjectForKey:type];
   1956 }
   1957 
   1958 - (void)_writeSelectionToPasteboard:(NSPasteboard *)pasteboard
   1959 {
   1960     ASSERT([self _hasSelection]);
   1961     NSArray *types = [self pasteboardTypesForSelection];
   1962 
   1963     // Don't write RTFD to the pasteboard when the copied attributed string has no attachments.
   1964     NSAttributedString *attributedString = [self selectedAttributedString];
   1965     NSMutableArray *mutableTypes = nil;
   1966     if (![attributedString containsAttachments]) {
   1967         mutableTypes = [types mutableCopy];
   1968         [mutableTypes removeObject:NSRTFDPboardType];
   1969         types = mutableTypes;
   1970     }
   1971 
   1972     [pasteboard declareTypes:types owner:[self _topHTMLView]];
   1973     [self _writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard cachedAttributedString:attributedString];
   1974     [mutableTypes release];
   1975 }
   1976 
   1977 - (void)close
   1978 {
   1979     // Check for a nil _private here in case we were created with initWithCoder. In that case, the WebView is just throwing
   1980     // out the archived WebHTMLView and recreating a new one if needed. So close doesn't need to do anything in that case.
   1981     if (!_private || _private->closed)
   1982         return;
   1983 
   1984     _private->closed = YES;
   1985 
   1986     [self _cancelUpdateMouseoverTimer];
   1987     [self _clearLastHitViewIfSelf];
   1988     [self _removeMouseMovedObserverUnconditionally];
   1989     [self _removeWindowObservers];
   1990     [self _removeSuperviewObservers];
   1991     [_private->pluginController destroyAllPlugins];
   1992     [_private->pluginController setDataSource:nil];
   1993     // remove tooltips before clearing _private so removeTrackingRect: will work correctly
   1994     [self removeAllToolTips];
   1995 
   1996     [_private clear];
   1997 
   1998     Page* page = core([self _webView]);
   1999     if (page)
   2000         page->dragController()->setDraggingImageURL(KURL());
   2001 }
   2002 
   2003 - (BOOL)_hasHTMLDocument
   2004 {
   2005     Frame* coreFrame = core([self _frame]);
   2006     if (!coreFrame)
   2007         return NO;
   2008     Document* document = coreFrame->document();
   2009     return document && document->isHTMLDocument();
   2010 }
   2011 
   2012 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
   2013                                                  forType:(NSString *)pboardType
   2014                                                inContext:(DOMRange *)context
   2015                                             subresources:(NSArray **)subresources
   2016 {
   2017     if (pboardType == WebArchivePboardType) {
   2018         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
   2019         if (subresources)
   2020             *subresources = [archive subresources];
   2021         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithArchive:archive];
   2022         [archive release];
   2023         return fragment;
   2024     }
   2025     if (pboardType == NSFilenamesPboardType)
   2026         return [self _documentFragmentWithPaths:[pasteboard propertyListForType:NSFilenamesPboardType]];
   2027 
   2028     if (pboardType == NSHTMLPboardType) {
   2029         NSString *HTMLString = [pasteboard stringForType:NSHTMLPboardType];
   2030         // This is a hack to make Microsoft's HTML pasteboard data work. See 3778785.
   2031         if ([HTMLString hasPrefix:@"Version:"]) {
   2032             NSRange range = [HTMLString rangeOfString:@"<html" options:NSCaseInsensitiveSearch];
   2033             if (range.location != NSNotFound)
   2034                 HTMLString = [HTMLString substringFromIndex:range.location];
   2035         }
   2036         if ([HTMLString length] == 0)
   2037             return nil;
   2038 
   2039         return [[self _frame] _documentFragmentWithMarkupString:HTMLString baseURLString:nil];
   2040     }
   2041 
   2042     // The _hasHTMLDocument clause here is a workaround for a bug in NSAttributedString: Radar 5052369.
   2043     // If we call _documentFromRange on an XML document we'll get "setInnerHTML: method not found".
   2044     // FIXME: Remove this once bug 5052369 is fixed.
   2045     if ([self _hasHTMLDocument] && pboardType == NSRTFPboardType || pboardType == NSRTFDPboardType) {
   2046         NSAttributedString *string = nil;
   2047         if (pboardType == NSRTFDPboardType)
   2048             string = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
   2049         if (string == nil)
   2050             string = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
   2051         if (string == nil)
   2052             return nil;
   2053 
   2054         NSDictionary *documentAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
   2055             [[self class] _excludedElementsForAttributedStringConversion], NSExcludedElementsDocumentAttribute,
   2056             self, @"WebResourceHandler", nil];
   2057         NSArray *s;
   2058 
   2059         BOOL wasDeferringCallbacks = [[self _webView] defersCallbacks];
   2060         if (!wasDeferringCallbacks)
   2061             [[self _webView] setDefersCallbacks:YES];
   2062 
   2063         DOMDocumentFragment *fragment = [string _documentFromRange:NSMakeRange(0, [string length])
   2064                                                           document:[[self _frame] DOMDocument]
   2065                                                 documentAttributes:documentAttributes
   2066                                                       subresources:&s];
   2067         if (subresources)
   2068             *subresources = s;
   2069 
   2070         NSEnumerator *e = [s objectEnumerator];
   2071         WebResource *r;
   2072         while ((r = [e nextObject]))
   2073             [[self _dataSource] addSubresource:r];
   2074 
   2075         if (!wasDeferringCallbacks)
   2076             [[self _webView] setDefersCallbacks:NO];
   2077 
   2078         [documentAttributes release];
   2079         [string release];
   2080         return fragment;
   2081     }
   2082     if (pboardType == NSTIFFPboardType) {
   2083         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSTIFFPboardType]
   2084                                                               URL:uniqueURLWithRelativePart(@"image.tiff")
   2085                                                          MIMEType:@"image/tiff"
   2086                                                  textEncodingName:nil
   2087                                                         frameName:nil];
   2088         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
   2089         [resource release];
   2090         return fragment;
   2091     }
   2092     if (pboardType == NSPDFPboardType) {
   2093         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPDFPboardType]
   2094                                                               URL:uniqueURLWithRelativePart(@"application.pdf")
   2095                                                          MIMEType:@"application/pdf"
   2096                                                  textEncodingName:nil
   2097                                                         frameName:nil];
   2098         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
   2099         [resource release];
   2100         return fragment;
   2101     }
   2102 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
   2103     if (pboardType == NSPICTPboardType) {
   2104         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPICTPboardType]
   2105                                                               URL:uniqueURLWithRelativePart(@"image.pict")
   2106                                                          MIMEType:@"image/pict"
   2107                                                  textEncodingName:nil
   2108                                                         frameName:nil];
   2109         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
   2110         [resource release];
   2111         return fragment;
   2112     }
   2113 #endif
   2114     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
   2115     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
   2116     if ([pboardType isEqualToString:(NSString*)kUTTypePNG]) {
   2117         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:(NSString*)kUTTypePNG]
   2118                                                               URL:uniqueURLWithRelativePart(@"image.png")
   2119                                                          MIMEType:@"image/png"
   2120                                                  textEncodingName:nil
   2121                                                         frameName:nil];
   2122         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
   2123         [resource release];
   2124         return fragment;
   2125     }
   2126     if (pboardType == NSURLPboardType) {
   2127         NSURL *URL = [NSURL URLFromPasteboard:pasteboard];
   2128         DOMDocument* document = [[self _frame] DOMDocument];
   2129         ASSERT(document);
   2130         if (!document)
   2131             return nil;
   2132         DOMHTMLAnchorElement *anchor = (DOMHTMLAnchorElement *)[document createElement:@"a"];
   2133         NSString *URLString = [URL _web_originalDataAsString]; // Original data is ASCII-only, so there is no need to precompose.
   2134         if ([URLString length] == 0)
   2135             return nil;
   2136         NSString *URLTitleString = [[pasteboard stringForType:WebURLNamePboardType] precomposedStringWithCanonicalMapping];
   2137         DOMText *text = [document createTextNode:URLTitleString];
   2138         [anchor setHref:URLString];
   2139         [anchor appendChild:text];
   2140         DOMDocumentFragment *fragment = [document createDocumentFragment];
   2141         [fragment appendChild:anchor];
   2142         return fragment;
   2143     }
   2144     if (pboardType == NSStringPboardType)
   2145         return kit(createFragmentFromText(core(context), [[pasteboard stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping]).get());
   2146     return nil;
   2147 }
   2148 
   2149 #if ENABLE(NETSCAPE_PLUGIN_API)
   2150 - (void)_pauseNullEventsForAllNetscapePlugins
   2151 {
   2152     NSArray *subviews = [self subviews];
   2153     unsigned int subviewCount = [subviews count];
   2154     unsigned int subviewIndex;
   2155 
   2156     for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) {
   2157         NSView *subview = [subviews objectAtIndex:subviewIndex];
   2158         if ([subview isKindOfClass:[WebBaseNetscapePluginView class]])
   2159             [(WebBaseNetscapePluginView *)subview stopTimers];
   2160     }
   2161 }
   2162 #endif
   2163 
   2164 #if ENABLE(NETSCAPE_PLUGIN_API)
   2165 - (void)_resumeNullEventsForAllNetscapePlugins
   2166 {
   2167     NSArray *subviews = [self subviews];
   2168     unsigned int subviewCount = [subviews count];
   2169     unsigned int subviewIndex;
   2170 
   2171     for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) {
   2172         NSView *subview = [subviews objectAtIndex:subviewIndex];
   2173         if ([subview isKindOfClass:[WebBaseNetscapePluginView class]])
   2174             [(WebBaseNetscapePluginView *)subview restartTimers];
   2175     }
   2176 }
   2177 #endif
   2178 
   2179 - (BOOL)_isUsingAcceleratedCompositing
   2180 {
   2181 #if USE(ACCELERATED_COMPOSITING)
   2182     return _private->layerHostingView != nil;
   2183 #else
   2184     return NO;
   2185 #endif
   2186 }
   2187 
   2188 - (NSView *)_compositingLayersHostingView
   2189 {
   2190 #if USE(ACCELERATED_COMPOSITING)
   2191     return _private->layerHostingView;
   2192 #else
   2193     return 0;
   2194 #endif
   2195 }
   2196 
   2197 @end
   2198 
   2199 @implementation NSView (WebHTMLViewFileInternal)
   2200 
   2201 - (void)_web_addDescendantWebHTMLViewsToArray:(NSMutableArray *)array
   2202 {
   2203     unsigned count = [_subviews count];
   2204     for (unsigned i = 0; i < count; ++i) {
   2205         NSView *child = [_subviews objectAtIndex:i];
   2206         if ([child isKindOfClass:[WebHTMLView class]])
   2207             [array addObject:child];
   2208         [child _web_addDescendantWebHTMLViewsToArray:array];
   2209     }
   2210 }
   2211 
   2212 @end
   2213 
   2214 @implementation NSMutableDictionary (WebHTMLViewFileInternal)
   2215 
   2216 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key
   2217 {
   2218     if (object == nil) {
   2219         [self removeObjectForKey:key];
   2220     } else {
   2221         [self setObject:object forKey:key];
   2222     }
   2223 }
   2224 
   2225 @end
   2226 
   2227 static bool matchesExtensionOrEquivalent(NSString *filename, NSString *extension)
   2228 {
   2229     NSString *extensionAsSuffix = [@"." stringByAppendingString:extension];
   2230     return [filename _webkit_hasCaseInsensitiveSuffix:extensionAsSuffix]
   2231         || ([extension _webkit_isCaseInsensitiveEqualToString:@"jpeg"]
   2232             && [filename _webkit_hasCaseInsensitiveSuffix:@".jpg"]);
   2233 }
   2234 
   2235 #ifdef BUILDING_ON_TIGER
   2236 
   2237 // The following is a workaround for
   2238 // <rdar://problem/3429631> window stops getting mouse moved events after first tooltip appears
   2239 // The trick is to define a category on NSToolTipPanel that implements setAcceptsMouseMovedEvents:.
   2240 // Since the category will be searched before the real class, we'll prevent the flag from being
   2241 // set on the tool tip panel.
   2242 
   2243 @interface NSToolTipPanel : NSPanel
   2244 @end
   2245 
   2246 @interface NSToolTipPanel (WebHTMLViewFileInternal)
   2247 @end
   2248 
   2249 @implementation NSToolTipPanel (WebHTMLViewFileInternal)
   2250 
   2251 - (void)setAcceptsMouseMovedEvents:(BOOL)flag
   2252 {
   2253     // Do nothing, preventing the tool tip panel from trying to accept mouse-moved events.
   2254 }
   2255 
   2256 @end
   2257 
   2258 #endif
   2259 
   2260 @interface NSArray (WebHTMLView)
   2261 - (void)_web_makePluginViewsPerformSelector:(SEL)selector withObject:(id)object;
   2262 @end
   2263 
   2264 @implementation WebHTMLView
   2265 
   2266 + (void)initialize
   2267 {
   2268     [NSApp registerServicesMenuSendTypes:[[self class] _selectionPasteboardTypes]
   2269                              returnTypes:[[self class] _insertablePasteboardTypes]];
   2270     JSC::initializeThreading();
   2271 #ifndef BUILDING_ON_TIGER
   2272     WebCoreObjCFinalizeOnMainThread(self);
   2273 #endif
   2274 }
   2275 
   2276 - (id)initWithFrame:(NSRect)frame
   2277 {
   2278     self = [super initWithFrame:frame];
   2279     if (!self)
   2280         return nil;
   2281 
   2282     [self setFocusRingType:NSFocusRingTypeNone];
   2283 
   2284     // Make all drawing go through us instead of subviews.
   2285     [self _setDrawsOwnDescendants:YES];
   2286 
   2287     _private = [[WebHTMLViewPrivate alloc] init];
   2288 
   2289     _private->pluginController = [[WebPluginController alloc] initWithDocumentView:self];
   2290 
   2291     return self;
   2292 }
   2293 
   2294 - (void)dealloc
   2295 {
   2296     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHTMLView class], self))
   2297         return;
   2298 
   2299     // We can't assert that close has already been called because
   2300     // this view can be removed from it's superview, even though
   2301     // it could be needed later, so close if needed.
   2302     [self close];
   2303     [_private release];
   2304     _private = nil;
   2305     [super dealloc];
   2306 }
   2307 
   2308 - (void)finalize
   2309 {
   2310     ASSERT_MAIN_THREAD();
   2311     // We can't assert that close has already been called because
   2312     // this view can be removed from it's superview, even though
   2313     // it could be needed later, so close if needed.
   2314     [self close];
   2315     [super finalize];
   2316 }
   2317 
   2318 // Returns YES if the delegate returns YES (so we should do no more work).
   2319 - (BOOL)callDelegateDoCommandBySelectorIfNeeded:(SEL)selector
   2320 {
   2321     BOOL callerAlreadyCalledDelegate = _private->selectorForDoCommandBySelector == selector;
   2322     _private->selectorForDoCommandBySelector = 0;
   2323     if (callerAlreadyCalledDelegate)
   2324         return NO;
   2325     WebView *webView = [self _webView];
   2326     return [[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector];
   2327 }
   2328 
   2329 typedef HashMap<SEL, String> SelectorNameMap;
   2330 
   2331 // Map selectors into Editor command names.
   2332 // This is not needed for any selectors that have the same name as the Editor command.
   2333 static const SelectorNameMap* createSelectorExceptionMap()
   2334 {
   2335     SelectorNameMap* map = new HashMap<SEL, String>;
   2336 
   2337     map->add(@selector(insertNewlineIgnoringFieldEditor:), "InsertNewline");
   2338     map->add(@selector(insertParagraphSeparator:), "InsertNewline");
   2339     map->add(@selector(insertTabIgnoringFieldEditor:), "InsertTab");
   2340     map->add(@selector(pageDown:), "MovePageDown");
   2341     map->add(@selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection");
   2342     map->add(@selector(pageUp:), "MovePageUp");
   2343     map->add(@selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection");
   2344 
   2345     return map;
   2346 }
   2347 
   2348 static String commandNameForSelector(SEL selector)
   2349 {
   2350     // Check the exception map first.
   2351     static const SelectorNameMap* exceptionMap = createSelectorExceptionMap();
   2352     SelectorNameMap::const_iterator it = exceptionMap->find(selector);
   2353     if (it != exceptionMap->end())
   2354         return it->second;
   2355 
   2356     // Remove the trailing colon.
   2357     // No need to capitalize the command name since Editor command names are
   2358     // not case sensitive.
   2359     const char* selectorName = sel_getName(selector);
   2360     size_t selectorNameLength = strlen(selectorName);
   2361     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
   2362         return String();
   2363     return String(selectorName, selectorNameLength - 1);
   2364 }
   2365 
   2366 - (Editor::Command)coreCommandBySelector:(SEL)selector
   2367 {
   2368     Frame* coreFrame = core([self _frame]);
   2369     if (!coreFrame)
   2370         return Editor::Command();
   2371     return coreFrame->editor()->command(commandNameForSelector(selector));
   2372 }
   2373 
   2374 - (Editor::Command)coreCommandByName:(const char*)name
   2375 {
   2376     Frame* coreFrame = core([self _frame]);
   2377     if (!coreFrame)
   2378         return Editor::Command();
   2379     return coreFrame->editor()->command(name);
   2380 }
   2381 
   2382 - (void)executeCoreCommandBySelector:(SEL)selector
   2383 {
   2384     if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
   2385         return;
   2386     [self coreCommandBySelector:selector].execute();
   2387 }
   2388 
   2389 - (void)executeCoreCommandByName:(const char*)name
   2390 {
   2391     [self coreCommandByName:name].execute();
   2392 }
   2393 
   2394 // These commands are forwarded to the Editor object in WebCore.
   2395 // Ideally we'd do this for all editing commands; more of the code
   2396 // should be moved from here to there, and more commands should be
   2397 // added to this list.
   2398 
   2399 // FIXME: Maybe we should set things up so that all these share a single method implementation function.
   2400 // The functions are identical.
   2401 
   2402 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { [self executeCoreCommandBySelector:_cmd]; }
   2403 
   2404 WEBCORE_COMMAND(alignCenter)
   2405 WEBCORE_COMMAND(alignJustified)
   2406 WEBCORE_COMMAND(alignLeft)
   2407 WEBCORE_COMMAND(alignRight)
   2408 WEBCORE_COMMAND(copy)
   2409 WEBCORE_COMMAND(cut)
   2410 WEBCORE_COMMAND(delete)
   2411 WEBCORE_COMMAND(deleteBackward)
   2412 WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter)
   2413 WEBCORE_COMMAND(deleteForward)
   2414 WEBCORE_COMMAND(deleteToBeginningOfLine)
   2415 WEBCORE_COMMAND(deleteToBeginningOfParagraph)
   2416 WEBCORE_COMMAND(deleteToEndOfLine)
   2417 WEBCORE_COMMAND(deleteToEndOfParagraph)
   2418 WEBCORE_COMMAND(deleteToMark)
   2419 WEBCORE_COMMAND(deleteWordBackward)
   2420 WEBCORE_COMMAND(deleteWordForward)
   2421 WEBCORE_COMMAND(ignoreSpelling)
   2422 WEBCORE_COMMAND(indent)
   2423 WEBCORE_COMMAND(insertBacktab)
   2424 WEBCORE_COMMAND(insertLineBreak)
   2425 WEBCORE_COMMAND(insertNewline)
   2426 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
   2427 WEBCORE_COMMAND(insertParagraphSeparator)
   2428 WEBCORE_COMMAND(insertTab)
   2429 WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
   2430 WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight)
   2431 WEBCORE_COMMAND(makeTextWritingDirectionNatural)
   2432 WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft)
   2433 WEBCORE_COMMAND(moveBackward)
   2434 WEBCORE_COMMAND(moveBackwardAndModifySelection)
   2435 WEBCORE_COMMAND(moveDown)
   2436 WEBCORE_COMMAND(moveDownAndModifySelection)
   2437 WEBCORE_COMMAND(moveForward)
   2438 WEBCORE_COMMAND(moveForwardAndModifySelection)
   2439 WEBCORE_COMMAND(moveLeft)
   2440 WEBCORE_COMMAND(moveLeftAndModifySelection)
   2441 WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection)
   2442 WEBCORE_COMMAND(moveParagraphForwardAndModifySelection)
   2443 WEBCORE_COMMAND(moveRight)
   2444 WEBCORE_COMMAND(moveRightAndModifySelection)
   2445 WEBCORE_COMMAND(moveToBeginningOfDocument)
   2446 WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection)
   2447 WEBCORE_COMMAND(moveToBeginningOfLine)
   2448 WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection)
   2449 WEBCORE_COMMAND(moveToBeginningOfParagraph)
   2450 WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection)
   2451 WEBCORE_COMMAND(moveToBeginningOfSentence)
   2452 WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection)
   2453 WEBCORE_COMMAND(moveToEndOfDocument)
   2454 WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection)
   2455 WEBCORE_COMMAND(moveToEndOfLine)
   2456 WEBCORE_COMMAND(moveToEndOfLineAndModifySelection)
   2457 WEBCORE_COMMAND(moveToEndOfParagraph)
   2458 WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection)
   2459 WEBCORE_COMMAND(moveToEndOfSentence)
   2460 WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection)
   2461 WEBCORE_COMMAND(moveToLeftEndOfLine)
   2462 WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection)
   2463 WEBCORE_COMMAND(moveToRightEndOfLine)
   2464 WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection)
   2465 WEBCORE_COMMAND(moveUp)
   2466 WEBCORE_COMMAND(moveUpAndModifySelection)
   2467 WEBCORE_COMMAND(moveWordBackward)
   2468 WEBCORE_COMMAND(moveWordBackwardAndModifySelection)
   2469 WEBCORE_COMMAND(moveWordForward)
   2470 WEBCORE_COMMAND(moveWordForwardAndModifySelection)
   2471 WEBCORE_COMMAND(moveWordLeft)
   2472 WEBCORE_COMMAND(moveWordLeftAndModifySelection)
   2473 WEBCORE_COMMAND(moveWordRight)
   2474 WEBCORE_COMMAND(moveWordRightAndModifySelection)
   2475 WEBCORE_COMMAND(outdent)
   2476 WEBCORE_COMMAND(pageDown)
   2477 WEBCORE_COMMAND(pageDownAndModifySelection)
   2478 WEBCORE_COMMAND(pageUp)
   2479 WEBCORE_COMMAND(pageUpAndModifySelection)
   2480 WEBCORE_COMMAND(selectAll)
   2481 WEBCORE_COMMAND(selectLine)
   2482 WEBCORE_COMMAND(selectParagraph)
   2483 WEBCORE_COMMAND(selectSentence)
   2484 WEBCORE_COMMAND(selectToMark)
   2485 WEBCORE_COMMAND(selectWord)
   2486 WEBCORE_COMMAND(setMark)
   2487 WEBCORE_COMMAND(subscript)
   2488 WEBCORE_COMMAND(superscript)
   2489 WEBCORE_COMMAND(swapWithMark)
   2490 WEBCORE_COMMAND(transpose)
   2491 WEBCORE_COMMAND(underline)
   2492 WEBCORE_COMMAND(unscript)
   2493 WEBCORE_COMMAND(yank)
   2494 WEBCORE_COMMAND(yankAndSelect)
   2495 
   2496 #undef WEBCORE_COMMAND
   2497 
   2498 #define COMMAND_PROLOGUE if ([self callDelegateDoCommandBySelectorIfNeeded:_cmd]) return;
   2499 
   2500 - (IBAction)takeFindStringFromSelection:(id)sender
   2501 {
   2502     COMMAND_PROLOGUE
   2503 
   2504     if (![self _hasSelection]) {
   2505         NSBeep();
   2506         return;
   2507     }
   2508 
   2509     [NSPasteboard _web_setFindPasteboardString:[self selectedString] withOwner:self];
   2510 }
   2511 
   2512 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
   2513 {
   2514     [pasteboard declareTypes:types owner:[self _topHTMLView]];
   2515     [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
   2516     return YES;
   2517 }
   2518 
   2519 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard
   2520 {
   2521     Frame* coreFrame = core([self _frame]);
   2522     if (!coreFrame)
   2523         return NO;
   2524     if (coreFrame->selection()->isContentRichlyEditable())
   2525         [self _pasteWithPasteboard:pasteboard allowPlainText:YES];
   2526     else
   2527         [self _pasteAsPlainTextWithPasteboard:pasteboard];
   2528     return YES;
   2529 }
   2530 
   2531 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
   2532 {
   2533     BOOL isSendTypeOK = !sendType || ([[self pasteboardTypesForSelection] containsObject:sendType] && [self _hasSelection]);
   2534     BOOL isReturnTypeOK = !returnType || ([[[self class] _insertablePasteboardTypes] containsObject:returnType] && [self _isEditable]);
   2535     if (isSendTypeOK && isReturnTypeOK)
   2536         return self;
   2537     return [[self nextResponder] validRequestorForSendType:sendType returnType:returnType];
   2538 }
   2539 
   2540 // jumpToSelection is the old name for what AppKit now calls centerSelectionInVisibleArea. Safari
   2541 // was using the old jumpToSelection selector in its menu. Newer versions of Safari will use the
   2542 // selector centerSelectionInVisibleArea. We'll leave the old selector in place for two reasons:
   2543 // (1) Compatibility between older Safari and newer WebKit; (2) other WebKit-based applications
   2544 // might be using the selector, and we don't want to break them.
   2545 - (void)jumpToSelection:(id)sender
   2546 {
   2547     COMMAND_PROLOGUE
   2548 
   2549     if (Frame* coreFrame = core([self _frame]))
   2550         coreFrame->revealSelection(ScrollAlignment::alignCenterAlways);
   2551 }
   2552 
   2553 - (NSCellStateValue)selectionHasStyle:(CSSStyleDeclaration*)style
   2554 {
   2555     Frame* coreFrame = core([self _frame]);
   2556     if (!coreFrame)
   2557         return NSOffState;
   2558     return kit(coreFrame->editor()->selectionHasStyle(style));
   2559 }
   2560 
   2561 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
   2562 {
   2563     SEL action = [item action];
   2564     RefPtr<Frame> frame = core([self _frame]);
   2565 
   2566     if (!frame)
   2567         return NO;
   2568 
   2569     if (Document* doc = frame->document()) {
   2570         if (doc->isPluginDocument())
   2571             return NO;
   2572         if (doc->isImageDocument()) {
   2573             if (action == @selector(copy:))
   2574                 return frame->loader()->isComplete();
   2575             return NO;
   2576         }
   2577     }
   2578 
   2579     if (action == @selector(changeSpelling:)
   2580             || action == @selector(_changeSpellingFromMenu:)
   2581             || action == @selector(checkSpelling:)
   2582             || action == @selector(complete:)
   2583             || action == @selector(pasteFont:))
   2584         return [self _canEdit];
   2585 
   2586     if (action == @selector(showGuessPanel:)) {
   2587 #ifndef BUILDING_ON_TIGER
   2588         // Match OS X AppKit behavior for post-Tiger. Don't change Tiger behavior.
   2589         NSMenuItem *menuItem = (NSMenuItem *)item;
   2590         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
   2591             BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible];
   2592             [menuItem setTitle:panelShowing
   2593                 ? UI_STRING("Hide Spelling and Grammar", "menu item title")
   2594                 : UI_STRING("Show Spelling and Grammar", "menu item title")];
   2595         }
   2596 #endif
   2597         return [self _canEdit];
   2598     }
   2599 
   2600     if (action == @selector(changeBaseWritingDirection:)
   2601             || action == @selector(makeBaseWritingDirectionLeftToRight:)
   2602             || action == @selector(makeBaseWritingDirectionRightToLeft:)) {
   2603         NSWritingDirection writingDirection;
   2604 
   2605         if (action == @selector(changeBaseWritingDirection:)) {
   2606             writingDirection = static_cast<NSWritingDirection>([item tag]);
   2607             if (writingDirection == NSWritingDirectionNatural)
   2608                 return NO;
   2609         } else if (action == @selector(makeBaseWritingDirectionLeftToRight:))
   2610             writingDirection = NSWritingDirectionLeftToRight;
   2611         else
   2612             writingDirection = NSWritingDirectionRightToLeft;
   2613 
   2614         NSMenuItem *menuItem = (NSMenuItem *)item;
   2615         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
   2616             RefPtr<CSSStyleDeclaration> style = CSSMutableStyleDeclaration::create();
   2617             ExceptionCode ec;
   2618             style->setProperty("direction", writingDirection == NSWritingDirectionLeftToRight ? "LTR" : "RTL", ec);
   2619             [menuItem setState:frame->editor()->selectionHasStyle(style.get())];
   2620         }
   2621         return [self _canEdit];
   2622     }
   2623 
   2624     if (action == @selector(makeBaseWritingDirectionNatural:)) {
   2625         NSMenuItem *menuItem = (NSMenuItem *)item;
   2626         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2627             [menuItem setState:NSOffState];
   2628         return NO;
   2629     }
   2630 
   2631     if (action == @selector(toggleBaseWritingDirection:)) {
   2632         NSMenuItem *menuItem = (NSMenuItem *)item;
   2633         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
   2634             RefPtr<CSSStyleDeclaration> style = CSSMutableStyleDeclaration::create();
   2635             ExceptionCode ec;
   2636             style->setProperty("direction", "RTL", ec);
   2637             // Take control of the title of the menu item instead of just checking/unchecking it because
   2638             // a check would be ambiguous.
   2639             [menuItem setTitle:frame->editor()->selectionHasStyle(style.get())
   2640                 ? UI_STRING("Left to Right", "Left to Right context menu item")
   2641                 : UI_STRING("Right to Left", "Right to Left context menu item")];
   2642         }
   2643         return [self _canEdit];
   2644     }
   2645 
   2646     if (action == @selector(changeAttributes:)
   2647             || action == @selector(changeColor:)
   2648             || action == @selector(changeFont:))
   2649         return [self _canEditRichly];
   2650 
   2651     if (action == @selector(capitalizeWord:)
   2652                || action == @selector(lowercaseWord:)
   2653                || action == @selector(uppercaseWord:))
   2654         return [self _hasSelection] && [self _isEditable];
   2655 
   2656     if (action == @selector(centerSelectionInVisibleArea:)
   2657                || action == @selector(jumpToSelection:)
   2658                || action == @selector(copyFont:))
   2659         return [self _hasSelection] || ([self _isEditable] && [self _hasInsertionPoint]);
   2660 
   2661     if (action == @selector(changeDocumentBackgroundColor:))
   2662         return [[self _webView] isEditable] && [self _canEditRichly];
   2663 
   2664     if (action == @selector(_ignoreSpellingFromMenu:)
   2665             || action == @selector(_learnSpellingFromMenu:)
   2666             || action == @selector(takeFindStringFromSelection:))
   2667         return [self _hasSelection];
   2668 
   2669     if (action == @selector(paste:) || action == @selector(pasteAsPlainText:))
   2670         return frame && (frame->editor()->canDHTMLPaste() || frame->editor()->canPaste());
   2671 
   2672     if (action == @selector(pasteAsRichText:))
   2673         return frame && (frame->editor()->canDHTMLPaste()
   2674             || (frame->editor()->canPaste() && frame->selection()->isContentRichlyEditable()));
   2675 
   2676     if (action == @selector(performFindPanelAction:))
   2677         return NO;
   2678 
   2679     if (action == @selector(_lookUpInDictionaryFromMenu:))
   2680         return [self _hasSelection];
   2681 
   2682     if (action == @selector(stopSpeaking:))
   2683         return [NSApp isSpeaking];
   2684 
   2685 #ifndef BUILDING_ON_TIGER
   2686     if (action == @selector(toggleGrammarChecking:)) {
   2687         // FIXME 4799134: WebView is the bottleneck for this grammar-checking logic, but we must validate
   2688         // the selector here because we implement it here, and we must implement it here because the AppKit
   2689         // code checks the first responder.
   2690         NSMenuItem *menuItem = (NSMenuItem *)item;
   2691         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2692             [menuItem setState:[self isGrammarCheckingEnabled] ? NSOnState : NSOffState];
   2693         return YES;
   2694     }
   2695 #endif
   2696 
   2697 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
   2698     if (action == @selector(orderFrontSubstitutionsPanel:)) {
   2699         NSMenuItem *menuItem = (NSMenuItem *)item;
   2700         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
   2701             BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible];
   2702             [menuItem setTitle:panelShowing
   2703                 ? UI_STRING("Hide Substitutions", "menu item title")
   2704                 : UI_STRING("Show Substitutions", "menu item title")];
   2705         }
   2706         return [self _canEdit];
   2707     }
   2708     // FIXME 4799134: WebView is the bottleneck for this logic, but we must validate
   2709     // the selector here because we implement it here, and we must implement it here because the AppKit
   2710     // code checks the first responder.
   2711     if (action == @selector(toggleSmartInsertDelete:)) {
   2712         NSMenuItem *menuItem = (NSMenuItem *)item;
   2713         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2714             [menuItem setState:[self smartInsertDeleteEnabled] ? NSOnState : NSOffState];
   2715         return [self _canEdit];
   2716     }
   2717     if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
   2718         NSMenuItem *menuItem = (NSMenuItem *)item;
   2719         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2720             [menuItem setState:[self isAutomaticQuoteSubstitutionEnabled] ? NSOnState : NSOffState];
   2721         return [self _canEdit];
   2722     }
   2723     if (action == @selector(toggleAutomaticLinkDetection:)) {
   2724         NSMenuItem *menuItem = (NSMenuItem *)item;
   2725         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2726             [menuItem setState:[self isAutomaticLinkDetectionEnabled] ? NSOnState : NSOffState];
   2727         return [self _canEdit];
   2728     }
   2729     if (action == @selector(toggleAutomaticDashSubstitution:)) {
   2730         NSMenuItem *menuItem = (NSMenuItem *)item;
   2731         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2732             [menuItem setState:[self isAutomaticDashSubstitutionEnabled] ? NSOnState : NSOffState];
   2733         return [self _canEdit];
   2734     }
   2735     if (action == @selector(toggleAutomaticTextReplacement:)) {
   2736         NSMenuItem *menuItem = (NSMenuItem *)item;
   2737         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2738             [menuItem setState:[self isAutomaticTextReplacementEnabled] ? NSOnState : NSOffState];
   2739         return [self _canEdit];
   2740     }
   2741     if (action == @selector(toggleAutomaticSpellingCorrection:)) {
   2742         NSMenuItem *menuItem = (NSMenuItem *)item;
   2743         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2744             [menuItem setState:[self isAutomaticSpellingCorrectionEnabled] ? NSOnState : NSOffState];
   2745         return [self _canEdit];
   2746     }
   2747 #endif
   2748 
   2749     Editor::Command command = [self coreCommandBySelector:action];
   2750     if (command.isSupported()) {
   2751         NSMenuItem *menuItem = (NSMenuItem *)item;
   2752         if ([menuItem isKindOfClass:[NSMenuItem class]])
   2753             [menuItem setState:kit(command.state())];
   2754         return command.isEnabled();
   2755     }
   2756 
   2757     return YES;
   2758 }
   2759 
   2760 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
   2761 {
   2762     // This can be called during teardown when _webView is nil. Return NO when this happens, because CallUIDelegateReturningBoolean
   2763     // assumes the WebVIew is non-nil.
   2764     if (![self _webView])
   2765         return NO;
   2766     BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
   2767     return CallUIDelegateReturningBoolean(result, [self _webView], @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
   2768 }
   2769 
   2770 - (BOOL)acceptsFirstResponder
   2771 {
   2772     // Don't accept first responder when we first click on this view.
   2773     // We have to pass the event down through WebCore first to be sure we don't hit a subview.
   2774     // Do accept first responder at any other time, for example from keyboard events,
   2775     // or from calls back from WebCore once we begin mouse-down event handling.
   2776     NSEvent *event = [NSApp currentEvent];
   2777     if ([event type] == NSLeftMouseDown
   2778             && !_private->handlingMouseDownEvent
   2779             && NSPointInRect([event locationInWindow], [self convertRect:[self visibleRect] toView:nil])) {
   2780         return NO;
   2781     }
   2782     return YES;
   2783 }
   2784 
   2785 - (BOOL)maintainsInactiveSelection
   2786 {
   2787     // This method helps to determine whether the WebHTMLView should maintain
   2788     // an inactive selection when it's not first responder.
   2789     // Traditionally, these views have not maintained such selections,
   2790     // clearing them when the view was not first responder. However,
   2791     // to fix bugs like this one:
   2792     // <rdar://problem/3672088>: "Editable WebViews should maintain a selection even
   2793     //                            when they're not firstResponder"
   2794     // it was decided to add a switch to act more like an NSTextView.
   2795 
   2796     if ([[self _webView] maintainsInactiveSelection])
   2797         return YES;
   2798 
   2799     // Predict the case where we are losing first responder status only to
   2800     // gain it back again. Want to keep the selection in that case.
   2801     id nextResponder = [[self window] _newFirstResponderAfterResigning];
   2802     if ([nextResponder isKindOfClass:[NSScrollView class]]) {
   2803         id contentView = [nextResponder contentView];
   2804         if (contentView)
   2805             nextResponder = contentView;
   2806     }
   2807     if ([nextResponder isKindOfClass:[NSClipView class]]) {
   2808         id documentView = [nextResponder documentView];
   2809         if (documentView)
   2810             nextResponder = documentView;
   2811     }
   2812     if (nextResponder == self)
   2813         return YES;
   2814 
   2815     Frame* coreFrame = core([self _frame]);
   2816     bool selectionIsEditable = coreFrame && coreFrame->selection()->isContentEditable();
   2817     bool nextResponderIsInWebView = [nextResponder isKindOfClass:[NSView class]]
   2818         && [nextResponder isDescendantOf:[[[self _webView] mainFrame] frameView]];
   2819 
   2820     return selectionIsEditable && nextResponderIsInWebView;
   2821 }
   2822 
   2823 - (void)addMouseMovedObserver
   2824 {
   2825     if (!_private->dataSource || ![self _isTopHTMLView] || _private->observingMouseMovedNotifications)
   2826         return;
   2827 
   2828     // Unless the Dashboard asks us to do this for all windows, keep an observer going only for the key window.
   2829     if (!([[self window] isKeyWindow]
   2830 #if ENABLE(DASHBOARD_SUPPORT)
   2831             || [[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows]
   2832 #endif
   2833         ))
   2834         return;
   2835 
   2836     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mouseMovedNotification:)
   2837         name:WKMouseMovedNotification() object:nil];
   2838     [self _frameOrBoundsChanged];
   2839     _private->observingMouseMovedNotifications = true;
   2840 }
   2841 
   2842 - (void)removeMouseMovedObserver
   2843 {
   2844 #if ENABLE(DASHBOARD_SUPPORT)
   2845     // Don't remove the observer if we're running the Dashboard.
   2846     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows])
   2847         return;
   2848 #endif
   2849 
   2850     [[self _webView] _mouseDidMoveOverElement:nil modifierFlags:0];
   2851     [self _removeMouseMovedObserverUnconditionally];
   2852 }
   2853 
   2854 - (void)addSuperviewObservers
   2855 {
   2856     if (_private->observingSuperviewNotifications)
   2857         return;
   2858 
   2859     NSView *superview = [self superview];
   2860     if (!superview || ![self window])
   2861         return;
   2862 
   2863     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
   2864     [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewFrameDidChangeNotification object:superview];
   2865     [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewBoundsDidChangeNotification object:superview];
   2866 
   2867     // In addition to registering for frame/bounds change notifications, call -_frameOrBoundsChanged.
   2868     // It will check the current scroll against the previous layout's scroll.  We need to
   2869     // do this here to catch the case where the WebView is laid out at one size, removed from its
   2870     // window, resized, and inserted into another window.  Our frame/bounds changed notifications
   2871     // will not be sent in that situation, since we only watch for changes while in the view hierarchy.
   2872     [self _frameOrBoundsChanged];
   2873 
   2874     _private->observingSuperviewNotifications = true;
   2875 }
   2876 
   2877 - (void)addWindowObservers
   2878 {
   2879     if (_private->observingWindowNotifications)
   2880         return;
   2881 
   2882     NSWindow *window = [self window];
   2883     if (!window)
   2884         return;
   2885 
   2886     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
   2887     [notificationCenter addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:nil];
   2888     [notificationCenter addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:nil];
   2889     [notificationCenter addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:window];
   2890 
   2891     _private->observingWindowNotifications = true;
   2892 }
   2893 
   2894 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
   2895 {
   2896     [self _removeSuperviewObservers];
   2897 }
   2898 
   2899 - (void)viewDidMoveToSuperview
   2900 {
   2901     if ([self superview] != nil)
   2902         [self addSuperviewObservers];
   2903 
   2904 #if USE(ACCELERATED_COMPOSITING)
   2905     if ([self superview] && [self _isUsingAcceleratedCompositing]) {
   2906         WebView *webView = [self _webView];
   2907         if ([webView _postsAcceleratedCompositingNotifications])
   2908             [[NSNotificationCenter defaultCenter] postNotificationName:_WebViewDidStartAcceleratedCompositingNotification object:webView userInfo:nil];
   2909     }
   2910 #endif
   2911 }
   2912 
   2913 - (void)viewWillMoveToWindow:(NSWindow *)window
   2914 {
   2915     // Don't do anything if we aren't initialized.  This happens
   2916     // when decoding a WebView.  When WebViews are decoded their subviews
   2917     // are created by initWithCoder: and so won't be normally
   2918     // initialized.  The stub views are discarded by WebView.
   2919     if (!_private)
   2920         return;
   2921 
   2922     // FIXME: Some of these calls may not work because this view may be already removed from it's superview.
   2923     [self _removeMouseMovedObserverUnconditionally];
   2924     [self _removeWindowObservers];
   2925     [self _removeSuperviewObservers];
   2926     [self _cancelUpdateMouseoverTimer];
   2927 
   2928     [[self _pluginController] stopAllPlugins];
   2929 }
   2930 
   2931 - (void)viewDidMoveToWindow
   2932 {
   2933     // Don't do anything if we aren't initialized.  This happens
   2934     // when decoding a WebView.  When WebViews are decoded their subviews
   2935     // are created by initWithCoder: and so won't be normally
   2936     // initialized.  The stub views are discarded by WebView.
   2937     if (!_private || _private->closed)
   2938         return;
   2939 
   2940     [self _stopAutoscrollTimer];
   2941     if ([self window]) {
   2942         _private->lastScrollPosition = [[self superview] bounds].origin;
   2943         [self addWindowObservers];
   2944         [self addSuperviewObservers];
   2945         [self addMouseMovedObserver];
   2946 
   2947         [[self _pluginController] startAllPlugins];
   2948 
   2949         _private->lastScrollPosition = NSZeroPoint;
   2950     }
   2951 }
   2952 
   2953 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
   2954 {
   2955     [[self subviews] _web_makePluginViewsPerformSelector:@selector(viewWillMoveToHostWindow:) withObject:hostWindow];
   2956 }
   2957 
   2958 - (void)viewDidMoveToHostWindow
   2959 {
   2960     [[self subviews] _web_makePluginViewsPerformSelector:@selector(viewDidMoveToHostWindow) withObject:nil];
   2961 }
   2962 
   2963 
   2964 - (void)addSubview:(NSView *)view
   2965 {
   2966     [super addSubview:view];
   2967 
   2968     if ([WebPluginController isPlugInView:view])
   2969         [[self _pluginController] addPlugin:view];
   2970 }
   2971 
   2972 - (void)willRemoveSubview:(NSView *)subview
   2973 {
   2974     if ([WebPluginController isPlugInView:subview])
   2975         [[self _pluginController] destroyPlugin:subview];
   2976 
   2977     [super willRemoveSubview:subview];
   2978 }
   2979 
   2980 - (void)reapplyStyles
   2981 {
   2982     if (!_private->needsToApplyStyles)
   2983         return;
   2984 
   2985 #ifdef LOG_TIMES
   2986     double start = CFAbsoluteTimeGetCurrent();
   2987 #endif
   2988 
   2989     if (Frame* coreFrame = core([self _frame])) {
   2990         if (FrameView* coreView = coreFrame->view())
   2991             coreView->setMediaType(_private->printing ? "print" : "screen");
   2992         if (Document* document = coreFrame->document())
   2993             document->setPrinting(_private->printing);
   2994         coreFrame->reapplyStyles();
   2995     }
   2996 
   2997 #ifdef LOG_TIMES
   2998     double thisTime = CFAbsoluteTimeGetCurrent() - start;
   2999     LOG(Timing, "%s apply style seconds = %f", [self URL], thisTime);
   3000 #endif
   3001 
   3002     _private->needsToApplyStyles = NO;
   3003 }
   3004 
   3005 // Do a layout, but set up a new fixed width for the purposes of doing printing layout.
   3006 // minPageWidth==0 implies a non-printing layout
   3007 - (void)layoutToMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)adjustViewSize
   3008 {
   3009     [self reapplyStyles];
   3010 
   3011     if (![self _needsLayout])
   3012         return;
   3013 
   3014 #ifdef LOG_TIMES
   3015     double start = CFAbsoluteTimeGetCurrent();
   3016 #endif
   3017 
   3018     LOG(View, "%@ doing layout", self);
   3019 
   3020     Frame* coreFrame = core([self _frame]);
   3021     if (!coreFrame)
   3022         return;
   3023 
   3024     if (FrameView* coreView = coreFrame->view()) {
   3025         if (minPageWidth > 0.0)
   3026             coreView->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
   3027         else {
   3028             coreView->forceLayout(!adjustViewSize);
   3029             if (adjustViewSize)
   3030                 coreView->adjustViewSize();
   3031         }
   3032     }
   3033 
   3034 #ifdef LOG_TIMES
   3035     double thisTime = CFAbsoluteTimeGetCurrent() - start;
   3036     LOG(Timing, "%s layout seconds = %f", [self URL], thisTime);
   3037 #endif
   3038 }
   3039 
   3040 - (void)layout
   3041 {
   3042     [self layoutToMinimumPageWidth:0.0f maximumPageWidth:0.0f adjustingViewSize:NO];
   3043 }
   3044 
   3045 // Deliver mouseup events to the DOM for button 2.
   3046 - (void)rightMouseUp:(NSEvent *)event
   3047 {
   3048     // There's a chance that if we run a nested event loop the event will be released.
   3049     // Retaining and then autoreleasing prevents that from causing a problem later here or
   3050     // inside AppKit code.
   3051     [[event retain] autorelease];
   3052 
   3053     [super rightMouseUp:event];
   3054 
   3055     if (Frame* coreframe = core([self _frame]))
   3056         coreframe->eventHandler()->mouseUp(event);
   3057 }
   3058 
   3059 - (NSMenu *)menuForEvent:(NSEvent *)event
   3060 {
   3061     // There's a chance that if we run a nested event loop the event will be released.
   3062     // Retaining and then autoreleasing prevents that from causing a problem later here or
   3063     // inside AppKit code.
   3064     [[event retain] autorelease];
   3065 
   3066     [_private->completionController endRevertingChange:NO moveLeft:NO];
   3067 
   3068     RefPtr<Frame> coreFrame = core([self _frame]);
   3069     if (!coreFrame)
   3070         return nil;
   3071 
   3072     Page* page = coreFrame->page();
   3073     if (!page)
   3074         return nil;
   3075 
   3076     // Match behavior of other browsers by sending a mousedown event for right clicks.
   3077     _private->handlingMouseDownEvent = YES;
   3078     page->contextMenuController()->clearContextMenu();
   3079     coreFrame->eventHandler()->mouseDown(event);
   3080     BOOL handledEvent = coreFrame->eventHandler()->sendContextMenuEvent(event);
   3081     _private->handlingMouseDownEvent = NO;
   3082 
   3083     if (!handledEvent)
   3084         return nil;
   3085 
   3086     // Re-get page, since it might have gone away during event handling.
   3087     page = coreFrame->page();
   3088     if (!page)
   3089         return nil;
   3090 
   3091     ContextMenu* coreMenu = page->contextMenuController()->contextMenu();
   3092     if (!coreMenu)
   3093         return nil;
   3094 
   3095     NSArray* menuItems = coreMenu->platformDescription();
   3096     if (!menuItems)
   3097         return nil;
   3098 
   3099     NSUInteger count = [menuItems count];
   3100     if (!count)
   3101         return nil;
   3102 
   3103     NSMenu* menu = [[[NSMenu alloc] init] autorelease];
   3104     for (NSUInteger i = 0; i < count; i++)
   3105         [menu addItem:[menuItems objectAtIndex:i]];
   3106     return menu;
   3107 }
   3108 
   3109 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
   3110 {
   3111     return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
   3112 }
   3113 
   3114 - (void)clearFocus
   3115 {
   3116     Frame* coreFrame = core([self _frame]);
   3117     if (!coreFrame)
   3118         return;
   3119     Document* document = coreFrame->document();
   3120     if (!document)
   3121         return;
   3122 
   3123     document->setFocusedNode(0);
   3124 }
   3125 
   3126 - (BOOL)isOpaque
   3127 {
   3128     return [[self _webView] drawsBackground];
   3129 }
   3130 
   3131 - (void)setNeedsDisplay:(BOOL)flag
   3132 {
   3133     LOG(View, "%@ setNeedsDisplay:%@", self, flag ? @"YES" : @"NO");
   3134     [super setNeedsDisplay:flag];
   3135 }
   3136 
   3137 - (void)setNeedsLayout: (BOOL)flag
   3138 {
   3139     LOG(View, "%@ setNeedsLayout:%@", self, flag ? @"YES" : @"NO");
   3140     if (!flag)
   3141         return; // There's no way to say you don't need a layout.
   3142     if (Frame* frame = core([self _frame])) {
   3143         if (frame->document() && frame->document()->inPageCache())
   3144             return;
   3145         if (FrameView* view = frame->view())
   3146             view->setNeedsLayout();
   3147     }
   3148 }
   3149 
   3150 - (void)setNeedsToApplyStyles: (BOOL)flag
   3151 {
   3152     LOG(View, "%@ setNeedsToApplyStyles:%@", self, flag ? @"YES" : @"NO");
   3153     _private->needsToApplyStyles = flag;
   3154 }
   3155 
   3156 - (void)drawSingleRect:(NSRect)rect
   3157 {
   3158     [NSGraphicsContext saveGraphicsState];
   3159     NSRectClip(rect);
   3160 
   3161     ASSERT([[self superview] isKindOfClass:[WebClipView class]]);
   3162 
   3163     [(WebClipView *)[self superview] setAdditionalClip:rect];
   3164 
   3165     @try {
   3166         if ([self _transparentBackground]) {
   3167             [[NSColor clearColor] set];
   3168             NSRectFill (rect);
   3169         }
   3170 
   3171         [[self _frame] _drawRect:rect contentsOnly:YES];
   3172 
   3173         WebView *webView = [self _webView];
   3174 
   3175         // This hack is needed for <rdar://problem/5023545>. We can hit a race condition where drawRect will be
   3176         // called after the WebView has closed. If the client did not properly close the WebView and set the
   3177         // UIDelegate to nil, then the UIDelegate will be stale and this code will crash.
   3178         static BOOL version3OrLaterClient = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_QUICKBOOKS_QUIRK);
   3179         if (version3OrLaterClient)
   3180             [[webView _UIDelegateForwarder] webView:webView didDrawRect:[webView convertRect:rect fromView:self]];
   3181 
   3182         if (WebNodeHighlight *currentHighlight = [webView currentNodeHighlight])
   3183             [currentHighlight setNeedsUpdateInTargetViewRect:[self convertRect:rect toView:[currentHighlight targetView]]];
   3184 
   3185         [(WebClipView *)[self superview] resetAdditionalClip];
   3186 
   3187         [NSGraphicsContext restoreGraphicsState];
   3188     } @catch (NSException *localException) {
   3189         [(WebClipView *)[self superview] resetAdditionalClip];
   3190         [NSGraphicsContext restoreGraphicsState];
   3191         LOG_ERROR("Exception caught while drawing: %@", localException);
   3192         [localException raise];
   3193     }
   3194 }
   3195 
   3196 - (void)drawRect:(NSRect)rect
   3197 {
   3198     ASSERT_MAIN_THREAD();
   3199     LOG(View, "%@ drawing", self);
   3200 
   3201     const NSRect *rects;
   3202     NSInteger count;
   3203     [self getRectsBeingDrawn:&rects count:&count];
   3204 
   3205     BOOL subviewsWereSetAside = _private->subviewsSetAside;
   3206     if (subviewsWereSetAside)
   3207         [self _restoreSubviews];
   3208 
   3209 #ifdef LOG_TIMES
   3210     double start = CFAbsoluteTimeGetCurrent();
   3211 #endif
   3212 
   3213     WebView *webView = [self _webView];
   3214     if ([webView _mustDrawUnionedRect:rect singleRects:rects count:count])
   3215         [self drawSingleRect:rect];
   3216     else
   3217         for (int i = 0; i < count; ++i)
   3218             [self drawSingleRect:rects[i]];
   3219 
   3220 #ifdef LOG_TIMES
   3221     double thisTime = CFAbsoluteTimeGetCurrent() - start;
   3222     LOG(Timing, "%s draw seconds = %f", widget->part()->baseURL().URL().latin1(), thisTime);
   3223 #endif
   3224 
   3225     if (subviewsWereSetAside)
   3226         [self _setAsideSubviews];
   3227 
   3228 #if USE(ACCELERATED_COMPOSITING)
   3229     if ([webView _needsOneShotDrawingSynchronization]) {
   3230         // Disable screen updates so that any layer changes committed here
   3231         // don't show up on the screen before the window flush at the end
   3232         // of the current window display, but only if a window flush is actually
   3233         // going to happen.
   3234         NSWindow *window = [self window];
   3235         if ([window viewsNeedDisplay])
   3236             [window disableScreenUpdatesUntilFlush];
   3237 
   3238         // Make sure any layer changes that happened as a result of layout
   3239         // via -viewWillDraw are committed.
   3240         [CATransaction flush];
   3241         [webView _setNeedsOneShotDrawingSynchronization:NO];
   3242     }
   3243 #endif
   3244 }
   3245 
   3246 // Turn off the additional clip while computing our visibleRect.
   3247 - (NSRect)visibleRect
   3248 {
   3249     if (!([[self superview] isKindOfClass:[WebClipView class]]))
   3250         return [super visibleRect];
   3251 
   3252     WebClipView *clipView = (WebClipView *)[self superview];
   3253 
   3254     BOOL hasAdditionalClip = [clipView hasAdditionalClip];
   3255     if (!hasAdditionalClip) {
   3256         return [super visibleRect];
   3257     }
   3258 
   3259     NSRect additionalClip = [clipView additionalClip];
   3260     [clipView resetAdditionalClip];
   3261     NSRect visibleRect = [super visibleRect];
   3262     [clipView setAdditionalClip:additionalClip];
   3263     return visibleRect;
   3264 }
   3265 
   3266 - (BOOL)isFlipped
   3267 {
   3268     return YES;
   3269 }
   3270 
   3271 - (void)windowDidBecomeKey:(NSNotification *)notification
   3272 {
   3273     if (!pthread_main_np()) {
   3274         [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
   3275         return;
   3276     }
   3277 
   3278     NSWindow *keyWindow = [notification object];
   3279 
   3280     if (keyWindow == [self window])
   3281         [self addMouseMovedObserver];
   3282 }
   3283 
   3284 - (void)windowDidResignKey:(NSNotification *)notification
   3285 {
   3286     if (!pthread_main_np()) {
   3287         [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
   3288         return;
   3289     }
   3290 
   3291     NSWindow *formerKeyWindow = [notification object];
   3292 
   3293     if (formerKeyWindow == [self window])
   3294         [self removeMouseMovedObserver];
   3295 
   3296     if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet])
   3297         [_private->completionController endRevertingChange:NO moveLeft:NO];
   3298 }
   3299 
   3300 - (void)windowWillClose:(NSNotification *)notification
   3301 {
   3302     if (!pthread_main_np()) {
   3303         [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
   3304         return;
   3305     }
   3306 
   3307     [_private->completionController endRevertingChange:NO moveLeft:NO];
   3308     [[self _pluginController] destroyAllPlugins];
   3309 }
   3310 
   3311 - (void)scrollWheel:(NSEvent *)event
   3312 {
   3313     // There's a chance that responding to this event will run a nested event loop, and
   3314     // fetching a new event might release the old one. Retaining and then autoreleasing
   3315     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3316     [[event retain] autorelease];
   3317 
   3318     Frame* frame = core([self _frame]);
   3319     if (!frame || !frame->eventHandler()->wheelEvent(event))
   3320         [super scrollWheel:event];
   3321 }
   3322 
   3323 - (BOOL)_isSelectionEvent:(NSEvent *)event
   3324 {
   3325     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
   3326     return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsSelectedKey] boolValue];
   3327 }
   3328 
   3329 - (BOOL)_isScrollBarEvent:(NSEvent *)event
   3330 {
   3331     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
   3332     return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsInScrollBarKey] boolValue];
   3333 }
   3334 
   3335 - (BOOL)acceptsFirstMouse:(NSEvent *)event
   3336 {
   3337     // There's a chance that responding to this event will run a nested event loop, and
   3338     // fetching a new event might release the old one. Retaining and then autoreleasing
   3339     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3340     [[event retain] autorelease];
   3341 
   3342     NSView *hitView = [self _hitViewForEvent:event];
   3343     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
   3344 
   3345 #if ENABLE(DASHBOARD_SUPPORT)
   3346     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysAcceptsFirstMouse])
   3347         return YES;
   3348 #endif
   3349 
   3350     if (hitHTMLView) {
   3351         bool result = false;
   3352         if (Frame* coreFrame = core([hitHTMLView _frame])) {
   3353             coreFrame->eventHandler()->setActivationEventNumber([event eventNumber]);
   3354             [hitHTMLView _setMouseDownEvent:event];
   3355             if ([hitHTMLView _isSelectionEvent:event])
   3356                 result = coreFrame->eventHandler()->eventMayStartDrag(event);
   3357             else if ([hitHTMLView _isScrollBarEvent:event])
   3358                 result = true;
   3359             [hitHTMLView _setMouseDownEvent:nil];
   3360         }
   3361         return result;
   3362     }
   3363     return [hitView acceptsFirstMouse:event];
   3364 }
   3365 
   3366 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
   3367 {
   3368     // There's a chance that responding to this event will run a nested event loop, and
   3369     // fetching a new event might release the old one. Retaining and then autoreleasing
   3370     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3371     [[event retain] autorelease];
   3372 
   3373     NSView *hitView = [self _hitViewForEvent:event];
   3374     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
   3375     if (hitHTMLView) {
   3376         bool result = false;
   3377         if ([hitHTMLView _isSelectionEvent:event]) {
   3378             if (Frame* coreFrame = core([hitHTMLView _frame])) {
   3379                 [hitHTMLView _setMouseDownEvent:event];
   3380                 result = coreFrame->eventHandler()->eventMayStartDrag(event);
   3381                 [hitHTMLView _setMouseDownEvent:nil];
   3382             }
   3383         }
   3384         return result;
   3385     }
   3386     return [hitView shouldDelayWindowOrderingForEvent:event];
   3387 }
   3388 
   3389 - (void)mouseDown:(NSEvent *)event
   3390 {
   3391     // There's a chance that responding to this event will run a nested event loop, and
   3392     // fetching a new event might release the old one. Retaining and then autoreleasing
   3393     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3394     [[event retain] autorelease];
   3395 
   3396     RetainPtr<WebHTMLView> protector = self;
   3397     if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event])
   3398         return;
   3399 
   3400     _private->handlingMouseDownEvent = YES;
   3401 
   3402     // Record the mouse down position so we can determine drag hysteresis.
   3403     [self _setMouseDownEvent:event];
   3404 
   3405     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
   3406     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
   3407         goto done;
   3408 
   3409     [_private->completionController endRevertingChange:NO moveLeft:NO];
   3410 
   3411     // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here.
   3412     // We don't want to pass them along to KHTML a second time.
   3413     if (!([event modifierFlags] & NSControlKeyMask)) {
   3414         _private->ignoringMouseDraggedEvents = NO;
   3415 
   3416         // Don't do any mouseover while the mouse is down.
   3417         [self _cancelUpdateMouseoverTimer];
   3418 
   3419         // Let WebCore get a chance to deal with the event. This will call back to us
   3420         // to start the autoscroll timer if appropriate.
   3421         if (Frame* coreframe = core([self _frame]))
   3422             coreframe->eventHandler()->mouseDown(event);
   3423     }
   3424 
   3425 done:
   3426     _private->handlingMouseDownEvent = NO;
   3427 }
   3428 
   3429 - (void)dragImage:(NSImage *)dragImage
   3430                at:(NSPoint)at
   3431            offset:(NSSize)offset
   3432             event:(NSEvent *)event
   3433        pasteboard:(NSPasteboard *)pasteboard
   3434            source:(id)source
   3435         slideBack:(BOOL)slideBack
   3436 {
   3437     ASSERT(self == [self _topHTMLView]);
   3438     [super dragImage:dragImage at:at offset:offset event:event pasteboard:pasteboard source:source slideBack:slideBack];
   3439 }
   3440 
   3441 - (void)mouseDragged:(NSEvent *)event
   3442 {
   3443     // There's a chance that responding to this event will run a nested event loop, and
   3444     // fetching a new event might release the old one. Retaining and then autoreleasing
   3445     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3446     [[event retain] autorelease];
   3447 
   3448     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
   3449     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
   3450         return;
   3451 
   3452     [self retain];
   3453 
   3454     if (!_private->ignoringMouseDraggedEvents) {
   3455         if (Frame* frame = core([self _frame])) {
   3456             if (Page* page = frame->page())
   3457                 page->mainFrame()->eventHandler()->mouseDragged(event);
   3458         }
   3459     }
   3460 
   3461     [self release];
   3462 }
   3463 
   3464 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
   3465 {
   3466     ASSERT(![self _webView] || [self _isTopHTMLView]);
   3467 
   3468     Page* page = core([self _webView]);
   3469     if (!page)
   3470         return NSDragOperationNone;
   3471 
   3472     return (NSDragOperation)page->dragController()->sourceDragOperation();
   3473 }
   3474 
   3475 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
   3476 {
   3477     ASSERT(![self _webView] || [self _isTopHTMLView]);
   3478 
   3479     NSPoint windowImageLoc = [[self window] convertScreenToBase:aPoint];
   3480     NSPoint windowMouseLoc = windowImageLoc;
   3481 
   3482     if (Page* page = core([self _webView])) {
   3483         DragController* dragController = page->dragController();
   3484         windowMouseLoc = NSMakePoint(windowImageLoc.x + dragController->dragOffset().x(), windowImageLoc.y + dragController->dragOffset().y());
   3485         dragController->dragEnded();
   3486     }
   3487 
   3488     [[self _frame] _dragSourceEndedAt:windowMouseLoc operation:operation];
   3489 
   3490     // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event.
   3491     _private->ignoringMouseDraggedEvents = YES;
   3492 
   3493     // Once the dragging machinery kicks in, we no longer get mouse drags or the up event.
   3494     // WebCore expects to get balanced down/up's, so we must fake up a mouseup.
   3495     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
   3496                                             location:windowMouseLoc
   3497                                        modifierFlags:[[NSApp currentEvent] modifierFlags]
   3498                                            timestamp:[NSDate timeIntervalSinceReferenceDate]
   3499                                         windowNumber:[[self window] windowNumber]
   3500                                              context:[[NSApp currentEvent] context]
   3501                                          eventNumber:0 clickCount:0 pressure:0];
   3502     [self mouseUp:fakeEvent]; // This will also update the mouseover state.
   3503 }
   3504 
   3505 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
   3506 {
   3507     NSFileWrapper *wrapper = nil;
   3508     NSURL *draggingImageURL = nil;
   3509 
   3510     if (WebCore::CachedImage* tiffResource = [self promisedDragTIFFDataSource]) {
   3511 
   3512         SharedBuffer *buffer = static_cast<CachedResource*>(tiffResource)->data();
   3513         if (!buffer)
   3514             goto noPromisedData;
   3515 
   3516         NSData *data = buffer->createNSData();
   3517         NSURLResponse *response = tiffResource->response().nsURLResponse();
   3518         draggingImageURL = [response URL];
   3519         wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease];
   3520         NSString* filename = [response suggestedFilename];
   3521         NSString* trueExtension(tiffResource->image()->filenameExtension());
   3522         if (!matchesExtensionOrEquivalent(filename, trueExtension))
   3523             filename = [[filename stringByAppendingString:@"."] stringByAppendingString:trueExtension];
   3524         [wrapper setPreferredFilename:filename];
   3525     }
   3526 
   3527 noPromisedData:
   3528 
   3529     if (!wrapper) {
   3530         ASSERT(![self _webView] || [self _isTopHTMLView]);
   3531         Page* page = core([self _webView]);
   3532 
   3533         //If a load occurs midway through a drag, the view may be detached, which gives
   3534         //us no ability to get to the original Page, so we cannot access any drag state
   3535         //FIXME: is there a way to recover?
   3536         if (!page)
   3537             return nil;
   3538 
   3539         const KURL& imageURL = page->dragController()->draggingImageURL();
   3540         ASSERT(!imageURL.isEmpty());
   3541         draggingImageURL = imageURL;
   3542 
   3543         wrapper = [[self _dataSource] _fileWrapperForURL:draggingImageURL];
   3544     }
   3545 
   3546     if (wrapper == nil) {
   3547         LOG_ERROR("Failed to create image file.");
   3548         return nil;
   3549     }
   3550 
   3551     // FIXME: Report an error if we fail to create a file.
   3552     NSString *path = [[dropDestination path] stringByAppendingPathComponent:[wrapper preferredFilename]];
   3553     path = [[NSFileManager defaultManager] _webkit_pathWithUniqueFilenameForPath:path];
   3554     if (![wrapper writeToFile:path atomically:NO updateFilenames:YES])
   3555         LOG_ERROR("Failed to create image file via -[NSFileWrapper writeToFile:atomically:updateFilenames:]");
   3556 
   3557     if (draggingImageURL)
   3558         [[NSFileManager defaultManager] _webkit_setMetadataURL:[draggingImageURL absoluteString] referrer:nil atPath:path];
   3559 
   3560     return [NSArray arrayWithObject:[path lastPathComponent]];
   3561 }
   3562 
   3563 - (void)mouseUp:(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     [self _setMouseDownEvent:nil];
   3571 
   3572     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
   3573     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
   3574         return;
   3575 
   3576     [self retain];
   3577 
   3578     [self _stopAutoscrollTimer];
   3579     if (Frame* frame = core([self _frame])) {
   3580         if (Page* page = frame->page())
   3581             page->mainFrame()->eventHandler()->mouseUp(event);
   3582     }
   3583     [self _updateMouseoverWithFakeEvent];
   3584 
   3585     [self release];
   3586 }
   3587 
   3588 - (void)mouseMovedNotification:(NSNotification *)notification
   3589 {
   3590     [self _updateMouseoverWithEvent:[[notification userInfo] objectForKey:@"NSEvent"]];
   3591 }
   3592 
   3593 // returning YES from this method is the way we tell AppKit that it is ok for this view
   3594 // to be in the key loop even when "tab to all controls" is not on.
   3595 - (BOOL)needsPanelToBecomeKey
   3596 {
   3597     return YES;
   3598 }
   3599 
   3600 // Utility function to make sure we don't return anything through the NSTextInput
   3601 // API when an editable region is not currently focused.
   3602 static BOOL isTextInput(Frame* coreFrame)
   3603 {
   3604     return coreFrame && !coreFrame->selection()->isNone() && coreFrame->selection()->isContentEditable();
   3605 }
   3606 
   3607 static BOOL isInPasswordField(Frame* coreFrame)
   3608 {
   3609     return coreFrame && coreFrame->selection()->isInPasswordField();
   3610 }
   3611 
   3612 - (BOOL)becomeFirstResponder
   3613 {
   3614     NSSelectionDirection direction = NSDirectSelection;
   3615     if (![[self _webView] _isPerformingProgrammaticFocus])
   3616         direction = [[self window] keyViewSelectionDirection];
   3617 
   3618     [self _updateFontPanel];
   3619 
   3620     Frame* frame = core([self _frame]);
   3621     if (!frame)
   3622         return YES;
   3623 
   3624     BOOL exposeInputContext = isTextInput(frame) && !isInPasswordField(frame);
   3625     if (exposeInputContext != _private->exposeInputContext) {
   3626         _private->exposeInputContext = exposeInputContext;
   3627         [NSApp updateWindows];
   3628     }
   3629 
   3630     frame->editor()->setStartNewKillRingSequence(true);
   3631 
   3632     Page* page = frame->page();
   3633     if (!page)
   3634         return YES;
   3635 
   3636     if (![[self _webView] _isPerformingProgrammaticFocus])
   3637         page->focusController()->setFocusedFrame(frame);
   3638 
   3639     page->focusController()->setFocused(true);
   3640 
   3641     if (direction == NSDirectSelection)
   3642         return YES;
   3643 
   3644     if (Document* document = frame->document())
   3645         document->setFocusedNode(0);
   3646     page->focusController()->setInitialFocus(direction == NSSelectingNext ? FocusDirectionForward : FocusDirectionBackward,
   3647                                              frame->eventHandler()->currentKeyboardEvent().get());
   3648     return YES;
   3649 }
   3650 
   3651 - (BOOL)resignFirstResponder
   3652 {
   3653     BOOL resign = [super resignFirstResponder];
   3654     if (resign) {
   3655         [_private->completionController endRevertingChange:NO moveLeft:NO];
   3656         Frame* coreFrame = core([self _frame]);
   3657         if (!coreFrame)
   3658             return resign;
   3659         Page* page = coreFrame->page();
   3660         if (!page)
   3661             return resign;
   3662         if (![self maintainsInactiveSelection]) {
   3663             [self deselectAll];
   3664             if (![[self _webView] _isPerformingProgrammaticFocus])
   3665                 [self clearFocus];
   3666         }
   3667 
   3668         id nextResponder = [[self window] _newFirstResponderAfterResigning];
   3669         bool nextResponderIsInWebView = [nextResponder isKindOfClass:[NSView class]]
   3670             && [nextResponder isDescendantOf:[[[self _webView] mainFrame] frameView]];
   3671         if (!nextResponderIsInWebView)
   3672             page->focusController()->setFocused(false);
   3673     }
   3674     return resign;
   3675 }
   3676 
   3677 - (void)setDataSource:(WebDataSource *)dataSource
   3678 {
   3679     ASSERT(dataSource);
   3680     if (_private->dataSource != dataSource) {
   3681         ASSERT(!_private->closed);
   3682         BOOL hadDataSource = _private->dataSource != nil;
   3683 
   3684         [dataSource retain];
   3685         [_private->dataSource release];
   3686         _private->dataSource = dataSource;
   3687         [_private->pluginController setDataSource:dataSource];
   3688 
   3689         if (!hadDataSource)
   3690             [self addMouseMovedObserver];
   3691     }
   3692 }
   3693 
   3694 - (void)dataSourceUpdated:(WebDataSource *)dataSource
   3695 {
   3696 }
   3697 
   3698 // This is an override of an NSControl method that wants to repaint the entire view when the window resigns/becomes
   3699 // key.  WebHTMLView is an NSControl only because it hosts NSCells that are painted by WebCore's Aqua theme
   3700 // renderer (and those cells must be hosted by an enclosing NSControl in order to paint properly).
   3701 - (void)updateCell:(NSCell*)cell
   3702 {
   3703 }
   3704 
   3705 // Does setNeedsDisplay:NO as a side effect when printing is ending.
   3706 // pageWidth != 0 implies we will relayout to a new width
   3707 - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize
   3708 {
   3709     WebFrame *frame = [self _frame];
   3710     NSArray *subframes = [frame childFrames];
   3711     unsigned n = [subframes count];
   3712     unsigned i;
   3713     for (i = 0; i != n; ++i) {
   3714         WebFrame *subframe = [subframes objectAtIndex:i];
   3715         WebFrameView *frameView = [subframe frameView];
   3716         if ([[subframe _dataSource] _isDocumentHTML]) {
   3717             [(WebHTMLView *)[frameView documentView] _setPrinting:printing minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:adjustViewSize];
   3718         }
   3719     }
   3720 
   3721     if (printing != _private->printing) {
   3722         [_private->pageRects release];
   3723         _private->pageRects = nil;
   3724         _private->printing = printing;
   3725         if (!printing)
   3726             _private->avoidingPrintOrphan = NO;
   3727         [self setNeedsToApplyStyles:YES];
   3728         [self setNeedsLayout:YES];
   3729         [self layoutToMinimumPageWidth:minPageWidth maximumPageWidth:maxPageWidth adjustingViewSize:adjustViewSize];
   3730         if (!printing) {
   3731             // Can't do this when starting printing or nested printing won't work, see 3491427.
   3732             [self setNeedsDisplay:NO];
   3733         }
   3734     }
   3735 }
   3736 
   3737 - (BOOL)canPrintHeadersAndFooters
   3738 {
   3739     return YES;
   3740 }
   3741 
   3742 // This is needed for the case where the webview is embedded in the view that's being printed.
   3743 // It shouldn't be called when the webview is being printed directly.
   3744 - (void)adjustPageHeightNew:(CGFloat *)newBottom top:(CGFloat)oldTop bottom:(CGFloat)oldBottom limit:(CGFloat)bottomLimit
   3745 {
   3746     // This helps when we print as part of a larger print process.
   3747     // If the WebHTMLView itself is what we're printing, then we will never have to do this.
   3748     BOOL wasInPrintingMode = _private->printing;
   3749     if (!wasInPrintingMode)
   3750         [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   3751 
   3752     float newBottomFloat = *newBottom;
   3753     if (Frame* frame = core([self _frame])) {
   3754         if (FrameView* view = frame->view())
   3755             view->adjustPageHeight(&newBottomFloat, oldTop, oldBottom, bottomLimit);
   3756     }
   3757 
   3758 #ifdef __LP64__
   3759     // If the new bottom is equal to the old bottom (when both are treated as floats), we just copy
   3760     // oldBottom over to newBottom. This prevents rounding errors that can occur when converting newBottomFloat to a double.
   3761     if (fabs((float)oldBottom - newBottomFloat) <= numeric_limits<float>::epsilon())
   3762         *newBottom = oldBottom;
   3763     else
   3764 #endif
   3765         *newBottom = newBottomFloat;
   3766 
   3767     if (!wasInPrintingMode) {
   3768         NSPrintOperation *currenPrintOperation = [NSPrintOperation currentOperation];
   3769         if (currenPrintOperation)
   3770             // delay _setPrinting:NO until back to main loop as this method may get called repeatedly
   3771             [self performSelector:@selector(_delayedEndPrintMode:) withObject:currenPrintOperation afterDelay:0];
   3772         else
   3773             // not sure if this is actually ever invoked, it probably shouldn't be
   3774             [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   3775     }
   3776 }
   3777 
   3778 - (float)_availablePaperWidthForPrintOperation:(NSPrintOperation *)printOperation
   3779 {
   3780     NSPrintInfo *printInfo = [printOperation printInfo];
   3781     return [printInfo paperSize].width - [printInfo leftMargin] - [printInfo rightMargin];
   3782 }
   3783 
   3784 - (float)_scaleFactorForPrintOperation:(NSPrintOperation *)printOperation
   3785 {
   3786     float viewWidth = NSWidth([self bounds]);
   3787     if (viewWidth < 1) {
   3788         LOG_ERROR("%@ has no width when printing", self);
   3789         return 1.0f;
   3790     }
   3791 
   3792     float userScaleFactor = [printOperation _web_pageSetupScaleFactor];
   3793     float maxShrinkToFitScaleFactor = 1.0f / PrintingMaximumShrinkFactor;
   3794     float shrinkToFitScaleFactor = [self _availablePaperWidthForPrintOperation:printOperation]/viewWidth;
   3795     float shrinkToAvoidOrphan = _private->avoidingPrintOrphan ? (1.0f / PrintingOrphanShrinkAdjustment) : 1.0f;
   3796     return userScaleFactor * max(maxShrinkToFitScaleFactor, shrinkToFitScaleFactor) * shrinkToAvoidOrphan;
   3797 }
   3798 
   3799 // FIXME 3491344: This is a secret AppKit-internal method that we need to override in order
   3800 // to get our shrink-to-fit to work with a custom pagination scheme. We can do this better
   3801 // if AppKit makes it SPI/API.
   3802 - (CGFloat)_provideTotalScaleFactorForPrintOperation:(NSPrintOperation *)printOperation
   3803 {
   3804     return [self _scaleFactorForPrintOperation:printOperation];
   3805 }
   3806 
   3807 // This is used for Carbon printing. At some point we might want to make this public API.
   3808 - (void)setPageWidthForPrinting:(float)pageWidth
   3809 {
   3810     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
   3811     [self _setPrinting:YES minimumPageWidth:pageWidth maximumPageWidth:pageWidth adjustViewSize:YES];
   3812 }
   3813 
   3814 - (void)_endPrintMode
   3815 {
   3816     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:YES];
   3817     [[self window] setAutodisplay:YES];
   3818 }
   3819 
   3820 - (void)_delayedEndPrintMode:(NSPrintOperation *)initiatingOperation
   3821 {
   3822     ASSERT_ARG(initiatingOperation, initiatingOperation != nil);
   3823     NSPrintOperation *currentOperation = [NSPrintOperation currentOperation];
   3824     if (initiatingOperation == currentOperation) {
   3825         // The print operation is still underway. We don't expect this to ever happen, hence the assert, but we're
   3826         // being extra paranoid here since the printing code is so fragile. Delay the cleanup
   3827         // further.
   3828         ASSERT_NOT_REACHED();
   3829         [self performSelector:@selector(_delayedEndPrintMode:) withObject:initiatingOperation afterDelay:0];
   3830     } else if ([currentOperation view] == self) {
   3831         // A new print job has started, but it is printing the same WebHTMLView again. We don't expect
   3832         // this to ever happen, hence the assert, but we're being extra paranoid here since the printing code is so
   3833         // fragile. Do nothing, because we don't want to break the print job currently in progress, and
   3834         // the print job currently in progress is responsible for its own cleanup.
   3835         ASSERT_NOT_REACHED();
   3836     } else {
   3837         // The print job that kicked off this delayed call has finished, and this view is not being
   3838         // printed again. We expect that no other print job has started. Since this delayed call wasn't
   3839         // cancelled, beginDocument and endDocument must not have been called, and we need to clean up
   3840         // the print mode here.
   3841         ASSERT(currentOperation == nil);
   3842         [self _endPrintMode];
   3843     }
   3844 }
   3845 
   3846 // Return the number of pages available for printing
   3847 - (BOOL)knowsPageRange:(NSRangePointer)range
   3848 {
   3849     // Must do this explicit display here, because otherwise the view might redisplay while the print
   3850     // sheet was up, using printer fonts (and looking different).
   3851     [self displayIfNeeded];
   3852     [[self window] setAutodisplay:NO];
   3853 
   3854     // If we are a frameset just print with the layout we have onscreen, otherwise relayout
   3855     // according to the paper size
   3856     float minLayoutWidth = 0.0f;
   3857     float maxLayoutWidth = 0.0f;
   3858     Frame* frame = core([self _frame]);
   3859     if (!frame)
   3860         return NO;
   3861     if (!frame->document() || !frame->document()->isFrameSet()) {
   3862         float paperWidth = [self _availablePaperWidthForPrintOperation:[NSPrintOperation currentOperation]];
   3863         minLayoutWidth = paperWidth * PrintingMinimumShrinkFactor;
   3864         maxLayoutWidth = paperWidth * PrintingMaximumShrinkFactor;
   3865     }
   3866     [self _setPrinting:YES minimumPageWidth:minLayoutWidth maximumPageWidth:maxLayoutWidth adjustViewSize:YES]; // will relayout
   3867     NSPrintOperation *printOperation = [NSPrintOperation currentOperation];
   3868     // Certain types of errors, including invalid page ranges, can cause beginDocument and
   3869     // endDocument to be skipped after we've put ourselves in print mode (see 4145905). In those cases
   3870     // we need to get out of print mode without relying on any more callbacks from the printing mechanism.
   3871     // If we get as far as beginDocument without trouble, then this delayed request will be cancelled.
   3872     // If not cancelled, this delayed call will be invoked in the next pass through the main event loop,
   3873     // which is after beginDocument and endDocument would be called.
   3874     [self performSelector:@selector(_delayedEndPrintMode:) withObject:printOperation afterDelay:0];
   3875     [[self _webView] _adjustPrintingMarginsForHeaderAndFooter];
   3876 
   3877     // There is a theoretical chance that someone could do some drawing between here and endDocument,
   3878     // if something caused setNeedsDisplay after this point. If so, it's not a big tragedy, because
   3879     // you'd simply see the printer fonts on screen. As of this writing, this does not happen with Safari.
   3880 
   3881     range->location = 1;
   3882     float totalScaleFactor = [self _scaleFactorForPrintOperation:printOperation];
   3883     float userScaleFactor = [printOperation _web_pageSetupScaleFactor];
   3884     [_private->pageRects release];
   3885     float fullPageHeight = floorf([self _calculatePrintHeight]/totalScaleFactor);
   3886     NSArray *newPageRects = [[self _frame] _computePageRectsWithPrintWidthScaleFactor:userScaleFactor
   3887                                                                           printHeight:fullPageHeight];
   3888 
   3889     // AppKit gets all messed up if you give it a zero-length page count (see 3576334), so if we
   3890     // hit that case we'll pass along a degenerate 1 pixel square to print. This will print
   3891     // a blank page (with correct-looking header and footer if that option is on), which matches
   3892     // the behavior of IE and Camino at least.
   3893     if ([newPageRects count] == 0)
   3894         newPageRects = [NSArray arrayWithObject:[NSValue valueWithRect:NSMakeRect(0, 0, 1, 1)]];
   3895     else if ([newPageRects count] > 1) {
   3896         // If the last page is a short orphan, try adjusting the print height slightly to see if this will squeeze the
   3897         // content onto one fewer page. If it does, use the adjusted scale. If not, use the original scale.
   3898         float lastPageHeight = NSHeight([[newPageRects lastObject] rectValue]);
   3899         if (lastPageHeight/fullPageHeight < LastPrintedPageOrphanRatio) {
   3900             NSArray *adjustedPageRects = [[self _frame] _computePageRectsWithPrintWidthScaleFactor:userScaleFactor
   3901                                                                                        printHeight:fullPageHeight*PrintingOrphanShrinkAdjustment];
   3902             // Use the adjusted rects only if the page count went down
   3903             if ([adjustedPageRects count] < [newPageRects count]) {
   3904                 newPageRects = adjustedPageRects;
   3905                 _private->avoidingPrintOrphan = YES;
   3906             }
   3907         }
   3908     }
   3909 
   3910     _private->pageRects = [newPageRects retain];
   3911 
   3912     range->length = [_private->pageRects count];
   3913 
   3914     return YES;
   3915 }
   3916 
   3917 // Return the drawing rectangle for a particular page number
   3918 - (NSRect)rectForPage:(NSInteger)page
   3919 {
   3920     return [[_private->pageRects objectAtIndex:page - 1] rectValue];
   3921 }
   3922 
   3923 - (void)drawPageBorderWithSize:(NSSize)borderSize
   3924 {
   3925     ASSERT(NSEqualSizes(borderSize, [[[NSPrintOperation currentOperation] printInfo] paperSize]));
   3926     [[self _webView] _drawHeaderAndFooter];
   3927 }
   3928 
   3929 - (void)beginDocument
   3930 {
   3931     @try {
   3932         // From now on we'll get a chance to call _endPrintMode in either beginDocument or
   3933         // endDocument, so we can cancel the "just in case" pending call.
   3934         [NSObject cancelPreviousPerformRequestsWithTarget:self
   3935                                                  selector:@selector(_delayedEndPrintMode:)
   3936                                                    object:[NSPrintOperation currentOperation]];
   3937         [super beginDocument];
   3938     } @catch (NSException *localException) {
   3939         // Exception during [super beginDocument] means that endDocument will not get called,
   3940         // so we need to clean up our "print mode" here.
   3941         [self _endPrintMode];
   3942     }
   3943 }
   3944 
   3945 - (void)endDocument
   3946 {
   3947     [super endDocument];
   3948     // Note sadly at this point [NSGraphicsContext currentContextDrawingToScreen] is still NO
   3949     [self _endPrintMode];
   3950 }
   3951 
   3952 - (void)keyDown:(NSEvent *)event
   3953 {
   3954     // There's a chance that responding to this event will run a nested event loop, and
   3955     // fetching a new event might release the old one. Retaining and then autoreleasing
   3956     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3957     [[event retain] autorelease];
   3958 
   3959     RetainPtr<WebHTMLView> selfProtector = self;
   3960     BOOL eventWasSentToWebCore = (_private->keyDownEvent == event);
   3961 
   3962     BOOL callSuper = NO;
   3963 
   3964     [_private->keyDownEvent release];
   3965     _private->keyDownEvent = [event retain];
   3966 
   3967     BOOL completionPopupWasOpen = _private->completionController && [_private->completionController popupWindowIsOpen];
   3968     Frame* coreFrame = core([self _frame]);
   3969     if (!eventWasSentToWebCore && coreFrame && coreFrame->eventHandler()->keyEvent(event)) {
   3970         // WebCore processed a key event, bail on any preexisting complete: UI
   3971         if (completionPopupWasOpen)
   3972             [_private->completionController endRevertingChange:YES moveLeft:NO];
   3973     } else if (!_private->completionController || ![_private->completionController filterKeyDown:event]) {
   3974         // Not consumed by complete: popup window
   3975         [_private->completionController endRevertingChange:YES moveLeft:NO];
   3976         callSuper = YES;
   3977     }
   3978     if (callSuper)
   3979         [super keyDown:event];
   3980     else
   3981         [NSCursor setHiddenUntilMouseMoves:YES];
   3982 }
   3983 
   3984 - (void)keyUp:(NSEvent *)event
   3985 {
   3986     // There's a chance that responding to this event will run a nested event loop, and
   3987     // fetching a new event might release the old one. Retaining and then autoreleasing
   3988     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   3989     [[event retain] autorelease];
   3990 
   3991     BOOL eventWasSentToWebCore = (_private->keyDownEvent == event);
   3992 
   3993     RetainPtr<WebHTMLView> selfProtector = self;
   3994     Frame* coreFrame = core([self _frame]);
   3995     if (coreFrame && !eventWasSentToWebCore)
   3996         coreFrame->eventHandler()->keyEvent(event);
   3997     else
   3998         [super keyUp:event];
   3999 }
   4000 
   4001 - (void)flagsChanged:(NSEvent *)event
   4002 {
   4003     // There's a chance that responding to this event will run a nested event loop, and
   4004     // fetching a new event might release the old one. Retaining and then autoreleasing
   4005     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   4006     [[event retain] autorelease];
   4007 
   4008     Frame* coreFrame = core([self _frame]);
   4009     if (coreFrame)
   4010         coreFrame->eventHandler()->capsLockStateMayHaveChanged();
   4011 
   4012     RetainPtr<WebHTMLView> selfProtector = self;
   4013 
   4014     unsigned short keyCode = [event keyCode];
   4015 
   4016     //Don't make an event from the num lock and function keys
   4017     if (coreFrame && keyCode != 0 && keyCode != 10 && keyCode != 63) {
   4018         coreFrame->eventHandler()->keyEvent(PlatformKeyboardEvent(event));
   4019         return;
   4020     }
   4021 
   4022     [super flagsChanged:event];
   4023 }
   4024 
   4025 - (id)accessibilityAttributeValue:(NSString*)attributeName
   4026 {
   4027     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
   4028         id accTree = [[self _frame] _accessibilityTree];
   4029         if (accTree)
   4030             return [NSArray arrayWithObject:accTree];
   4031         return nil;
   4032     }
   4033     return [super accessibilityAttributeValue:attributeName];
   4034 }
   4035 
   4036 - (id)accessibilityFocusedUIElement
   4037 {
   4038     id accTree = [[self _frame] _accessibilityTree];
   4039     if (accTree)
   4040         return [accTree accessibilityFocusedUIElement];
   4041     return self;
   4042 }
   4043 
   4044 - (id)accessibilityHitTest:(NSPoint)point
   4045 {
   4046     id accTree = [[self _frame] _accessibilityTree];
   4047     if (accTree) {
   4048         NSPoint windowCoord = [[self window] convertScreenToBase:point];
   4049         return [accTree accessibilityHitTest:[self convertPoint:windowCoord fromView:nil]];
   4050     }
   4051     return self;
   4052 }
   4053 
   4054 - (id)_accessibilityParentForSubview:(NSView *)subview
   4055 {
   4056     id accTree = [[self _frame] _accessibilityTree];
   4057     if (!accTree)
   4058         return self;
   4059     id parent = [accTree _accessibilityParentForSubview:subview];
   4060     if (!parent)
   4061         return self;
   4062     return parent;
   4063 }
   4064 
   4065 - (void)centerSelectionInVisibleArea:(id)sender
   4066 {
   4067     COMMAND_PROLOGUE
   4068 
   4069     if (Frame* coreFrame = core([self _frame]))
   4070         coreFrame->revealSelection(ScrollAlignment::alignCenterAlways);
   4071 }
   4072 
   4073 - (NSData *)_selectionStartFontAttributesAsRTF
   4074 {
   4075     Frame* coreFrame = core([self _frame]);
   4076     NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"x"
   4077         attributes:coreFrame ? coreFrame->fontAttributesForSelectionStart() : nil];
   4078     NSData *data = [string RTFFromRange:NSMakeRange(0, [string length]) documentAttributes:nil];
   4079     [string release];
   4080     return data;
   4081 }
   4082 
   4083 - (NSDictionary *)_fontAttributesFromFontPasteboard
   4084 {
   4085     NSPasteboard *fontPasteboard = [NSPasteboard pasteboardWithName:NSFontPboard];
   4086     if (fontPasteboard == nil)
   4087         return nil;
   4088     NSData *data = [fontPasteboard dataForType:NSFontPboardType];
   4089     if (data == nil || [data length] == 0)
   4090         return nil;
   4091     // NSTextView does something more efficient by parsing the attributes only, but that's not available in API.
   4092     NSAttributedString *string = [[[NSAttributedString alloc] initWithRTF:data documentAttributes:NULL] autorelease];
   4093     if (string == nil || [string length] == 0)
   4094         return nil;
   4095     return [string fontAttributesInRange:NSMakeRange(0, 1)];
   4096 }
   4097 
   4098 - (DOMCSSStyleDeclaration *)_emptyStyle
   4099 {
   4100     return [[[self _frame] DOMDocument] createCSSStyleDeclaration];
   4101 }
   4102 
   4103 - (NSString *)_colorAsString:(NSColor *)color
   4104 {
   4105     NSColor *rgbColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
   4106     // FIXME: If color is non-nil and rgbColor is nil, that means we got some kind
   4107     // of fancy color that can't be converted to RGB. Changing that to "transparent"
   4108     // might not be great, but it's probably OK.
   4109     if (rgbColor == nil)
   4110         return @"transparent";
   4111     float r = [rgbColor redComponent];
   4112     float g = [rgbColor greenComponent];
   4113     float b = [rgbColor blueComponent];
   4114     float a = [rgbColor alphaComponent];
   4115     if (a == 0)
   4116         return @"transparent";
   4117     if (r == 0 && g == 0 && b == 0 && a == 1)
   4118         return @"black";
   4119     if (r == 1 && g == 1 && b == 1 && a == 1)
   4120         return @"white";
   4121     // FIXME: Lots more named colors. Maybe we could use the table in WebCore?
   4122     if (a == 1)
   4123         return [NSString stringWithFormat:@"rgb(%.0f,%.0f,%.0f)", r * 255, g * 255, b * 255];
   4124     return [NSString stringWithFormat:@"rgba(%.0f,%.0f,%.0f,%f)", r * 255, g * 255, b * 255, a];
   4125 }
   4126 
   4127 - (NSString *)_shadowAsString:(NSShadow *)shadow
   4128 {
   4129     if (shadow == nil)
   4130         return @"none";
   4131     NSSize offset = [shadow shadowOffset];
   4132     float blurRadius = [shadow shadowBlurRadius];
   4133     if (offset.width == 0 && offset.height == 0 && blurRadius == 0)
   4134         return @"none";
   4135     NSColor *color = [shadow shadowColor];
   4136     if (color == nil)
   4137         return @"none";
   4138     // FIXME: Handle non-integral values here?
   4139     if (blurRadius == 0)
   4140         return [NSString stringWithFormat:@"%@ %.0fpx %.0fpx", [self _colorAsString:color], offset.width, offset.height];
   4141     return [NSString stringWithFormat:@"%@ %.0fpx %.0fpx %.0fpx", [self _colorAsString:color], offset.width, offset.height, blurRadius];
   4142 }
   4143 
   4144 - (DOMCSSStyleDeclaration *)_styleFromFontAttributes:(NSDictionary *)dictionary
   4145 {
   4146     DOMCSSStyleDeclaration *style = [self _emptyStyle];
   4147 
   4148     NSColor *color = [dictionary objectForKey:NSBackgroundColorAttributeName];
   4149     [style setBackgroundColor:[self _colorAsString:color]];
   4150 
   4151     NSFont *font = [dictionary objectForKey:NSFontAttributeName];
   4152     if (!font) {
   4153         [style setFontFamily:@"Helvetica"];
   4154         [style setFontSize:@"12px"];
   4155         [style setFontWeight:@"normal"];
   4156         [style setFontStyle:@"normal"];
   4157     } else {
   4158         NSFontManager *fm = [NSFontManager sharedFontManager];
   4159         // FIXME: Need more sophisticated escaping code if we want to handle family names
   4160         // with characters like single quote or backslash in their names.
   4161         [style setFontFamily:[NSString stringWithFormat:@"'%@'", [font familyName]]];
   4162         [style setFontSize:[NSString stringWithFormat:@"%0.fpx", [font pointSize]]];
   4163         // FIXME: Map to the entire range of CSS weight values.
   4164         if ([fm weightOfFont:font] >= MIN_BOLD_WEIGHT)
   4165             [style setFontWeight:@"bold"];
   4166         else
   4167             [style setFontWeight:@"normal"];
   4168         if ([fm traitsOfFont:font] & NSItalicFontMask)
   4169             [style setFontStyle:@"italic"];
   4170         else
   4171             [style setFontStyle:@"normal"];
   4172     }
   4173 
   4174     color = [dictionary objectForKey:NSForegroundColorAttributeName];
   4175     [style setColor:color ? [self _colorAsString:color] : (NSString *)@"black"];
   4176 
   4177     NSShadow *shadow = [dictionary objectForKey:NSShadowAttributeName];
   4178     [style setTextShadow:[self _shadowAsString:shadow]];
   4179 
   4180     int strikethroughInt = [[dictionary objectForKey:NSStrikethroughStyleAttributeName] intValue];
   4181 
   4182     int superscriptInt = [[dictionary objectForKey:NSSuperscriptAttributeName] intValue];
   4183     if (superscriptInt > 0)
   4184         [style setVerticalAlign:@"super"];
   4185     else if (superscriptInt < 0)
   4186         [style setVerticalAlign:@"sub"];
   4187     else
   4188         [style setVerticalAlign:@"baseline"];
   4189     int underlineInt = [[dictionary objectForKey:NSUnderlineStyleAttributeName] intValue];
   4190     // FIXME: Underline wins here if we have both (see bug 3790443).
   4191     if (strikethroughInt == NSUnderlineStyleNone && underlineInt == NSUnderlineStyleNone)
   4192         [style setProperty:@"-khtml-text-decorations-in-effect" value:@"none" priority:@""];
   4193     else if (underlineInt == NSUnderlineStyleNone)
   4194         [style setProperty:@"-khtml-text-decorations-in-effect" value:@"line-through" priority:@""];
   4195     else
   4196         [style setProperty:@"-khtml-text-decorations-in-effect" value:@"underline" priority:@""];
   4197 
   4198     return style;
   4199 }
   4200 
   4201 - (void)_applyStyleToSelection:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
   4202 {
   4203     if (Frame* coreFrame = core([self _frame]))
   4204         coreFrame->editor()->applyStyleToSelection(core(style), undoAction);
   4205 }
   4206 
   4207 - (void)_applyParagraphStyleToSelection:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
   4208 {
   4209     if (Frame* coreFrame = core([self _frame]))
   4210         coreFrame->editor()->applyParagraphStyleToSelection(core(style), undoAction);
   4211 }
   4212 
   4213 - (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event
   4214 {
   4215     ASSERT([self _webView]);
   4216     if (![[[self _webView] preferences] respectStandardStyleKeyEquivalents])
   4217         return NO;
   4218 
   4219     if (![self _canEdit])
   4220         return NO;
   4221 
   4222     if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) != NSCommandKeyMask)
   4223         return NO;
   4224 
   4225     NSString *string = [event characters];
   4226     if ([string caseInsensitiveCompare:@"b"] == NSOrderedSame) {
   4227         [self executeCoreCommandByName:"ToggleBold"];
   4228         return YES;
   4229     }
   4230     if ([string caseInsensitiveCompare:@"i"] == NSOrderedSame) {
   4231         [self executeCoreCommandByName:"ToggleItalic"];
   4232         return YES;
   4233     }
   4234 
   4235     return NO;
   4236 }
   4237 
   4238 - (BOOL)performKeyEquivalent:(NSEvent *)event
   4239 {
   4240     // There's a chance that responding to this event will run a nested event loop, and
   4241     // fetching a new event might release the old one. Retaining and then autoreleasing
   4242     // the current event prevents that from causing a problem inside WebKit or AppKit code.
   4243     [[event retain] autorelease];
   4244 
   4245     if ([self _handleStyleKeyEquivalent:event])
   4246         return YES;
   4247 
   4248     BOOL eventWasSentToWebCore = (_private->keyDownEvent == event);
   4249     BOOL ret = NO;
   4250 
   4251     [_private->keyDownEvent release];
   4252     _private->keyDownEvent = [event retain];
   4253 
   4254     [self retain];
   4255 
   4256     // Pass command-key combos through WebCore if there is a key binding available for
   4257     // this event. This lets web pages have a crack at intercepting command-modified keypresses.
   4258     // But don't do it if we have already handled the event.
   4259     // Pressing Esc results in a fake event being sent - don't pass it to WebCore.
   4260     if (!eventWasSentToWebCore && event == [NSApp currentEvent] && self == [[self window] firstResponder])
   4261         if (Frame* frame = core([self _frame]))
   4262             ret = frame->eventHandler()->keyEvent(event);
   4263 
   4264     if (!ret)
   4265         ret = [super performKeyEquivalent:event];
   4266 
   4267     [self release];
   4268 
   4269     return ret;
   4270 }
   4271 
   4272 - (void)copyFont:(id)sender
   4273 {
   4274     COMMAND_PROLOGUE
   4275 
   4276     // Put RTF with font attributes on the pasteboard.
   4277     // Maybe later we should add a pasteboard type that contains CSS text for "native" copy and paste font.
   4278     NSPasteboard *fontPasteboard = [NSPasteboard pasteboardWithName:NSFontPboard];
   4279     [fontPasteboard declareTypes:[NSArray arrayWithObject:NSFontPboardType] owner:nil];
   4280     [fontPasteboard setData:[self _selectionStartFontAttributesAsRTF] forType:NSFontPboardType];
   4281 }
   4282 
   4283 - (void)pasteFont:(id)sender
   4284 {
   4285     COMMAND_PROLOGUE
   4286 
   4287     // Read RTF with font attributes from the pasteboard.
   4288     // Maybe later we should add a pasteboard type that contains CSS text for "native" copy and paste font.
   4289     [self _applyStyleToSelection:[self _styleFromFontAttributes:[self _fontAttributesFromFontPasteboard]] withUndoAction:EditActionPasteFont];
   4290 }
   4291 
   4292 - (void)pasteAsRichText:(id)sender
   4293 {
   4294     COMMAND_PROLOGUE
   4295 
   4296     // Since rich text always beats plain text when both are on the pasteboard, it's not
   4297     // clear how this is different from plain old paste.
   4298     [self _pasteWithPasteboard:[NSPasteboard generalPasteboard] allowPlainText:NO];
   4299 }
   4300 
   4301 - (NSFont *)_originalFontA
   4302 {
   4303     return [[NSFontManager sharedFontManager] fontWithFamily:@"Helvetica" traits:0 weight:STANDARD_WEIGHT size:10.0f];
   4304 }
   4305 
   4306 - (NSFont *)_originalFontB
   4307 {
   4308     return [[NSFontManager sharedFontManager] fontWithFamily:@"Times" traits:NSFontItalicTrait weight:STANDARD_BOLD_WEIGHT size:12.0f];
   4309 }
   4310 
   4311 - (void)_addToStyle:(DOMCSSStyleDeclaration *)style fontA:(NSFont *)a fontB:(NSFont *)b
   4312 {
   4313     // Since there's no way to directly ask NSFontManager what style change it's going to do
   4314     // we instead pass two "specimen" fonts to it and let it change them. We then deduce what
   4315     // style change it was doing by looking at what happened to each of the two fonts.
   4316     // So if it was making the text bold, both fonts will be bold after the fact.
   4317 
   4318     if (a == nil || b == nil)
   4319         return;
   4320 
   4321     NSFontManager *fm = [NSFontManager sharedFontManager];
   4322 
   4323     NSFont *oa = [self _originalFontA];
   4324 
   4325     NSString *aFamilyName = [a familyName];
   4326     NSString *bFamilyName = [b familyName];
   4327 
   4328     int aPointSize = (int)[a pointSize];
   4329     int bPointSize = (int)[b pointSize];
   4330 
   4331     int aWeight = [fm weightOfFont:a];
   4332     int bWeight = [fm weightOfFont:b];
   4333 
   4334     BOOL aIsItalic = ([fm traitsOfFont:a] & NSItalicFontMask) != 0;
   4335     BOOL bIsItalic = ([fm traitsOfFont:b] & NSItalicFontMask) != 0;
   4336 
   4337     BOOL aIsBold = aWeight > MIN_BOLD_WEIGHT;
   4338 
   4339     if ([aFamilyName isEqualToString:bFamilyName]) {
   4340         NSString *familyNameForCSS = aFamilyName;
   4341 
   4342         // The family name may not be specific enough to get us the font specified.
   4343         // In some cases, the only way to get exactly what we are looking for is to use
   4344         // the Postscript name.
   4345 
   4346         // Find the font the same way the rendering code would later if it encountered this CSS.
   4347         NSFontTraitMask traits = aIsItalic ? NSFontItalicTrait : 0;
   4348         int weight = aIsBold ? STANDARD_BOLD_WEIGHT : STANDARD_WEIGHT;
   4349         NSFont *foundFont = [WebFontCache fontWithFamily:aFamilyName traits:traits weight:weight size:aPointSize];
   4350 
   4351         // If we don't find a font with the same Postscript name, then we'll have to use the
   4352         // Postscript name to make the CSS specific enough.
   4353         if (![[foundFont fontName] isEqualToString:[a fontName]])
   4354             familyNameForCSS = [a fontName];
   4355 
   4356         // FIXME: Need more sophisticated escaping code if we want to handle family names
   4357         // with characters like single quote or backslash in their names.
   4358         [style setFontFamily:[NSString stringWithFormat:@"'%@'", familyNameForCSS]];
   4359     }
   4360 
   4361     int soa = (int)[oa pointSize];
   4362     if (aPointSize == bPointSize)
   4363         [style setFontSize:[NSString stringWithFormat:@"%dpx", aPointSize]];
   4364     else if (aPointSize < soa)
   4365         [style _setFontSizeDelta:@"-1px"];
   4366     else if (aPointSize > soa)
   4367         [style _setFontSizeDelta:@"1px"];
   4368 
   4369     // FIXME: Map to the entire range of CSS weight values.
   4370     if (aWeight == bWeight)
   4371         [style setFontWeight:aIsBold ? @"bold" : @"normal"];
   4372 
   4373     if (aIsItalic == bIsItalic)
   4374         [style setFontStyle:aIsItalic ? @"italic" :  @"normal"];
   4375 }
   4376 
   4377 - (DOMCSSStyleDeclaration *)_styleFromFontManagerOperation
   4378 {
   4379     DOMCSSStyleDeclaration *style = [self _emptyStyle];
   4380 
   4381     NSFontManager *fm = [NSFontManager sharedFontManager];
   4382 
   4383     NSFont *oa = [self _originalFontA];
   4384     NSFont *ob = [self _originalFontB];
   4385     [self _addToStyle:style fontA:[fm convertFont:oa] fontB:[fm convertFont:ob]];
   4386 
   4387     return style;
   4388 }
   4389 
   4390 - (void)changeFont:(id)sender
   4391 {
   4392     COMMAND_PROLOGUE
   4393 
   4394     [self _applyStyleToSelection:[self _styleFromFontManagerOperation] withUndoAction:EditActionSetFont];
   4395 }
   4396 
   4397 - (DOMCSSStyleDeclaration *)_styleForAttributeChange:(id)sender
   4398 {
   4399     DOMCSSStyleDeclaration *style = [self _emptyStyle];
   4400 
   4401     NSShadow *shadow = [[NSShadow alloc] init];
   4402     [shadow setShadowOffset:NSMakeSize(1, 1)];
   4403 
   4404     NSDictionary *oa = [NSDictionary dictionaryWithObjectsAndKeys:
   4405         [self _originalFontA], NSFontAttributeName,
   4406         nil];
   4407     NSDictionary *ob = [NSDictionary dictionaryWithObjectsAndKeys:
   4408         [NSColor blackColor], NSBackgroundColorAttributeName,
   4409         [self _originalFontB], NSFontAttributeName,
   4410         [NSColor whiteColor], NSForegroundColorAttributeName,
   4411         shadow, NSShadowAttributeName,
   4412         [NSNumber numberWithInt:NSUnderlineStyleSingle], NSStrikethroughStyleAttributeName,
   4413         [NSNumber numberWithInt:1], NSSuperscriptAttributeName,
   4414         [NSNumber numberWithInt:NSUnderlineStyleSingle], NSUnderlineStyleAttributeName,
   4415         nil];
   4416 
   4417     [shadow release];
   4418 
   4419 #if 0
   4420 
   4421 NSObliquenessAttributeName        /* float; skew to be applied to glyphs, default 0: no skew */
   4422     // font-style, but that is just an on-off switch
   4423 
   4424 NSExpansionAttributeName          /* float; log of expansion factor to be applied to glyphs, default 0: no expansion */
   4425     // font-stretch?
   4426 
   4427 NSKernAttributeName               /* float, amount to modify default kerning, if 0, kerning off */
   4428     // letter-spacing? probably not good enough
   4429 
   4430 NSUnderlineColorAttributeName     /* NSColor, default nil: same as foreground color */
   4431 NSStrikethroughColorAttributeName /* NSColor, default nil: same as foreground color */
   4432     // text-decoration-color?
   4433 
   4434 NSLigatureAttributeName           /* int, default 1: default ligatures, 0: no ligatures, 2: all ligatures */
   4435 NSBaselineOffsetAttributeName     /* float, in points; offset from baseline, default 0 */
   4436 NSStrokeWidthAttributeName        /* float, in percent of font point size, default 0: no stroke; positive for stroke alone, negative for stroke and fill (a typical value for outlined text would be 3.0) */
   4437 NSStrokeColorAttributeName        /* NSColor, default nil: same as foreground color */
   4438     // need extensions?
   4439 
   4440 #endif
   4441 
   4442     NSDictionary *a = [sender convertAttributes:oa];
   4443     NSDictionary *b = [sender convertAttributes:ob];
   4444 
   4445     NSColor *ca = [a objectForKey:NSBackgroundColorAttributeName];
   4446     NSColor *cb = [b objectForKey:NSBackgroundColorAttributeName];
   4447     if (ca == cb) {
   4448         [style setBackgroundColor:[self _colorAsString:ca]];
   4449     }
   4450 
   4451     [self _addToStyle:style fontA:[a objectForKey:NSFontAttributeName] fontB:[b objectForKey:NSFontAttributeName]];
   4452 
   4453     ca = [a objectForKey:NSForegroundColorAttributeName];
   4454     cb = [b objectForKey:NSForegroundColorAttributeName];
   4455     if (ca == cb) {
   4456         [style setColor:[self _colorAsString:ca]];
   4457     }
   4458 
   4459     NSShadow *sha = [a objectForKey:NSShadowAttributeName];
   4460     if (sha)
   4461         [style setTextShadow:[self _shadowAsString:sha]];
   4462     else if ([b objectForKey:NSShadowAttributeName] == nil)
   4463         [style setTextShadow:@"none"];
   4464 
   4465     int sa = [[a objectForKey:NSStrikethroughStyleAttributeName] intValue];
   4466     int sb = [[b objectForKey:NSStrikethroughStyleAttributeName] intValue];
   4467     if (sa == sb) {
   4468         if (sa == NSUnderlineStyleNone)
   4469             [style setProperty:@"-khtml-text-decorations-in-effect" value:@"none" priority:@""];
   4470             // we really mean "no line-through" rather than "none"
   4471         else
   4472             [style setProperty:@"-khtml-text-decorations-in-effect" value:@"line-through" priority:@""];
   4473             // we really mean "add line-through" rather than "line-through"
   4474     }
   4475 
   4476     sa = [[a objectForKey:NSSuperscriptAttributeName] intValue];
   4477     sb = [[b objectForKey:NSSuperscriptAttributeName] intValue];
   4478     if (sa == sb) {
   4479         if (sa > 0)
   4480             [style setVerticalAlign:@"super"];
   4481         else if (sa < 0)
   4482             [style setVerticalAlign:@"sub"];
   4483         else
   4484             [style setVerticalAlign:@"baseline"];
   4485     }
   4486 
   4487     int ua = [[a objectForKey:NSUnderlineStyleAttributeName] intValue];
   4488     int ub = [[b objectForKey:NSUnderlineStyleAttributeName] intValue];
   4489     if (ua == ub) {
   4490         if (ua == NSUnderlineStyleNone)
   4491             [style setProperty:@"-khtml-text-decorations-in-effect" value:@"none" priority:@""];
   4492             // we really mean "no underline" rather than "none"
   4493         else
   4494             [style setProperty:@"-khtml-text-decorations-in-effect" value:@"underline" priority:@""];
   4495             // we really mean "add underline" rather than "underline"
   4496     }
   4497 
   4498     return style;
   4499 }
   4500 
   4501 - (void)changeAttributes:(id)sender
   4502 {
   4503     COMMAND_PROLOGUE
   4504 
   4505     [self _applyStyleToSelection:[self _styleForAttributeChange:sender] withUndoAction:EditActionChangeAttributes];
   4506 }
   4507 
   4508 - (DOMCSSStyleDeclaration *)_styleFromColorPanelWithSelector:(SEL)selector
   4509 {
   4510     DOMCSSStyleDeclaration *style = [self _emptyStyle];
   4511 
   4512     ASSERT([style respondsToSelector:selector]);
   4513     [style performSelector:selector withObject:[self _colorAsString:[[NSColorPanel sharedColorPanel] color]]];
   4514 
   4515     return style;
   4516 }
   4517 
   4518 - (EditAction)_undoActionFromColorPanelWithSelector:(SEL)selector
   4519 {
   4520     if (selector == @selector(setBackgroundColor:))
   4521         return EditActionSetBackgroundColor;
   4522     return EditActionSetColor;
   4523 }
   4524 
   4525 - (void)_changeCSSColorUsingSelector:(SEL)selector inRange:(DOMRange *)range
   4526 {
   4527     DOMCSSStyleDeclaration *style = [self _styleFromColorPanelWithSelector:selector];
   4528     WebView *webView = [self _webView];
   4529     if ([[webView _editingDelegateForwarder] webView:webView shouldApplyStyle:style toElementsInDOMRange:range])
   4530         if (Frame* coreFrame = core([self _frame]))
   4531             coreFrame->editor()->applyStyle(core(style), [self _undoActionFromColorPanelWithSelector:selector]);
   4532 }
   4533 
   4534 - (void)changeDocumentBackgroundColor:(id)sender
   4535 {
   4536     COMMAND_PROLOGUE
   4537 
   4538     // Mimicking NSTextView, this method sets the background color for the
   4539     // entire document. There is no NSTextView API for setting the background
   4540     // color on the selected range only. Note that this method is currently
   4541     // never called from the UI (see comment in changeColor:).
   4542     // FIXME: this actually has no effect when called, probably due to 3654850. _documentRange seems
   4543     // to do the right thing because it works in startSpeaking:, and I know setBackgroundColor: does the
   4544     // right thing because I tested it with [self _selectedRange].
   4545     // FIXME: This won't actually apply the style to the entire range here, because it ends up calling
   4546     // [frame _applyStyle:], which operates on the current selection. To make this work right, we'll
   4547     // need to save off the selection, temporarily set it to the entire range, make the change, then
   4548     // restore the old selection.
   4549     [self _changeCSSColorUsingSelector:@selector(setBackgroundColor:) inRange:[self _documentRange]];
   4550 }
   4551 
   4552 - (void)changeColor:(id)sender
   4553 {
   4554     COMMAND_PROLOGUE
   4555 
   4556     // FIXME: in NSTextView, this method calls changeDocumentBackgroundColor: when a
   4557     // private call has earlier been made by [NSFontFontEffectsBox changeColor:], see 3674493.
   4558     // AppKit will have to be revised to allow this to work with anything that isn't an
   4559     // NSTextView. However, this might not be required for Tiger, since the background-color
   4560     // changing box in the font panel doesn't work in Mail (3674481), though it does in TextEdit.
   4561     [self _applyStyleToSelection:[self _styleFromColorPanelWithSelector:@selector(setColor:)]
   4562                   withUndoAction:EditActionSetColor];
   4563 }
   4564 
   4565 - (void)_changeWordCaseWithSelector:(SEL)selector
   4566 {
   4567     if (![self _canEdit])
   4568         return;
   4569 
   4570     WebFrame *frame = [self _frame];
   4571     [self selectWord:nil];
   4572     NSString *word = [[frame _selectedString] performSelector:selector];
   4573     // FIXME: Does this need a different action context other than "typed"?
   4574     if ([self _shouldReplaceSelectionWithText:word givenAction:WebViewInsertActionTyped])
   4575         [frame _replaceSelectionWithText:word selectReplacement:NO smartReplace:NO];
   4576 }
   4577 
   4578 - (void)uppercaseWord:(id)sender
   4579 {
   4580     COMMAND_PROLOGUE
   4581 
   4582     [self _changeWordCaseWithSelector:@selector(uppercaseString)];
   4583 }
   4584 
   4585 - (void)lowercaseWord:(id)sender
   4586 {
   4587     COMMAND_PROLOGUE
   4588 
   4589     [self _changeWordCaseWithSelector:@selector(lowercaseString)];
   4590 }
   4591 
   4592 - (void)capitalizeWord:(id)sender
   4593 {
   4594     COMMAND_PROLOGUE
   4595 
   4596     [self _changeWordCaseWithSelector:@selector(capitalizedString)];
   4597 }
   4598 
   4599 - (void)complete:(id)sender
   4600 {
   4601     COMMAND_PROLOGUE
   4602 
   4603     if (![self _canEdit])
   4604         return;
   4605     if (!_private->completionController)
   4606         _private->completionController = [[WebTextCompletionController alloc] initWithWebView:[self _webView] HTMLView:self];
   4607     [_private->completionController doCompletion];
   4608 }
   4609 
   4610 - (void)checkSpelling:(id)sender
   4611 {
   4612     COMMAND_PROLOGUE
   4613 
   4614     if (Frame* coreFrame = core([self _frame]))
   4615         coreFrame->editor()->advanceToNextMisspelling();
   4616 }
   4617 
   4618 - (void)showGuessPanel:(id)sender
   4619 {
   4620     COMMAND_PROLOGUE
   4621 
   4622     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
   4623     if (!checker) {
   4624         LOG_ERROR("No NSSpellChecker");
   4625         return;
   4626     }
   4627 
   4628     NSPanel *spellingPanel = [checker spellingPanel];
   4629 #ifndef BUILDING_ON_TIGER
   4630     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
   4631     // to match rest of OS X.
   4632     if ([spellingPanel isVisible]) {
   4633         [spellingPanel orderOut:sender];
   4634         return;
   4635     }
   4636 #endif
   4637 
   4638     if (Frame* coreFrame = core([self _frame]))
   4639         coreFrame->editor()->advanceToNextMisspelling(true);
   4640     [spellingPanel orderFront:sender];
   4641 }
   4642 
   4643 - (void)_changeSpellingToWord:(NSString *)newWord
   4644 {
   4645     if (![self _canEdit])
   4646         return;
   4647 
   4648     // Don't correct to empty string.  (AppKit checked this, we might as well too.)
   4649     if (![NSSpellChecker sharedSpellChecker]) {
   4650         LOG_ERROR("No NSSpellChecker");
   4651         return;
   4652     }
   4653 
   4654     if ([newWord isEqualToString:@""])
   4655         return;
   4656 
   4657     if ([self _shouldReplaceSelectionWithText:newWord givenAction:WebViewInsertActionPasted])
   4658         [[self _frame] _replaceSelectionWithText:newWord selectReplacement:YES smartReplace:NO];
   4659 }
   4660 
   4661 - (void)changeSpelling:(id)sender
   4662 {
   4663     COMMAND_PROLOGUE
   4664 
   4665     [self _changeSpellingToWord:[[sender selectedCell] stringValue]];
   4666 }
   4667 
   4668 - (void)performFindPanelAction:(id)sender
   4669 {
   4670     COMMAND_PROLOGUE
   4671 
   4672     // Implementing this will probably require copying all of NSFindPanel.h and .m.
   4673     // We need *almost* the same thing as AppKit, but not quite.
   4674     LOG_ERROR("unimplemented");
   4675 }
   4676 
   4677 - (void)startSpeaking:(id)sender
   4678 {
   4679     COMMAND_PROLOGUE
   4680 
   4681     WebFrame *frame = [self _frame];
   4682     DOMRange *range = [self _selectedRange];
   4683     if (!range || [range collapsed])
   4684         range = [self _documentRange];
   4685     [NSApp speakString:[frame _stringForRange:range]];
   4686 }
   4687 
   4688 - (void)stopSpeaking:(id)sender
   4689 {
   4690     COMMAND_PROLOGUE
   4691 
   4692     [NSApp stopSpeaking:sender];
   4693 }
   4694 
   4695 - (void)toggleBaseWritingDirection:(id)sender
   4696 {
   4697     COMMAND_PROLOGUE
   4698 
   4699     if (![self _canEdit])
   4700         return;
   4701 
   4702     Frame* coreFrame = core([self _frame]);
   4703     if (!coreFrame)
   4704         return;
   4705 
   4706     WritingDirection direction = RightToLeftWritingDirection;
   4707     switch (coreFrame->baseWritingDirectionForSelectionStart()) {
   4708         case NSWritingDirectionLeftToRight:
   4709             break;
   4710         case NSWritingDirectionRightToLeft:
   4711             direction = LeftToRightWritingDirection;
   4712             break;
   4713         // The writingDirectionForSelectionStart method will never return "natural". It
   4714         // will always return a concrete direction. So, keep the compiler happy, and assert not reached.
   4715         case NSWritingDirectionNatural:
   4716             ASSERT_NOT_REACHED();
   4717             break;
   4718     }
   4719 
   4720     if (Frame* coreFrame = core([self _frame]))
   4721         coreFrame->editor()->setBaseWritingDirection(direction);
   4722 }
   4723 
   4724 - (void)changeBaseWritingDirection:(id)sender
   4725 {
   4726     COMMAND_PROLOGUE
   4727 
   4728     if (![self _canEdit])
   4729         return;
   4730 
   4731     NSWritingDirection writingDirection = static_cast<NSWritingDirection>([sender tag]);
   4732 
   4733     // We disable the menu item that performs this action because we can't implement
   4734     // NSWritingDirectionNatural's behavior using CSS.
   4735     ASSERT(writingDirection != NSWritingDirectionNatural);
   4736 
   4737     if (Frame* coreFrame = core([self _frame]))
   4738         coreFrame->editor()->setBaseWritingDirection(writingDirection == NSWritingDirectionLeftToRight ? LeftToRightWritingDirection : RightToLeftWritingDirection);
   4739 }
   4740 
   4741 static BOOL writingDirectionKeyBindingsEnabled()
   4742 {
   4743 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
   4744     return YES;
   4745 #else
   4746     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
   4747     return [defaults boolForKey:@"NSAllowsBaseWritingDirectionKeyBindings"] || [defaults boolForKey:@"AppleTextDirection"];
   4748 #endif
   4749 }
   4750 
   4751 - (void)_changeBaseWritingDirectionTo:(NSWritingDirection)direction
   4752 {
   4753     if (![self _canEdit])
   4754         return;
   4755 
   4756     static BOOL bindingsEnabled = writingDirectionKeyBindingsEnabled();
   4757 
   4758     if (!bindingsEnabled) {
   4759         NSBeep();
   4760         return;
   4761     }
   4762 
   4763     if (Frame* coreFrame = core([self _frame]))
   4764         coreFrame->editor()->setBaseWritingDirection(direction == NSWritingDirectionLeftToRight ? LeftToRightWritingDirection : RightToLeftWritingDirection);
   4765 }
   4766 
   4767 - (void)makeBaseWritingDirectionLeftToRight:(id)sender
   4768 {
   4769     COMMAND_PROLOGUE
   4770 
   4771     [self _changeBaseWritingDirectionTo:NSWritingDirectionLeftToRight];
   4772 }
   4773 
   4774 - (void)makeBaseWritingDirectionRightToLeft:(id)sender
   4775 {
   4776     COMMAND_PROLOGUE
   4777 
   4778     [self _changeBaseWritingDirectionTo:NSWritingDirectionRightToLeft];
   4779 }
   4780 
   4781 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
   4782 - (void)changeBaseWritingDirectionToLTR:(id)sender
   4783 {
   4784     [self makeBaseWritingDirectionLeftToRight:sender];
   4785 }
   4786 
   4787 - (void)changeBaseWritingDirectionToRTL:(id)sender
   4788 {
   4789     [self makeBaseWritingDirectionRightToLeft:sender];
   4790 }
   4791 #endif
   4792 
   4793 - (void)makeBaseWritingDirectionNatural:(id)sender
   4794 {
   4795     LOG_ERROR("Sent from %@.", sender);
   4796 }
   4797 
   4798 #if 0
   4799 
   4800 // CSS does not have a way to specify an outline font, which may make this difficult to implement.
   4801 // Maybe a special case of text-shadow?
   4802 - (void)outline:(id)sender;
   4803 
   4804 // This is part of table support, which may be in NSTextView for Tiger.
   4805 // It's probably simple to do the equivalent thing for WebKit.
   4806 - (void)insertTable:(id)sender;
   4807 
   4808 // This could be important.
   4809 - (void)toggleTraditionalCharacterShape:(id)sender;
   4810 
   4811 // I'm not sure what the equivalents of these in the web world are.
   4812 - (void)insertLineSeparator:(id)sender;
   4813 - (void)insertPageBreak:(id)sender;
   4814 
   4815 // These methods are not implemented in NSTextView yet at the time of this writing.
   4816 - (void)changeCaseOfLetter:(id)sender;
   4817 - (void)transposeWords:(id)sender;
   4818 
   4819 #endif
   4820 
   4821 #ifndef BUILDING_ON_TIGER
   4822 
   4823 // Override this so that AppKit will send us arrow keys as key down events so we can
   4824 // support them via the key bindings mechanism.
   4825 - (BOOL)_wantsKeyDownForEvent:(NSEvent *)event
   4826 {
   4827     bool haveWebCoreFrame = core([self _frame]);
   4828 
   4829     // If we have a frame, our keyDown method will handle key bindings after sending
   4830     // the event through the DOM, so ask AppKit not to do its early special key binding
   4831     // mapping. If we don't have a frame, just let things work the normal way without
   4832     // a keyDown.
   4833     return haveWebCoreFrame;
   4834 }
   4835 
   4836 #else
   4837 
   4838 // Super-hack alert.
   4839 // All this code accomplishes the same thing as the _wantsKeyDownForEvent method above.
   4840 
   4841 // Returns a selector only if called while:
   4842 //   1) first responder is self
   4843 //   2) handling a key down event
   4844 //   3) not yet inside keyDown: method
   4845 //   4) key is an arrow key
   4846 // The selector is the one that gets sent by -[NSWindow _processKeyboardUIKey] for this key.
   4847 - (SEL)_arrowKeyDownEventSelectorIfPreprocessing
   4848 {
   4849     NSWindow *w = [self window];
   4850     if ([w firstResponder] != self)
   4851         return NULL;
   4852     NSEvent *e = [w currentEvent];
   4853     if ([e type] != NSKeyDown)
   4854         return NULL;
   4855     if (e == _private->keyDownEvent)
   4856         return NULL;
   4857     NSString *s = [e charactersIgnoringModifiers];
   4858     if ([s length] == 0)
   4859         return NULL;
   4860     switch ([s characterAtIndex:0]) {
   4861         case NSDownArrowFunctionKey:
   4862             return @selector(moveDown:);
   4863         case NSLeftArrowFunctionKey:
   4864             return @selector(moveLeft:);
   4865         case NSRightArrowFunctionKey:
   4866             return @selector(moveRight:);
   4867         case NSUpArrowFunctionKey:
   4868             return @selector(moveUp:);
   4869         default:
   4870             return NULL;
   4871     }
   4872 }
   4873 
   4874 // Returns NO instead of YES if called on the selector that the
   4875 // _arrowKeyDownEventSelectorIfPreprocessing method returns.
   4876 // This should only happen inside -[NSWindow _processKeyboardUIKey],
   4877 // and together with the change below should cause that method
   4878 // to return NO rather than handling the key.
   4879 // Also set a 1-shot flag for the nextResponder check below.
   4880 - (BOOL)respondsToSelector:(SEL)selector
   4881 {
   4882     if (![super respondsToSelector:selector])
   4883         return NO;
   4884     SEL arrowKeySelector = [self _arrowKeyDownEventSelectorIfPreprocessing];
   4885     if (selector != arrowKeySelector)
   4886         return YES;
   4887     _private->nextResponderDisabledOnce = YES;
   4888     return NO;
   4889 }
   4890 
   4891 // Returns nil instead of the next responder if called when the
   4892 // one-shot flag is set, and _arrowKeyDownEventSelectorIfPreprocessing
   4893 // returns something other than NULL. This should only happen inside
   4894 // -[NSWindow _processKeyboardUIKey] and together with the change above
   4895 // should cause that method to return NO rather than handling the key.
   4896 - (NSResponder *)nextResponder
   4897 {
   4898     BOOL disabled = _private->nextResponderDisabledOnce;
   4899     _private->nextResponderDisabledOnce = NO;
   4900     if (disabled && [self _arrowKeyDownEventSelectorIfPreprocessing] != NULL)
   4901         return nil;
   4902     return [super nextResponder];
   4903 }
   4904 
   4905 #endif
   4906 
   4907 - (void)_updateControlTints
   4908 {
   4909     Frame* frame = core([self _frame]);
   4910     if (!frame)
   4911         return;
   4912     FrameView* view = frame->view();
   4913     if (!view)
   4914         return;
   4915     view->updateControlTints();
   4916 }
   4917 
   4918 // Despite its name, this is called at different times than windowDidBecomeKey is.
   4919 // It takes into account all the other factors that determine when NSCell draws
   4920 // with different tints, so it's the right call to use for control tints. We'd prefer
   4921 // to do this with API. <rdar://problem/5136760>
   4922 - (void)_windowChangedKeyState
   4923 {
   4924     if (pthread_main_np())
   4925         [self _updateControlTints];
   4926     else
   4927         [self performSelectorOnMainThread:@selector(_updateControlTints) withObject:nil waitUntilDone:NO];
   4928 
   4929     [super _windowChangedKeyState];
   4930 }
   4931 
   4932 - (void)otherMouseDown:(NSEvent *)event
   4933 {
   4934     if ([event buttonNumber] == 2)
   4935         [self mouseDown:event];
   4936     else
   4937         [super otherMouseDown:event];
   4938 }
   4939 
   4940 - (void)otherMouseDragged:(NSEvent *)event
   4941 {
   4942     if ([event buttonNumber] == 2)
   4943         [self mouseDragged:event];
   4944     else
   4945         [super otherMouseDragged:event];
   4946 }
   4947 
   4948 - (void)otherMouseUp:(NSEvent *)event
   4949 {
   4950     if ([event buttonNumber] == 2)
   4951         [self mouseUp:event];
   4952     else
   4953         [super otherMouseUp:event];
   4954 }
   4955 
   4956 @end
   4957 
   4958 @implementation NSArray (WebHTMLView)
   4959 
   4960 - (void)_web_makePluginViewsPerformSelector:(SEL)selector withObject:(id)object
   4961 {
   4962 #if ENABLE(NETSCAPE_PLUGIN_API)
   4963     NSEnumerator *enumerator = [self objectEnumerator];
   4964     WebNetscapePluginView *view;
   4965     while ((view = [enumerator nextObject]) != nil)
   4966         if ([view isKindOfClass:[WebBaseNetscapePluginView class]])
   4967             [view performSelector:selector withObject:object];
   4968 #endif
   4969 }
   4970 
   4971 @end
   4972 
   4973 @implementation WebHTMLView (WebInternal)
   4974 
   4975 - (void)_selectionChanged
   4976 {
   4977     [self _updateSelectionForInputManager];
   4978     [self _updateFontPanel];
   4979     if (Frame* coreFrame = core([self _frame]))
   4980         coreFrame->editor()->setStartNewKillRingSequence(true);
   4981 }
   4982 
   4983 - (void)_updateFontPanel
   4984 {
   4985     // FIXME: NSTextView bails out if becoming or resigning first responder, for which it has ivar flags. Not
   4986     // sure if we need to do something similar.
   4987 
   4988     if (![self _canEdit])
   4989         return;
   4990 
   4991     NSWindow *window = [self window];
   4992     // FIXME: is this first-responder check correct? What happens if a subframe is editable and is first responder?
   4993     if ([NSApp keyWindow] != window || [window firstResponder] != self)
   4994         return;
   4995 
   4996     bool multipleFonts = false;
   4997     NSFont *font = nil;
   4998     if (Frame* coreFrame = core([self _frame])) {
   4999         if (const SimpleFontData* fd = coreFrame->editor()->fontForSelection(multipleFonts))
   5000             font = fd->getNSFont();
   5001     }
   5002 
   5003 
   5004     // FIXME: for now, return a bogus font that distinguishes the empty selection from the non-empty
   5005     // selection. We should be able to remove this once the rest of this code works properly.
   5006     if (font == nil)
   5007         font = [self _hasSelection] ? [NSFont menuFontOfSize:23] : [NSFont toolTipsFontOfSize:17];
   5008     ASSERT(font != nil);
   5009 
   5010     [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:multipleFonts];
   5011 
   5012     // FIXME: we don't keep track of selected attributes, or set them on the font panel. This
   5013     // appears to have no effect on the UI. E.g., underlined text in Mail or TextEdit is
   5014     // not reflected in the font panel. Maybe someday this will change.
   5015 }
   5016 
   5017 - (BOOL)_canSmartCopyOrDelete
   5018 {
   5019     if (![[self _webView] smartInsertDeleteEnabled])
   5020         return NO;
   5021     Frame* coreFrame = core([self _frame]);
   5022     return coreFrame && coreFrame->selectionGranularity() == WordGranularity;
   5023 }
   5024 
   5025 - (NSEvent *)_mouseDownEvent
   5026 {
   5027     return _private->mouseDownEvent;
   5028 }
   5029 
   5030 - (id<WebHTMLHighlighter>)_highlighterForType:(NSString*)type
   5031 {
   5032     return [_private->highlighters objectForKey:type];
   5033 }
   5034 
   5035 - (WebFrame *)_frame
   5036 {
   5037     return [_private->dataSource webFrame];
   5038 }
   5039 
   5040 - (void)paste:(id)sender
   5041 {
   5042     COMMAND_PROLOGUE
   5043 
   5044     RetainPtr<WebHTMLView> selfProtector = self;
   5045     RefPtr<Frame> coreFrame = core([self _frame]);
   5046     if (!coreFrame)
   5047         return;
   5048     if (coreFrame->editor()->tryDHTMLPaste())
   5049         return; // DHTML did the whole operation
   5050     if (!coreFrame->editor()->canPaste())
   5051         return;
   5052     if (coreFrame->selection()->isContentRichlyEditable())
   5053         [self _pasteWithPasteboard:[NSPasteboard generalPasteboard] allowPlainText:YES];
   5054     else
   5055         coreFrame->editor()->pasteAsPlainText();
   5056 }
   5057 
   5058 - (void)pasteAsPlainText:(id)sender
   5059 {
   5060     COMMAND_PROLOGUE
   5061 
   5062     if (![self _canEdit])
   5063         return;
   5064     [self _pasteAsPlainTextWithPasteboard:[NSPasteboard generalPasteboard]];
   5065 }
   5066 
   5067 - (void)closeIfNotCurrentView
   5068 {
   5069     if ([[[self _frame] frameView] documentView] != self)
   5070         [self close];
   5071 }
   5072 
   5073 - (DOMDocumentFragment*)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
   5074 {
   5075     return [self _documentFragmentFromPasteboard:pasteboard inContext:nil allowPlainText:NO];
   5076 }
   5077 
   5078 #ifndef BUILDING_ON_TIGER
   5079 
   5080 - (BOOL)isGrammarCheckingEnabled
   5081 {
   5082     // FIXME 4799134: WebView is the bottleneck for this grammar-checking logic, but we must implement the method here because
   5083     // the AppKit code checks the first responder.
   5084     return [[self _webView] isGrammarCheckingEnabled];
   5085 }
   5086 
   5087 - (void)setGrammarCheckingEnabled:(BOOL)flag
   5088 {
   5089     // FIXME 4799134: WebView is the bottleneck for this grammar-checking logic, but we must implement the method here because
   5090     // the AppKit code checks the first responder.
   5091     [[self _webView] setGrammarCheckingEnabled:flag];
   5092 }
   5093 
   5094 - (void)toggleGrammarChecking:(id)sender
   5095 {
   5096     // FIXME 4799134: WebView is the bottleneck for this grammar-checking logic, but we must implement the method here because
   5097     // the AppKit code checks the first responder.
   5098     [[self _webView] toggleGrammarChecking:sender];
   5099 }
   5100 
   5101 
   5102 static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point)
   5103 {
   5104     NSArray *screens = [NSScreen screens];
   5105 
   5106     if ([screens count] == 0) {
   5107         // You could theoretically get here if running with no monitor, in which case it doesn't matter
   5108         // much where the "on-screen" point is.
   5109         return CGPointMake(point.x, point.y);
   5110     }
   5111 
   5112     // Flip the y coordinate from the top of the menu bar screen -- see 4636390
   5113     return CGPointMake(point.x, NSMaxY([[screens objectAtIndex:0] frame]) - point.y);
   5114 }
   5115 
   5116 #endif
   5117 
   5118 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
   5119 
   5120 - (void)orderFrontSubstitutionsPanel:(id)sender
   5121 {
   5122     COMMAND_PROLOGUE
   5123 
   5124     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
   5125     if (!checker) {
   5126         LOG_ERROR("No NSSpellChecker");
   5127         return;
   5128     }
   5129 
   5130     NSPanel *substitutionsPanel = [checker substitutionsPanel];
   5131     if ([substitutionsPanel isVisible]) {
   5132         [substitutionsPanel orderOut:sender];
   5133         return;
   5134     }
   5135     [substitutionsPanel orderFront:sender];
   5136 }
   5137 
   5138 // FIXME 4799134: WebView is the bottleneck for this logic, but we must implement these methods here because
   5139 // the AppKit code checks the first responder.
   5140 
   5141 - (BOOL)smartInsertDeleteEnabled
   5142 {
   5143     return [[self _webView] smartInsertDeleteEnabled];
   5144 }
   5145 
   5146 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
   5147 {
   5148     [[self _webView] setSmartInsertDeleteEnabled:flag];
   5149 }
   5150 
   5151 - (void)toggleSmartInsertDelete:(id)sender
   5152 {
   5153     [[self _webView] toggleSmartInsertDelete:sender];
   5154 }
   5155 
   5156 - (BOOL)isAutomaticQuoteSubstitutionEnabled
   5157 {
   5158     return [[self _webView] isAutomaticQuoteSubstitutionEnabled];
   5159 }
   5160 
   5161 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag
   5162 {
   5163     [[self _webView] setAutomaticQuoteSubstitutionEnabled:flag];
   5164 }
   5165 
   5166 - (void)toggleAutomaticQuoteSubstitution:(id)sender
   5167 {
   5168     [[self _webView] toggleAutomaticQuoteSubstitution:sender];
   5169 }
   5170 
   5171 - (BOOL)isAutomaticLinkDetectionEnabled
   5172 {
   5173     return [[self _webView] isAutomaticLinkDetectionEnabled];
   5174 }
   5175 
   5176 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag
   5177 {
   5178     [[self _webView] setAutomaticLinkDetectionEnabled:flag];
   5179 }
   5180 
   5181 - (void)toggleAutomaticLinkDetection:(id)sender
   5182 {
   5183     [[self _webView] toggleAutomaticLinkDetection:sender];
   5184 }
   5185 
   5186 - (BOOL)isAutomaticDashSubstitutionEnabled
   5187 {
   5188     return [[self _webView] isAutomaticDashSubstitutionEnabled];
   5189 }
   5190 
   5191 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag
   5192 {
   5193     [[self _webView] setAutomaticDashSubstitutionEnabled:flag];
   5194 }
   5195 
   5196 - (void)toggleAutomaticDashSubstitution:(id)sender
   5197 {
   5198     [[self _webView] toggleAutomaticDashSubstitution:sender];
   5199 }
   5200 
   5201 - (BOOL)isAutomaticTextReplacementEnabled
   5202 {
   5203     return [[self _webView] isAutomaticTextReplacementEnabled];
   5204 }
   5205 
   5206 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag
   5207 {
   5208     [[self _webView] setAutomaticTextReplacementEnabled:flag];
   5209 }
   5210 
   5211 - (void)toggleAutomaticTextReplacement:(id)sender
   5212 {
   5213     [[self _webView] toggleAutomaticTextReplacement:sender];
   5214 }
   5215 
   5216 - (BOOL)isAutomaticSpellingCorrectionEnabled
   5217 {
   5218     return [[self _webView] isAutomaticSpellingCorrectionEnabled];
   5219 }
   5220 
   5221 - (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag
   5222 {
   5223     [[self _webView] setAutomaticSpellingCorrectionEnabled:flag];
   5224 }
   5225 
   5226 - (void)toggleAutomaticSpellingCorrection:(id)sender
   5227 {
   5228     [[self _webView] toggleAutomaticSpellingCorrection:sender];
   5229 }
   5230 
   5231 #endif
   5232 
   5233 - (void)_lookUpInDictionaryFromMenu:(id)sender
   5234 {
   5235     // Dictionary API will accept a whitespace-only string and display UI as if it were real text,
   5236     // so bail out early to avoid that.
   5237     if ([[[self selectedString] _webkit_stringByTrimmingWhitespace] length] == 0)
   5238         return;
   5239 
   5240     NSAttributedString *attrString = [self selectedAttributedString];
   5241 
   5242     Frame* coreFrame = core([self _frame]);
   5243     if (!coreFrame)
   5244         return;
   5245 
   5246     NSRect rect = coreFrame->selectionBounds();
   5247 
   5248 #ifndef BUILDING_ON_TIGER
   5249     NSDictionary *attributes = [attrString fontAttributesInRange:NSMakeRange(0,1)];
   5250     NSFont *font = [attributes objectForKey:NSFontAttributeName];
   5251     if (font)
   5252         rect.origin.y += [font ascender];
   5253 #endif
   5254 
   5255 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
   5256     [self showDefinitionForAttributedString:attrString atPoint:rect.origin];
   5257     return;
   5258 #endif
   5259 
   5260     // We soft link to get the function that displays the dictionary (either pop-up window or app) to avoid the performance
   5261     // penalty of linking to another framework. This function changed signature as well as framework between Tiger and Leopard,
   5262     // so the two cases are handled separately.
   5263 
   5264 #ifdef BUILDING_ON_TIGER
   5265     typedef OSStatus (*ServiceWindowShowFunction)(id inWordString, NSRect inWordBoundary, UInt16 inLineDirection);
   5266     const char *frameworkPath = "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/LangAnalysis.framework/LangAnalysis";
   5267     const char *functionName = "DCMDictionaryServiceWindowShow";
   5268 #else
   5269     typedef void (*ServiceWindowShowFunction)(id unusedDictionaryRef, id inWordString, CFRange selectionRange, id unusedFont, CGPoint textOrigin, Boolean verticalText, id unusedTransform);
   5270     const char *frameworkPath = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
   5271     const char *functionName = "HIDictionaryWindowShow";
   5272 #endif
   5273 
   5274     static bool lookedForFunction = false;
   5275     static ServiceWindowShowFunction dictionaryServiceWindowShow = NULL;
   5276 
   5277     if (!lookedForFunction) {
   5278         void* langAnalysisFramework = dlopen(frameworkPath, RTLD_LAZY);
   5279         ASSERT(langAnalysisFramework);
   5280         if (langAnalysisFramework)
   5281             dictionaryServiceWindowShow = (ServiceWindowShowFunction)dlsym(langAnalysisFramework, functionName);
   5282         lookedForFunction = true;
   5283     }
   5284 
   5285     ASSERT(dictionaryServiceWindowShow);
   5286     if (!dictionaryServiceWindowShow) {
   5287         NSLog(@"Couldn't find the %s function in %s", functionName, frameworkPath);
   5288         return;
   5289     }
   5290 
   5291 #ifdef BUILDING_ON_TIGER
   5292     // FIXME: must check for right-to-left here
   5293     NSWritingDirection writingDirection = NSWritingDirectionLeftToRight;
   5294 
   5295     // FIXME: the dictionary API expects the rect for the first line of selection. Passing
   5296     // the rect for the entire selection, as we do here, positions the pop-up window near
   5297     // the bottom of the selection rather than at the selected word.
   5298     rect = [self convertRect:rect toView:nil];
   5299     rect.origin = [[self window] convertBaseToScreen:rect.origin];
   5300     NSData *data = [attrString RTFFromRange:NSMakeRange(0, [attrString length]) documentAttributes:nil];
   5301     dictionaryServiceWindowShow(data, rect, (writingDirection == NSWritingDirectionRightToLeft) ? 1 : 0);
   5302 #else
   5303     // The HIDictionaryWindowShow function requires the origin, in CG screen coordinates, of the first character of text in the selection.
   5304     // FIXME 4945808: We approximate this in a way that works well when a single word is selected, and less well in some other cases
   5305     // (but no worse than we did in Tiger)
   5306     NSPoint windowPoint = [self convertPoint:rect.origin toView:nil];
   5307     NSPoint screenPoint = [[self window] convertBaseToScreen:windowPoint];
   5308 
   5309     dictionaryServiceWindowShow(nil, attrString, CFRangeMake(0, [attrString length]), nil,
   5310                                 coreGraphicsScreenPointForAppKitScreenPoint(screenPoint), false, nil);
   5311 #endif
   5312 }
   5313 
   5314 - (void)_hoverFeedbackSuspendedChanged
   5315 {
   5316     [self _updateMouseoverWithFakeEvent];
   5317 }
   5318 
   5319 - (BOOL)_interceptEditingKeyEvent:(KeyboardEvent*)event shouldSaveCommand:(BOOL)shouldSave
   5320 {
   5321     // Ask AppKit to process the key event -- it will call back with either insertText or doCommandBySelector.
   5322     WebHTMLViewInterpretKeyEventsParameters parameters;
   5323     parameters.eventWasHandled = false;
   5324     parameters.shouldSaveCommand = shouldSave;
   5325     // If we're intercepting the initial IM call we assume that the IM has consumed the event,
   5326     // and only change this assumption if one of the NSTextInput/Responder callbacks is used.
   5327     // We assume the IM will *not* consume hotkey sequences
   5328     parameters.consumedByIM = !event->metaKey() && shouldSave;
   5329 
   5330     if (const PlatformKeyboardEvent* platformEvent = event->keyEvent()) {
   5331         NSEvent *macEvent = platformEvent->macEvent();
   5332         if ([macEvent type] == NSKeyDown && [_private->completionController filterKeyDown:macEvent])
   5333             return true;
   5334 
   5335         if ([macEvent type] == NSFlagsChanged)
   5336             return false;
   5337 
   5338         parameters.event = event;
   5339         _private->interpretKeyEventsParameters = &parameters;
   5340         _private->receivedNOOP = NO;
   5341         const Vector<KeypressCommand>& commands = event->keypressCommands();
   5342         bool hasKeypressCommand = !commands.isEmpty();
   5343 
   5344         // FIXME: interpretKeyEvents doesn't match application key equivalents (such as Cmd+A),
   5345         // and sends noop: for those. As a result, we don't handle those from within WebCore,
   5346         // but send a full sequence of DOM events, including an unneeded keypress.
   5347         if (parameters.shouldSaveCommand || !hasKeypressCommand)
   5348             [self interpretKeyEvents:[NSArray arrayWithObject:macEvent]];
   5349         else {
   5350             size_t size = commands.size();
   5351             // Are there commands that would just cause text insertion if executed via Editor?
   5352             // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
   5353             // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
   5354             // (e.g. Tab that inserts a Tab character, or Enter).
   5355             bool haveTextInsertionCommands = false;
   5356             for (size_t i = 0; i < size; ++i) {
   5357                 if ([self coreCommandBySelector:NSSelectorFromString(commands[i].commandName)].isTextInsertion())
   5358                     haveTextInsertionCommands = true;
   5359             }
   5360             if (!haveTextInsertionCommands || platformEvent->type() == PlatformKeyboardEvent::Char) {
   5361                 for (size_t i = 0; i < size; ++i) {
   5362                     if (commands[i].commandName == "insertText:")
   5363                         [self insertText:commands[i].text];
   5364                     else
   5365                         [self doCommandBySelector:NSSelectorFromString(commands[i].commandName)];
   5366                 }
   5367             }
   5368         }
   5369         _private->interpretKeyEventsParameters = 0;
   5370     }
   5371     return (!_private->receivedNOOP && parameters.eventWasHandled) || parameters.consumedByIM;
   5372 }
   5373 
   5374 - (WebCore::CachedImage*)promisedDragTIFFDataSource
   5375 {
   5376     return _private->promisedDragTIFFDataSource;
   5377 }
   5378 
   5379 - (void)setPromisedDragTIFFDataSource:(WebCore::CachedImage*)source
   5380 {
   5381     if (source)
   5382         source->addClient(promisedDataClient());
   5383 
   5384     if (_private->promisedDragTIFFDataSource)
   5385         _private->promisedDragTIFFDataSource->removeClient(promisedDataClient());
   5386     _private->promisedDragTIFFDataSource = source;
   5387 }
   5388 
   5389 #undef COMMAND_PROLOGUE
   5390 
   5391 - (void)_layoutIfNeeded
   5392 {
   5393     ASSERT(!_private->subviewsSetAside);
   5394 
   5395     if (_private->needsToApplyStyles || [self _needsLayout])
   5396         [self layout];
   5397 }
   5398 
   5399 - (void)_web_layoutIfNeededRecursive
   5400 {
   5401     [self _layoutIfNeeded];
   5402 
   5403 #ifndef NDEBUG
   5404     _private->enumeratingSubviews = YES;
   5405 #endif
   5406 
   5407     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
   5408 
   5409     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
   5410 
   5411     unsigned count = [descendantWebHTMLViews count];
   5412     for (unsigned i = 0; i < count; ++i)
   5413         [[descendantWebHTMLViews objectAtIndex:i] _layoutIfNeeded];
   5414 
   5415     [descendantWebHTMLViews release];
   5416 
   5417 #ifndef NDEBUG
   5418     _private->enumeratingSubviews = NO;
   5419 #endif
   5420 }
   5421 
   5422 - (void) _destroyAllWebPlugins
   5423 {
   5424     [[self _pluginController] destroyAllPlugins];
   5425 }
   5426 
   5427 - (BOOL)_needsLayout
   5428 {
   5429     return [[self _frame] _needsLayout];
   5430 }
   5431 
   5432 #if USE(ACCELERATED_COMPOSITING)
   5433 - (void)attachRootLayer:(CALayer*)layer
   5434 {
   5435     if (!_private->layerHostingView) {
   5436         NSView* hostingView = [[NSView alloc] initWithFrame:[self bounds]];
   5437 #if !defined(BUILDING_ON_LEOPARD)
   5438         [hostingView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
   5439 #endif
   5440         [self addSubview:hostingView];
   5441         [hostingView release];
   5442         // hostingView is owned by being a subview of self
   5443         _private->layerHostingView = hostingView;
   5444     }
   5445 
   5446     // Make a container layer, which will get sized/positioned by AppKit and CA.
   5447     CALayer* viewLayer = [CALayer layer];
   5448 
   5449 #if defined(BUILDING_ON_LEOPARD)
   5450     // Turn off default animations.
   5451     NSNull *nullValue = [NSNull null];
   5452     NSDictionary *actions = [NSDictionary dictionaryWithObjectsAndKeys:
   5453                              nullValue, @"anchorPoint",
   5454                              nullValue, @"bounds",
   5455                              nullValue, @"contents",
   5456                              nullValue, @"contentsRect",
   5457                              nullValue, @"opacity",
   5458                              nullValue, @"position",
   5459                              nullValue, @"sublayerTransform",
   5460                              nullValue, @"sublayers",
   5461                              nullValue, @"transform",
   5462                              nil];
   5463     [viewLayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]];
   5464 #endif
   5465 
   5466     [_private->layerHostingView setLayer:viewLayer];
   5467     [_private->layerHostingView setWantsLayer:YES];
   5468 
   5469     // Parent our root layer in the container layer
   5470     [viewLayer addSublayer:layer];
   5471 
   5472     if ([[self _webView] _postsAcceleratedCompositingNotifications])
   5473         [[NSNotificationCenter defaultCenter] postNotificationName:_WebViewDidStartAcceleratedCompositingNotification object:[self _webView] userInfo:nil];
   5474 
   5475 #if defined(BUILDING_ON_LEOPARD)
   5476     [self _updateLayerHostingViewPosition];
   5477 #endif
   5478 }
   5479 
   5480 - (void)detachRootLayer
   5481 {
   5482     if (_private->layerHostingView) {
   5483         [_private->layerHostingView setLayer:nil];
   5484         [_private->layerHostingView setWantsLayer:NO];
   5485         [_private->layerHostingView removeFromSuperview];
   5486         _private->layerHostingView = nil;
   5487     }
   5488 }
   5489 
   5490 #if defined(BUILDING_ON_LEOPARD)
   5491 // This method is necessary on Leopard to work around <rdar://problem/7067892>.
   5492 - (void)_updateLayerHostingViewPosition
   5493 {
   5494     if (!_private->layerHostingView)
   5495         return;
   5496 
   5497     const CGFloat maxHeight = 2048;
   5498     NSRect layerViewFrame = [self bounds];
   5499 
   5500     if (layerViewFrame.size.height > maxHeight) {
   5501         CGFloat documentHeight = layerViewFrame.size.height;
   5502 
   5503         // Clamp the size of the view to <= maxHeight to avoid the bug.
   5504         layerViewFrame.size.height = maxHeight;
   5505         NSRect visibleRect = [[self enclosingScrollView] documentVisibleRect];
   5506 
   5507         // Place the top of the layer-hosting view at the top of the visibleRect.
   5508         CGFloat topOffset = NSMinY(visibleRect);
   5509         layerViewFrame.origin.y = topOffset;
   5510 
   5511         // Compensate for the moved view by adjusting the sublayer transform on the view's layer (using flipped coords).
   5512         CGFloat bottomOffset = documentHeight - layerViewFrame.size.height - topOffset;
   5513         [[_private->layerHostingView layer] setSublayerTransform:CATransform3DMakeTranslation(0, -bottomOffset, 0)];
   5514     }
   5515 
   5516     [_private->layerHostingView _updateLayerGeometryFromView];  // Workaround for <rdar://problem/7071636>
   5517     [_private->layerHostingView setFrame:layerViewFrame];
   5518 }
   5519 #endif // defined(BUILDING_ON_LEOPARD)
   5520 #endif // USE(ACCELERATED_COMPOSITING)
   5521 
   5522 @end
   5523 
   5524 @implementation WebHTMLView (WebNSTextInputSupport)
   5525 
   5526 - (NSArray *)validAttributesForMarkedText
   5527 {
   5528     static NSArray *validAttributes;
   5529     if (!validAttributes) {
   5530         validAttributes = [[NSArray alloc] initWithObjects:
   5531             NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName,
   5532             NSMarkedClauseSegmentAttributeName, NSTextInputReplacementRangeAttributeName, nil];
   5533         // NSText also supports the following attributes, but it's
   5534         // hard to tell which are really required for text input to
   5535         // work well; I have not seen any input method make use of them yet.
   5536         //     NSFontAttributeName, NSForegroundColorAttributeName,
   5537         //     NSBackgroundColorAttributeName, NSLanguageAttributeName.
   5538         CFRetain(validAttributes);
   5539     }
   5540     LOG(TextInput, "validAttributesForMarkedText -> (...)");
   5541     return validAttributes;
   5542 }
   5543 
   5544 - (NSTextInputContext *)inputContext
   5545 {
   5546     return _private->exposeInputContext ? [super inputContext] : nil;
   5547 }
   5548 
   5549 - (NSAttributedString *)textStorage
   5550 {
   5551     if (!_private->exposeInputContext) {
   5552         LOG(TextInput, "textStorage -> nil");
   5553         return nil;
   5554     }
   5555     NSAttributedString *result = [self attributedSubstringFromRange:NSMakeRange(0, UINT_MAX)];
   5556 
   5557     LOG(TextInput, "textStorage -> \"%@\"", result ? [result string] : @"");
   5558 
   5559     // We have to return an empty string rather than null to prevent TSM from calling -string
   5560     return result ? result : [[[NSAttributedString alloc] initWithString:@""] autorelease];
   5561 }
   5562 
   5563 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
   5564 {
   5565     NSWindow *window = [self window];
   5566     WebFrame *frame = [self _frame];
   5567 
   5568     if (window)
   5569         thePoint = [window convertScreenToBase:thePoint];
   5570     thePoint = [self convertPoint:thePoint fromView:nil];
   5571 
   5572     DOMRange *range = [frame _characterRangeAtPoint:thePoint];
   5573     if (!range) {
   5574         LOG(TextInput, "characterIndexForPoint:(%f, %f) -> NSNotFound", thePoint.x, thePoint.y);
   5575         return NSNotFound;
   5576     }
   5577 
   5578     unsigned result = [frame _convertDOMRangeToNSRange:range].location;
   5579     LOG(TextInput, "characterIndexForPoint:(%f, %f) -> %u", thePoint.x, thePoint.y, result);
   5580     return result;
   5581 }
   5582 
   5583 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
   5584 {
   5585     WebFrame *frame = [self _frame];
   5586 
   5587     // Just to match NSTextView's behavior. Regression tests cannot detect this;
   5588     // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
   5589     // (type something; try ranges (1, -1) and (2, -1).
   5590     if ((theRange.location + theRange.length < theRange.location) && (theRange.location + theRange.length != 0))
   5591         theRange.length = 0;
   5592 
   5593     DOMRange *range = [frame _convertNSRangeToDOMRange:theRange];
   5594     if (!range) {
   5595         LOG(TextInput, "firstRectForCharacterRange:(%u, %u) -> (0, 0, 0, 0)", theRange.location, theRange.length);
   5596         return NSMakeRect(0, 0, 0, 0);
   5597     }
   5598 
   5599     ASSERT([range startContainer]);
   5600     ASSERT([range endContainer]);
   5601 
   5602     NSRect resultRect = [frame _firstRectForDOMRange:range];
   5603     resultRect = [self convertRect:resultRect toView:nil];
   5604 
   5605     NSWindow *window = [self window];
   5606     if (window)
   5607         resultRect.origin = [window convertBaseToScreen:resultRect.origin];
   5608 
   5609     LOG(TextInput, "firstRectForCharacterRange:(%u, %u) -> (%f, %f, %f, %f)", theRange.location, theRange.length, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
   5610     return resultRect;
   5611 }
   5612 
   5613 - (NSRange)selectedRange
   5614 {
   5615     if (!isTextInput(core([self _frame]))) {
   5616         LOG(TextInput, "selectedRange -> (NSNotFound, 0)");
   5617         return NSMakeRange(NSNotFound, 0);
   5618     }
   5619     NSRange result = [[self _frame] _selectedNSRange];
   5620 
   5621     LOG(TextInput, "selectedRange -> (%u, %u)", result.location, result.length);
   5622     return result;
   5623 }
   5624 
   5625 - (NSRange)markedRange
   5626 {
   5627     WebFrame *webFrame = [self _frame];
   5628     Frame* coreFrame = core(webFrame);
   5629     if (!coreFrame)
   5630         return NSMakeRange(0, 0);
   5631     NSRange result = [webFrame _convertToNSRange:coreFrame->editor()->compositionRange().get()];
   5632 
   5633     LOG(TextInput, "markedRange -> (%u, %u)", result.location, result.length);
   5634     return result;
   5635 }
   5636 
   5637 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)nsRange
   5638 {
   5639     WebFrame *frame = [self _frame];
   5640     Frame* coreFrame = core(frame);
   5641     if (!isTextInput(coreFrame) || isInPasswordField(coreFrame)) {
   5642         LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
   5643         return nil;
   5644     }
   5645     DOMRange *domRange = [frame _convertNSRangeToDOMRange:nsRange];
   5646     if (!domRange) {
   5647         LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
   5648         return nil;
   5649     }
   5650 
   5651     NSAttributedString *result = [NSAttributedString _web_attributedStringFromRange:core(domRange)];
   5652 
   5653     // [NSAttributedString(WebKitExtras) _web_attributedStringFromRange:]  insists on inserting a trailing
   5654     // whitespace at the end of the string which breaks the ATOK input method.  <rdar://problem/5400551>
   5655     // To work around this we truncate the resultant string to the correct length.
   5656     if ([result length] > nsRange.length) {
   5657         ASSERT([result length] == nsRange.length + 1);
   5658         ASSERT([[result string] characterAtIndex:nsRange.length] == '\n' || [[result string] characterAtIndex:nsRange.length] == ' ');
   5659         result = [result attributedSubstringFromRange:NSMakeRange(0, nsRange.length)];
   5660     }
   5661     LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%@\"", nsRange.location, nsRange.length, [result string]);
   5662     return result;
   5663 }
   5664 
   5665 // test for 10.4 because of <rdar://problem/4243463>
   5666 #ifdef BUILDING_ON_TIGER
   5667 - (long)conversationIdentifier
   5668 {
   5669     return (long)self;
   5670 }
   5671 #else
   5672 - (NSInteger)conversationIdentifier
   5673 {
   5674     return (NSInteger)self;
   5675 }
   5676 #endif
   5677 
   5678 - (BOOL)hasMarkedText
   5679 {
   5680     Frame* coreFrame = core([self _frame]);
   5681     BOOL result = coreFrame && coreFrame->editor()->hasComposition();
   5682     LOG(TextInput, "hasMarkedText -> %u", result);
   5683     return result;
   5684 }
   5685 
   5686 - (void)unmarkText
   5687 {
   5688     LOG(TextInput, "unmarkText");
   5689 
   5690     // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
   5691     WebHTMLViewInterpretKeyEventsParameters* parameters = _private->interpretKeyEventsParameters;
   5692     _private->interpretKeyEventsParameters = 0;
   5693 
   5694     if (parameters) {
   5695         parameters->eventWasHandled = YES;
   5696         parameters->consumedByIM = NO;
   5697     }
   5698 
   5699     if (Frame* coreFrame = core([self _frame]))
   5700         coreFrame->editor()->confirmComposition();
   5701 }
   5702 
   5703 static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnderline>& result)
   5704 {
   5705     int length = [[string string] length];
   5706 
   5707     int i = 0;
   5708     while (i < length) {
   5709         NSRange range;
   5710         NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&range inRange:NSMakeRange(i, length - i)];
   5711 
   5712         if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
   5713             Color color = Color::black;
   5714             if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName])
   5715                 color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
   5716             result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] > 1));
   5717         }
   5718 
   5719         i = range.location + range.length;
   5720     }
   5721 }
   5722 
   5723 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange
   5724 {
   5725     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
   5726 
   5727     LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelRange.location, newSelRange.length);
   5728 
   5729     // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
   5730     WebHTMLViewInterpretKeyEventsParameters* parameters = _private->interpretKeyEventsParameters;
   5731     _private->interpretKeyEventsParameters = 0;
   5732 
   5733     if (parameters) {
   5734         parameters->eventWasHandled = YES;
   5735         parameters->consumedByIM = NO;
   5736     }
   5737 
   5738     Frame* coreFrame = core([self _frame]);
   5739     if (!coreFrame)
   5740         return;
   5741 
   5742     if (![self _isEditable])
   5743         return;
   5744 
   5745     Vector<CompositionUnderline> underlines;
   5746     NSString *text = string;
   5747 
   5748     if (isAttributedString) {
   5749         unsigned markedTextLength = [(NSString *)string length];
   5750         NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, markedTextLength)];
   5751         LOG(TextInput, "    ReplacementRange: %@", rangeString);
   5752         // The AppKit adds a 'secret' property to the string that contains the replacement range.
   5753         // The replacement range is the range of the the text that should be replaced with the new string.
   5754         if (rangeString)
   5755             [[self _frame] _selectNSRange:NSRangeFromString(rangeString)];
   5756 
   5757         text = [string string];
   5758         extractUnderlines(string, underlines);
   5759     }
   5760 
   5761     coreFrame->editor()->setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange));
   5762 }
   5763 
   5764 - (void)doCommandBySelector:(SEL)selector
   5765 {
   5766     LOG(TextInput, "doCommandBySelector:\"%s\"", sel_getName(selector));
   5767 
   5768     // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
   5769     // The same call to interpretKeyEvents can do more than one command.
   5770     WebHTMLViewInterpretKeyEventsParameters* parameters = _private->interpretKeyEventsParameters;
   5771     if (parameters)
   5772         parameters->consumedByIM = NO;
   5773 
   5774     if (selector == @selector(noop:)) {
   5775         _private->receivedNOOP = YES;
   5776         return;
   5777     }
   5778 
   5779     KeyboardEvent* event = parameters ? parameters->event : 0;
   5780     bool shouldSaveCommand = parameters && parameters->shouldSaveCommand;
   5781 
   5782     if (event && shouldSaveCommand)
   5783         event->keypressCommands().append(KeypressCommand(NSStringFromSelector(selector)));
   5784     else {
   5785         // Make sure that only direct calls to doCommandBySelector: see the parameters by setting to 0.
   5786         _private->interpretKeyEventsParameters = 0;
   5787 
   5788         bool eventWasHandled;
   5789 
   5790         WebView *webView = [self _webView];
   5791         if ([[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector])
   5792             eventWasHandled = true;
   5793         else {
   5794             Editor::Command command = [self coreCommandBySelector:selector];
   5795             if (command.isSupported())
   5796                 eventWasHandled = command.execute(event);
   5797             else {
   5798                 // If WebKit does not support this command, we need to pass the selector to super.
   5799                 _private->selectorForDoCommandBySelector = selector;
   5800 
   5801                 // The sink does two things: 1) Tells us if the responder went unhandled, and
   5802                 // 2) prevents any NSBeep; we don't ever want to beep here.
   5803                 WebResponderChainSink *sink = [[WebResponderChainSink alloc] initWithResponderChain:self];
   5804                 [super doCommandBySelector:selector];
   5805                 eventWasHandled = ![sink receivedUnhandledCommand];
   5806                 [sink detach];
   5807                 [sink release];
   5808 
   5809                 _private->selectorForDoCommandBySelector = 0;
   5810             }
   5811         }
   5812 
   5813         if (parameters)
   5814             parameters->eventWasHandled = eventWasHandled;
   5815 
   5816         // Restore the parameters so that other calls to doCommandBySelector: see them,
   5817         // and other commands can participate in setting the "eventWasHandled" flag.
   5818         _private->interpretKeyEventsParameters = parameters;
   5819     }
   5820 }
   5821 
   5822 - (void)insertText:(id)string
   5823 {
   5824     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
   5825 
   5826     LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
   5827 
   5828     WebHTMLViewInterpretKeyEventsParameters* parameters = _private->interpretKeyEventsParameters;
   5829     _private->interpretKeyEventsParameters = 0;
   5830     if (parameters)
   5831         parameters->consumedByIM = NO;
   5832 
   5833     // We don't support inserting an attributed string but input methods don't appear to require this.
   5834     RefPtr<Frame> coreFrame = core([self _frame]);
   5835     NSString *text;
   5836     bool isFromInputMethod = coreFrame && coreFrame->editor()->hasComposition();
   5837     if (isAttributedString) {
   5838         text = [string string];
   5839         // We deal with the NSTextInputReplacementRangeAttributeName attribute from NSAttributedString here
   5840         // simply because it is used by at least one Input Method -- it corresonds to the kEventParamTextInputSendReplaceRange
   5841         // event in TSM.  This behaviour matches that of -[WebHTMLView setMarkedText:selectedRange:] when it receives an
   5842         // NSAttributedString
   5843         NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, [text length])];
   5844         LOG(TextInput, "    ReplacementRange: %@", rangeString);
   5845         if (rangeString) {
   5846             [[self _frame] _selectNSRange:NSRangeFromString(rangeString)];
   5847             isFromInputMethod = YES;
   5848         }
   5849     } else
   5850         text = string;
   5851 
   5852     bool eventHandled = false;
   5853     if ([text length]) {
   5854         KeyboardEvent* event = parameters ? parameters->event : 0;
   5855 
   5856         // insertText can be called from an input method or from normal key event processing
   5857         // If its from normal key event processing, we may need to save the action to perform it later.
   5858         // If its from an input method, then we should go ahead and insert the text now.
   5859         // We assume it's from the input method if we have marked text.
   5860         // FIXME: In theory, this could be wrong for some input methods, so we should try to find
   5861         // another way to determine if the call is from the input method
   5862         bool shouldSaveCommand = parameters && parameters->shouldSaveCommand;
   5863         if (event && shouldSaveCommand && !isFromInputMethod) {
   5864             event->keypressCommands().append(KeypressCommand("insertText:", text));
   5865             _private->interpretKeyEventsParameters = parameters;
   5866             return;
   5867         }
   5868 
   5869         String eventText = text;
   5870         eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
   5871         if (coreFrame && coreFrame->editor()->canEdit()) {
   5872             if (!coreFrame->editor()->hasComposition())
   5873                 eventHandled = coreFrame->editor()->insertText(eventText, event);
   5874             else {
   5875                 eventHandled = true;
   5876                 coreFrame->editor()->confirmComposition(eventText);
   5877             }
   5878         }
   5879     }
   5880 
   5881     if (!parameters)
   5882         return;
   5883 
   5884     if (isFromInputMethod) {
   5885         // Allow doCommandBySelector: to be called after insertText: by resetting interpretKeyEventsParameters
   5886         _private->interpretKeyEventsParameters = parameters;
   5887         parameters->consumedByIM = YES;
   5888         return;
   5889     }
   5890 
   5891     parameters->eventWasHandled = eventHandled;
   5892 }
   5893 
   5894 - (void)_updateSelectionForInputManager
   5895 {
   5896     Frame* coreFrame = core([self _frame]);
   5897     if (!coreFrame)
   5898         return;
   5899 
   5900     BOOL exposeInputContext = isTextInput(coreFrame) && !isInPasswordField(coreFrame);
   5901     if (exposeInputContext != _private->exposeInputContext) {
   5902         _private->exposeInputContext = exposeInputContext;
   5903         // Let AppKit cache a potentially changed input context.
   5904         // WebCore routinely sets the selection to None when editing, and IMs become unhappy when an input context suddenly turns nil, see bug 26009.
   5905         if (!coreFrame->selection()->isNone())
   5906             [NSApp updateWindows];
   5907     }
   5908 
   5909     if (!coreFrame->editor()->hasComposition())
   5910         return;
   5911 
   5912     if (coreFrame->editor()->ignoreCompositionSelectionChange())
   5913         return;
   5914 
   5915     unsigned start;
   5916     unsigned end;
   5917     if (coreFrame->editor()->getCompositionSelection(start, end))
   5918         [[NSInputManager currentInputManager] markedTextSelectionChanged:NSMakeRange(start, end - start) client:self];
   5919     else {
   5920         coreFrame->editor()->confirmCompositionWithoutDisturbingSelection();
   5921         [[NSInputManager currentInputManager] markedTextAbandoned:self];
   5922     }
   5923 }
   5924 
   5925 @end
   5926 
   5927 @implementation WebHTMLView (WebDocumentPrivateProtocols)
   5928 
   5929 - (NSRect)selectionRect
   5930 {
   5931     if ([self _hasSelection])
   5932         return core([self _frame])->selectionBounds();
   5933     return NSZeroRect;
   5934 }
   5935 
   5936 - (NSArray *)selectionTextRects
   5937 {
   5938     if (![self _hasSelection])
   5939         return nil;
   5940 
   5941     Vector<FloatRect> list;
   5942     if (Frame* coreFrame = core([self _frame]))
   5943         coreFrame->selectionTextRects(list, Frame::RespectTransforms);
   5944 
   5945     unsigned size = list.size();
   5946     NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease];
   5947     for (unsigned i = 0; i < size; ++i)
   5948         [result addObject:[NSValue valueWithRect:list[i]]];
   5949 
   5950     return result;
   5951 }
   5952 
   5953 - (NSView *)selectionView
   5954 {
   5955     return self;
   5956 }
   5957 
   5958 - (NSImage *)selectionImageForcingBlackText:(BOOL)forceBlackText
   5959 {
   5960     if ([self _hasSelection])
   5961         return core([self _frame])->selectionImage(forceBlackText);
   5962     return nil;
   5963 }
   5964 
   5965 - (NSRect)selectionImageRect
   5966 {
   5967     if ([self _hasSelection])
   5968         return core([self _frame])->selectionBounds();
   5969     return NSZeroRect;
   5970 }
   5971 
   5972 - (NSArray *)pasteboardTypesForSelection
   5973 {
   5974     if ([self _canSmartCopyOrDelete]) {
   5975         NSMutableArray *types = [[[[self class] _selectionPasteboardTypes] mutableCopy] autorelease];
   5976         [types addObject:WebSmartPastePboardType];
   5977         return types;
   5978     } else {
   5979         return [[self class] _selectionPasteboardTypes];
   5980     }
   5981 }
   5982 
   5983 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
   5984 {
   5985     [self _writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard cachedAttributedString:nil];
   5986 }
   5987 
   5988 - (void)selectAll
   5989 {
   5990     Frame* coreFrame = core([self _frame]);
   5991     if (coreFrame)
   5992         coreFrame->selection()->selectAll();
   5993 }
   5994 
   5995 - (void)deselectAll
   5996 {
   5997     Frame* coreFrame = core([self _frame]);
   5998     if (!coreFrame)
   5999         return;
   6000     coreFrame->selection()->clear();
   6001 }
   6002 
   6003 - (NSString *)string
   6004 {
   6005     return [[self _frame] _stringForRange:[self _documentRange]];
   6006 }
   6007 
   6008 - (NSAttributedString *)_attributeStringFromDOMRange:(DOMRange *)range
   6009 {
   6010     NSAttributedString *attributedString;
   6011 #if !LOG_DISABLED
   6012     double start = CFAbsoluteTimeGetCurrent();
   6013 #endif
   6014     attributedString = [[[NSAttributedString alloc] _initWithDOMRange:range] autorelease];
   6015 #if !LOG_DISABLED
   6016     double duration = CFAbsoluteTimeGetCurrent() - start;
   6017     LOG(Timing, "creating attributed string from selection took %f seconds.", duration);
   6018 #endif
   6019     return attributedString;
   6020 }
   6021 
   6022 - (NSAttributedString *)attributedString
   6023 {
   6024     DOMDocument *document = [[self _frame] DOMDocument];
   6025     NSAttributedString *attributedString = [self _attributeStringFromDOMRange:[document _documentRange]];
   6026     if (!attributedString) {
   6027         Document* coreDocument = core(document);
   6028         attributedString = [NSAttributedString _web_attributedStringFromRange:Range::create(coreDocument, coreDocument, 0, coreDocument, coreDocument->childNodeCount()).get()];
   6029     }
   6030     return attributedString;
   6031 }
   6032 
   6033 - (NSString *)selectedString
   6034 {
   6035     return [[self _frame] _selectedString];
   6036 }
   6037 
   6038 - (NSAttributedString *)selectedAttributedString
   6039 {
   6040     NSAttributedString *attributedString = [self _attributeStringFromDOMRange:[self _selectedRange]];
   6041     if (!attributedString) {
   6042         Frame* coreFrame = core([self _frame]);
   6043         if (coreFrame) {
   6044             RefPtr<Range> range = coreFrame->selection()->selection().toNormalizedRange();
   6045             attributedString = [NSAttributedString _web_attributedStringFromRange:range.get()];
   6046         }
   6047     }
   6048     return attributedString;
   6049 }
   6050 
   6051 - (BOOL)supportsTextEncoding
   6052 {
   6053     return YES;
   6054 }
   6055 
   6056 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
   6057 {
   6058     if (![string length])
   6059         return NO;
   6060     Frame* coreFrame = core([self _frame]);
   6061     return coreFrame && coreFrame->findString(string, forward, caseFlag, wrapFlag, startInSelection);
   6062 }
   6063 
   6064 @end
   6065 
   6066 @implementation WebHTMLView (WebDocumentInternalProtocols)
   6067 
   6068 - (NSDictionary *)elementAtPoint:(NSPoint)point
   6069 {
   6070     return [self elementAtPoint:point allowShadowContent:NO];
   6071 }
   6072 
   6073 - (NSDictionary *)elementAtPoint:(NSPoint)point allowShadowContent:(BOOL)allow
   6074 {
   6075     Frame* coreFrame = core([self _frame]);
   6076     if (!coreFrame)
   6077         return nil;
   6078     return [[[WebElementDictionary alloc] initWithHitTestResult:coreFrame->eventHandler()->hitTestResultAtPoint(IntPoint(point), allow)] autorelease];
   6079 }
   6080 
   6081 - (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag limit:(NSUInteger)limit
   6082 {
   6083     Frame* coreFrame = core([self _frame]);
   6084     if (!coreFrame)
   6085         return 0;
   6086     return coreFrame->markAllMatchesForText(string, caseFlag, limit);
   6087 }
   6088 
   6089 - (void)setMarkedTextMatchesAreHighlighted:(BOOL)newValue
   6090 {
   6091     Frame* coreFrame = core([self _frame]);
   6092     if (!coreFrame)
   6093         return;
   6094     coreFrame->setMarkedTextMatchesAreHighlighted(newValue);
   6095 }
   6096 
   6097 - (BOOL)markedTextMatchesAreHighlighted
   6098 {
   6099     Frame* coreFrame = core([self _frame]);
   6100     return coreFrame && coreFrame->markedTextMatchesAreHighlighted();
   6101 }
   6102 
   6103 - (void)unmarkAllTextMatches
   6104 {
   6105     Frame* coreFrame = core([self _frame]);
   6106     if (!coreFrame)
   6107         return;
   6108     Document* document = coreFrame->document();
   6109     if (!document)
   6110         return;
   6111     document->removeMarkers(DocumentMarker::TextMatch);
   6112 }
   6113 
   6114 - (NSArray *)rectsForTextMatches
   6115 {
   6116     Frame* coreFrame = core([self _frame]);
   6117     if (!coreFrame)
   6118         return [NSArray array];
   6119     Document* document = coreFrame->document();
   6120     if (!document)
   6121         return [NSArray array];
   6122 
   6123     Vector<IntRect> rects = document->renderedRectsForMarkers(DocumentMarker::TextMatch);
   6124     unsigned count = rects.size();
   6125     NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
   6126     for (unsigned index = 0; index < count; ++index)
   6127         [result addObject:[NSValue valueWithRect:rects[index]]];
   6128     return result;
   6129 }
   6130 
   6131 @end
   6132 
   6133 // This is used by AppKit and is included here so that WebDataProtocolScheme is only defined once.
   6134 @implementation NSURL (WebDataURL)
   6135 
   6136 + (NSURL *)_web_uniqueWebDataURL
   6137 {
   6138     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
   6139     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
   6140     CFRelease(UUIDRef);
   6141     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", WebDataProtocolScheme, UUIDString]];
   6142     CFRelease(UUIDString);
   6143     return URL;
   6144 }
   6145 
   6146 @end
   6147 
   6148 @implementation WebResponderChainSink
   6149 
   6150 - (id)initWithResponderChain:(NSResponder *)chain
   6151 {
   6152     self = [super init];
   6153     _lastResponderInChain = chain;
   6154     while (NSResponder *next = [_lastResponderInChain nextResponder])
   6155         _lastResponderInChain = next;
   6156     [_lastResponderInChain setNextResponder:self];
   6157     return self;
   6158 }
   6159 
   6160 - (void)detach
   6161 {
   6162     [_lastResponderInChain setNextResponder:nil];
   6163     _lastResponderInChain = nil;
   6164 }
   6165 
   6166 - (BOOL)receivedUnhandledCommand
   6167 {
   6168     return _receivedUnhandledCommand;
   6169 }
   6170 
   6171 - (void)noResponderFor:(SEL)selector
   6172 {
   6173     _receivedUnhandledCommand = YES;
   6174 }
   6175 
   6176 - (void)doCommandBySelector:(SEL)selector
   6177 {
   6178     _receivedUnhandledCommand = YES;
   6179 }
   6180 
   6181 - (BOOL)tryToPerform:(SEL)action with:(id)object
   6182 {
   6183     _receivedUnhandledCommand = YES;
   6184     return YES;
   6185 }
   6186 
   6187 @end
   6188