Home | History | Annotate | Download | only in WebView
      1 /*
      2  * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #import "WebFrameInternal.h"
     30 
     31 #import "DOMCSSStyleDeclarationInternal.h"
     32 #import "DOMDocumentFragmentInternal.h"
     33 #import "DOMDocumentInternal.h"
     34 #import "DOMElementInternal.h"
     35 #import "DOMHTMLElementInternal.h"
     36 #import "DOMNodeInternal.h"
     37 #import "DOMRangeInternal.h"
     38 #import "WebArchiveInternal.h"
     39 #import "WebChromeClient.h"
     40 #import "WebDataSourceInternal.h"
     41 #import "WebDocumentLoaderMac.h"
     42 #import "WebDynamicScrollBarsView.h"
     43 #import "WebFrameLoaderClient.h"
     44 #import "WebFrameViewInternal.h"
     45 #import "WebHTMLView.h"
     46 #import "WebHTMLViewInternal.h"
     47 #import "WebKitStatisticsPrivate.h"
     48 #import "WebKitVersionChecks.h"
     49 #import "WebNSObjectExtras.h"
     50 #import "WebNSURLExtras.h"
     51 #import "WebScriptDebugger.h"
     52 #import "WebScriptWorldInternal.h"
     53 #import "WebViewInternal.h"
     54 #import <JavaScriptCore/APICast.h>
     55 #import <WebCore/AXObjectCache.h>
     56 #import <WebCore/AccessibilityObject.h>
     57 #import <WebCore/AnimationController.h>
     58 #import <WebCore/CSSMutableStyleDeclaration.h>
     59 #import <WebCore/CachedResourceLoader.h>
     60 #import <WebCore/Chrome.h>
     61 #import <WebCore/ColorMac.h>
     62 #import <WebCore/DOMImplementation.h>
     63 #import <WebCore/DocumentFragment.h>
     64 #import <WebCore/DocumentLoader.h>
     65 #import <WebCore/DocumentMarkerController.h>
     66 #import <WebCore/EventHandler.h>
     67 #import <WebCore/EventNames.h>
     68 #import <WebCore/Frame.h>
     69 #import <WebCore/FrameLoader.h>
     70 #import <WebCore/FrameLoaderStateMachine.h>
     71 #import <WebCore/FrameTree.h>
     72 #import <WebCore/GraphicsContext.h>
     73 #import <WebCore/HTMLFrameOwnerElement.h>
     74 #import <WebCore/HistoryItem.h>
     75 #import <WebCore/HitTestResult.h>
     76 #import <WebCore/LegacyWebArchive.h>
     77 #import <WebCore/Page.h>
     78 #import <WebCore/PluginData.h>
     79 #import <WebCore/PrintContext.h>
     80 #import <WebCore/RenderLayer.h>
     81 #import <WebCore/RenderPart.h>
     82 #import <WebCore/RenderView.h>
     83 #import <WebCore/ReplaceSelectionCommand.h>
     84 #import <WebCore/RuntimeApplicationChecks.h>
     85 #import <WebCore/ScriptValue.h>
     86 #import <WebCore/SmartReplace.h>
     87 #import <WebCore/SVGDocumentExtensions.h>
     88 #import <WebCore/SVGSMILElement.h>
     89 #import <WebCore/TextIterator.h>
     90 #import <WebCore/ThreadCheck.h>
     91 #import <WebCore/TypingCommand.h>
     92 #import <WebCore/htmlediting.h>
     93 #import <WebCore/markup.h>
     94 #import <WebCore/visible_units.h>
     95 #import <WebKitSystemInterface.h>
     96 #import <runtime/JSLock.h>
     97 #import <runtime/JSObject.h>
     98 #import <runtime/JSValue.h>
     99 #import <wtf/CurrentTime.h>
    100 
    101 using namespace std;
    102 using namespace WebCore;
    103 using namespace HTMLNames;
    104 
    105 using JSC::JSGlobalObject;
    106 using JSC::JSLock;
    107 using JSC::JSValue;
    108 using JSC::SilenceAssertionsOnly;
    109 
    110 /*
    111 Here is the current behavior matrix for four types of navigations:
    112 
    113 Standard Nav:
    114 
    115  Restore form state:   YES
    116  Restore scroll and focus state:  YES
    117  Cache policy: NSURLRequestUseProtocolCachePolicy
    118  Add to back/forward list: YES
    119 
    120 Back/Forward:
    121 
    122  Restore form state:   YES
    123  Restore scroll and focus state:  YES
    124  Cache policy: NSURLRequestReturnCacheDataElseLoad
    125  Add to back/forward list: NO
    126 
    127 Reload (meaning only the reload button):
    128 
    129  Restore form state:   NO
    130  Restore scroll and focus state:  YES
    131  Cache policy: NSURLRequestReloadIgnoringCacheData
    132  Add to back/forward list: NO
    133 
    134 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
    135 
    136  Restore form state:   NO
    137  Restore scroll and focus state:  NO, reset to initial conditions
    138  Cache policy: NSURLRequestReloadIgnoringCacheData
    139  Add to back/forward list: NO
    140 */
    141 
    142 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
    143 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
    144 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
    145 
    146 NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey";
    147 NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey";
    148 NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey";
    149 NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey";
    150 NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey";
    151 NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey";
    152 NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey";
    153 
    154 // FIXME: Remove when this key becomes publicly defined
    155 NSString *NSAccessibilityEnhancedUserInterfaceAttribute = @"AXEnhancedUserInterface";
    156 
    157 @implementation WebFramePrivate
    158 
    159 - (void)dealloc
    160 {
    161     [webFrameView release];
    162 
    163     delete scriptDebugger;
    164 
    165     [super dealloc];
    166 }
    167 
    168 - (void)finalize
    169 {
    170     delete scriptDebugger;
    171 
    172     [super finalize];
    173 }
    174 
    175 - (void)setWebFrameView:(WebFrameView *)v
    176 {
    177     [v retain];
    178     [webFrameView release];
    179     webFrameView = v;
    180 }
    181 
    182 @end
    183 
    184 EditableLinkBehavior core(WebKitEditableLinkBehavior editableLinkBehavior)
    185 {
    186     switch (editableLinkBehavior) {
    187         case WebKitEditableLinkDefaultBehavior:
    188             return EditableLinkDefaultBehavior;
    189         case WebKitEditableLinkAlwaysLive:
    190             return EditableLinkAlwaysLive;
    191         case WebKitEditableLinkOnlyLiveWithShiftKey:
    192             return EditableLinkOnlyLiveWithShiftKey;
    193         case WebKitEditableLinkLiveWhenNotFocused:
    194             return EditableLinkLiveWhenNotFocused;
    195         case WebKitEditableLinkNeverLive:
    196             return EditableLinkNeverLive;
    197     }
    198     ASSERT_NOT_REACHED();
    199     return EditableLinkDefaultBehavior;
    200 }
    201 
    202 WebCore::EditingBehaviorType core(WebKitEditingBehavior behavior)
    203 {
    204     switch (behavior) {
    205         case WebKitEditingMacBehavior:
    206             return WebCore::EditingMacBehavior;
    207         case WebKitEditingWinBehavior:
    208             return WebCore::EditingWindowsBehavior;
    209         case WebKitEditingUnixBehavior:
    210             return WebCore::EditingUnixBehavior;
    211     }
    212     ASSERT_NOT_REACHED();
    213     return WebCore::EditingMacBehavior;
    214 }
    215 
    216 TextDirectionSubmenuInclusionBehavior core(WebTextDirectionSubmenuInclusionBehavior behavior)
    217 {
    218     switch (behavior) {
    219         case WebTextDirectionSubmenuNeverIncluded:
    220             return TextDirectionSubmenuNeverIncluded;
    221         case WebTextDirectionSubmenuAutomaticallyIncluded:
    222             return TextDirectionSubmenuAutomaticallyIncluded;
    223         case WebTextDirectionSubmenuAlwaysIncluded:
    224             return TextDirectionSubmenuAlwaysIncluded;
    225     }
    226     ASSERT_NOT_REACHED();
    227     return TextDirectionSubmenuNeverIncluded;
    228 }
    229 
    230 @implementation WebFrame (WebInternal)
    231 
    232 Frame* core(WebFrame *frame)
    233 {
    234     return frame ? frame->_private->coreFrame : 0;
    235 }
    236 
    237 WebFrame *kit(Frame* frame)
    238 {
    239     return frame ? static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame() : nil;
    240 }
    241 
    242 Page* core(WebView *webView)
    243 {
    244     return [webView page];
    245 }
    246 
    247 WebView *kit(Page* page)
    248 {
    249     return page ? static_cast<WebView*>(page->chrome()->client()->webView()) : nil;
    250 }
    251 
    252 WebView *getWebView(WebFrame *webFrame)
    253 {
    254     Frame* coreFrame = core(webFrame);
    255     if (!coreFrame)
    256         return nil;
    257     return kit(coreFrame->page());
    258 }
    259 
    260 + (PassRefPtr<Frame>)_createFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
    261 {
    262     WebView *webView = kit(page);
    263 
    264     WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
    265     RefPtr<Frame> coreFrame = Frame::create(page, ownerElement, new WebFrameLoaderClient(frame));
    266     [frame release];
    267     frame->_private->coreFrame = coreFrame.get();
    268 
    269     coreFrame->tree()->setName(name);
    270     if (ownerElement) {
    271         ASSERT(ownerElement->document()->frame());
    272         ownerElement->document()->frame()->tree()->appendChild(coreFrame.get());
    273     }
    274 
    275     coreFrame->init();
    276 
    277     [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
    278 
    279     return coreFrame.release();
    280 }
    281 
    282 + (void)_createMainFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView
    283 {
    284     [self _createFrameWithPage:page frameName:name frameView:frameView ownerElement:0];
    285 }
    286 
    287 + (PassRefPtr<WebCore::Frame>)_createSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(const String&)name frameView:(WebFrameView *)frameView
    288 {
    289     return [self _createFrameWithPage:ownerElement->document()->frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
    290 }
    291 
    292 - (BOOL)_isIncludedInWebKitStatistics
    293 {
    294     return _private && _private->includedInWebKitStatistics;
    295 }
    296 
    297 - (void)_attachScriptDebugger
    298 {
    299     ScriptController* scriptController = _private->coreFrame->script();
    300 
    301     // Calling ScriptController::globalObject() would create a window shell, and dispatch corresponding callbacks, which may be premature
    302     // if the script debugger is attached before a document is created.  These calls use the debuggerWorld(), we will need to pass a world
    303     // to be able to debug isolated worlds.
    304     if (!scriptController->existingWindowShell(debuggerWorld()))
    305         return;
    306 
    307     JSGlobalObject* globalObject = scriptController->globalObject(debuggerWorld());
    308     if (!globalObject)
    309         return;
    310 
    311     if (_private->scriptDebugger) {
    312         ASSERT(_private->scriptDebugger == globalObject->debugger());
    313         return;
    314     }
    315 
    316     _private->scriptDebugger = new WebScriptDebugger(globalObject);
    317 }
    318 
    319 - (void)_detachScriptDebugger
    320 {
    321     if (!_private->scriptDebugger)
    322         return;
    323 
    324     delete _private->scriptDebugger;
    325     _private->scriptDebugger = 0;
    326 }
    327 
    328 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v
    329 {
    330     self = [super init];
    331     if (!self)
    332         return nil;
    333 
    334     _private = [[WebFramePrivate alloc] init];
    335 
    336     // Set includedInWebKitStatistics before calling WebFrameView _setWebFrame, since
    337     // it calls WebFrame _isIncludedInWebKitStatistics.
    338     if ((_private->includedInWebKitStatistics = [[v class] shouldIncludeInWebKitStatistics]))
    339         ++WebFrameCount;
    340 
    341     if (fv) {
    342         [_private setWebFrameView:fv];
    343         [fv _setWebFrame:self];
    344     }
    345 
    346     _private->shouldCreateRenderers = YES;
    347 
    348     return self;
    349 }
    350 
    351 - (void)_clearCoreFrame
    352 {
    353     _private->coreFrame = 0;
    354 }
    355 
    356 - (void)_updateBackgroundAndUpdatesWhileOffscreen
    357 {
    358     WebView *webView = getWebView(self);
    359     BOOL drawsBackground = [webView drawsBackground];
    360     NSColor *backgroundColor = [webView backgroundColor];
    361 
    362     Frame* coreFrame = _private->coreFrame;
    363     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
    364         if ([webView _usesDocumentViews]) {
    365             // Don't call setDrawsBackground:YES here because it may be NO because of a load
    366             // in progress; WebFrameLoaderClient keeps it set to NO during the load process.
    367             WebFrame *webFrame = kit(frame);
    368             if (!drawsBackground)
    369                 [[[webFrame frameView] _scrollView] setDrawsBackground:NO];
    370             [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor];
    371             id documentView = [[webFrame frameView] documentView];
    372             if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
    373                 [documentView setDrawsBackground:drawsBackground];
    374             if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
    375                 [documentView setBackgroundColor:backgroundColor];
    376         }
    377 
    378         if (FrameView* view = frame->view()) {
    379             view->setTransparent(!drawsBackground);
    380             view->setBaseBackgroundColor(colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
    381             view->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]);
    382         }
    383     }
    384 }
    385 
    386 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
    387 {
    388     _private->internalLoadDelegate = internalLoadDelegate;
    389 }
    390 
    391 - (id)_internalLoadDelegate
    392 {
    393     return _private->internalLoadDelegate;
    394 }
    395 
    396 #ifndef BUILDING_ON_TIGER
    397 - (void)_unmarkAllBadGrammar
    398 {
    399     Frame* coreFrame = _private->coreFrame;
    400     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
    401         if (Document* document = frame->document())
    402             document->markers()->removeMarkers(DocumentMarker::Grammar);
    403     }
    404 }
    405 #endif
    406 
    407 - (void)_unmarkAllMisspellings
    408 {
    409     Frame* coreFrame = _private->coreFrame;
    410     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
    411         if (Document* document = frame->document())
    412             document->markers()->removeMarkers(DocumentMarker::Spelling);
    413     }
    414 }
    415 
    416 - (BOOL)_hasSelection
    417 {
    418     if ([getWebView(self) _usesDocumentViews]) {
    419         id documentView = [_private->webFrameView documentView];
    420 
    421         // optimization for common case to avoid creating potentially large selection string
    422         if ([documentView isKindOfClass:[WebHTMLView class]])
    423             if (Frame* coreFrame = _private->coreFrame)
    424                 return coreFrame->selection()->isRange();
    425 
    426         if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
    427             return [[documentView selectedString] length] > 0;
    428 
    429         return NO;
    430     }
    431 
    432     Frame* coreFrame = _private->coreFrame;
    433     return coreFrame && coreFrame->selection()->isRange();
    434 }
    435 
    436 - (void)_clearSelection
    437 {
    438     ASSERT([getWebView(self) _usesDocumentViews]);
    439     id documentView = [_private->webFrameView documentView];
    440     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
    441         [documentView deselectAll];
    442 }
    443 
    444 #if !ASSERT_DISABLED
    445 - (BOOL)_atMostOneFrameHasSelection
    446 {
    447     // FIXME: 4186050 is one known case that makes this debug check fail.
    448     BOOL found = NO;
    449     Frame* coreFrame = _private->coreFrame;
    450     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
    451         if ([kit(frame) _hasSelection]) {
    452             if (found)
    453                 return NO;
    454             found = YES;
    455         }
    456     return YES;
    457 }
    458 #endif
    459 
    460 - (WebFrame *)_findFrameWithSelection
    461 {
    462     Frame* coreFrame = _private->coreFrame;
    463     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
    464         WebFrame *webFrame = kit(frame);
    465         if ([webFrame _hasSelection])
    466             return webFrame;
    467     }
    468     return nil;
    469 }
    470 
    471 - (void)_clearSelectionInOtherFrames
    472 {
    473     // We rely on WebDocumentSelection protocol implementors to call this method when they become first
    474     // responder. It would be nicer to just notice first responder changes here instead, but there's no
    475     // notification sent when the first responder changes in general (Radar 2573089).
    476     WebFrame *frameWithSelection = [[getWebView(self) mainFrame] _findFrameWithSelection];
    477     if (frameWithSelection != self)
    478         [frameWithSelection _clearSelection];
    479 
    480     // While we're in the general area of selection and frames, check that there is only one now.
    481     ASSERT([[getWebView(self) mainFrame] _atMostOneFrameHasSelection]);
    482 }
    483 
    484 static inline WebDataSource *dataSource(DocumentLoader* loader)
    485 {
    486     return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
    487 }
    488 
    489 - (WebDataSource *)_dataSource
    490 {
    491     return dataSource(_private->coreFrame->loader()->documentLoader());
    492 }
    493 
    494 - (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString
    495 {
    496     return _private->coreFrame->documentTypeString() + markupString;
    497 }
    498 
    499 - (NSArray *)_nodesFromList:(Vector<Node*> *)nodesVector
    500 {
    501     size_t size = nodesVector->size();
    502     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
    503     for (size_t i = 0; i < size; ++i)
    504         [nodes addObject:kit((*nodesVector)[i])];
    505     return nodes;
    506 }
    507 
    508 - (NSString *)_markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
    509 {
    510     // FIXME: This is always "for interchange". Is that right? See the previous method.
    511     Vector<Node*> nodeList;
    512     NSString *markupString = createMarkup(core(range), nodes ? &nodeList : 0, AnnotateForInterchange);
    513     if (nodes)
    514         *nodes = [self _nodesFromList:&nodeList];
    515 
    516     return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
    517 }
    518 
    519 - (NSString *)_selectedString
    520 {
    521     return _private->coreFrame->displayStringModifiedByEncoding(_private->coreFrame->editor()->selectedText());
    522 }
    523 
    524 - (NSString *)_stringForRange:(DOMRange *)range
    525 {
    526     // This will give a system malloc'd buffer that can be turned directly into an NSString
    527     unsigned length;
    528     UChar* buf = plainTextToMallocAllocatedBuffer(core(range), length, true);
    529 
    530     if (!buf)
    531         return [NSString string];
    532 
    533     // Transfer buffer ownership to NSString
    534     return [[[NSString alloc] initWithCharactersNoCopy:buf length:length freeWhenDone:YES] autorelease];
    535 }
    536 
    537 - (BOOL)_shouldFlattenCompositingLayers:(CGContextRef)context
    538 {
    539     // -currentContextDrawingToScreen returns YES for bitmap contexts.
    540     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
    541     if (isPrinting)
    542         return YES;
    543 
    544     if (!WKCGContextIsBitmapContext(context))
    545         return NO;
    546 
    547     // If we're drawing into a bitmap, we might be snapshotting, or drawing into a layer-backed view.
    548     if ([getWebView(self) _usesDocumentViews]) {
    549         id documentView = [_private->webFrameView documentView];
    550         if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _web_isDrawingIntoLayer])
    551             return NO;
    552     }
    553 
    554     return [getWebView(self) _includesFlattenedCompositingLayersWhenDrawingToBitmap];
    555 }
    556 
    557 - (void)_drawRect:(NSRect)rect contentsOnly:(BOOL)contentsOnly
    558 {
    559     ASSERT([[NSGraphicsContext currentContext] isFlipped]);
    560 
    561     CGContextRef ctx = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
    562     GraphicsContext context(ctx);
    563 
    564     FrameView* view = _private->coreFrame->view();
    565 
    566     bool shouldFlatten = false;
    567     if (Frame* parentFrame = _private->coreFrame->tree()->parent()) {
    568         // For subframes, we need to inherit the paint behavior from our parent
    569         FrameView* parentView = parentFrame ? parentFrame->view() : 0;
    570         if (parentView)
    571             shouldFlatten = parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
    572     } else
    573         shouldFlatten = [self _shouldFlattenCompositingLayers:ctx];
    574 
    575     PaintBehavior oldBehavior = PaintBehaviorNormal;
    576     if (shouldFlatten) {
    577         oldBehavior = view->paintBehavior();
    578         view->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
    579     }
    580 
    581     if (contentsOnly)
    582         view->paintContents(&context, enclosingIntRect(rect));
    583     else
    584         view->paint(&context, enclosingIntRect(rect));
    585 
    586     if (shouldFlatten)
    587         view->setPaintBehavior(oldBehavior);
    588 }
    589 
    590 - (BOOL)_getVisibleRect:(NSRect*)rect
    591 {
    592     ASSERT_ARG(rect, rect);
    593     if (RenderPart* ownerRenderer = _private->coreFrame->ownerRenderer()) {
    594         if (ownerRenderer->needsLayout())
    595             return NO;
    596         *rect = ownerRenderer->absoluteClippedOverflowRect();
    597         return YES;
    598     }
    599 
    600     return NO;
    601 }
    602 
    603 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string
    604 {
    605     return [self _stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
    606 }
    607 
    608 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
    609 {
    610     ASSERT(_private->coreFrame->document());
    611 
    612     JSValue result = _private->coreFrame->script()->executeScript(string, forceUserGesture).jsValue();
    613 
    614     if (!_private->coreFrame) // In case the script removed our frame from the page.
    615         return @"";
    616 
    617     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
    618     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or
    619     // JSEvaluateScript instead, since they have less surprising semantics.
    620     if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
    621         return @"";
    622 
    623     JSLock lock(SilenceAssertionsOnly);
    624     return ustringToString(result.toString(_private->coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()));
    625 }
    626 
    627 - (NSRect)_caretRectAtPosition:(const Position&)pos affinity:(NSSelectionAffinity)affinity
    628 {
    629     VisiblePosition visiblePosition(pos, static_cast<EAffinity>(affinity));
    630     return visiblePosition.absoluteCaretBounds();
    631 }
    632 
    633 - (NSRect)_firstRectForDOMRange:(DOMRange *)range
    634 {
    635    return _private->coreFrame->editor()->firstRectForRange(core(range));
    636 }
    637 
    638 - (void)_scrollDOMRangeToVisible:(DOMRange *)range
    639 {
    640     NSRect rangeRect = [self _firstRectForDOMRange:range];
    641     Node *startNode = core([range startContainer]);
    642 
    643     if (startNode && startNode->renderer()) {
    644         RenderLayer *layer = startNode->renderer()->enclosingLayer();
    645         if (layer)
    646             layer->scrollRectToVisible(enclosingIntRect(rangeRect), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
    647     }
    648 }
    649 
    650 - (BOOL)_needsLayout
    651 {
    652     return _private->coreFrame->view() ? _private->coreFrame->view()->needsLayout() : false;
    653 }
    654 
    655 - (DOMRange *)_rangeByAlteringCurrentSelection:(SelectionController::EAlteration)alteration direction:(SelectionDirection)direction granularity:(TextGranularity)granularity
    656 {
    657     if (_private->coreFrame->selection()->isNone())
    658         return nil;
    659 
    660     SelectionController selection;
    661     selection.setSelection(_private->coreFrame->selection()->selection());
    662     selection.modify(alteration, direction, granularity);
    663     return kit(selection.toNormalizedRange().get());
    664 }
    665 
    666 - (TextGranularity)_selectionGranularity
    667 {
    668     return _private->coreFrame->selection()->granularity();
    669 }
    670 
    671 - (NSRange)_convertToNSRange:(Range *)range
    672 {
    673     if (!range)
    674         return NSMakeRange(NSNotFound, 0);
    675 
    676     size_t location;
    677     size_t length;
    678     if (!TextIterator::locationAndLengthFromRange(range, location, length))
    679         return NSMakeRange(NSNotFound, 0);
    680 
    681     return NSMakeRange(location, length);
    682 }
    683 
    684 - (PassRefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
    685 {
    686     if (nsrange.location > INT_MAX)
    687         return 0;
    688     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
    689         nsrange.length = INT_MAX - nsrange.location;
    690 
    691     // our critical assumption is that we are only called by input methods that
    692     // concentrate on a given area containing the selection
    693     // We have to do this because of text fields and textareas. The DOM for those is not
    694     // directly in the document DOM, so serialization is problematic. Our solution is
    695     // to use the root editable element of the selection start as the positional base.
    696     // That fits with AppKit's idea of an input context.
    697     Element* selectionRoot = _private->coreFrame->selection()->rootEditableElement();
    698     Element* scope = selectionRoot ? selectionRoot : _private->coreFrame->document()->documentElement();
    699     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
    700 }
    701 
    702 - (DOMRange *)convertNSRangeToDOMRange:(NSRange)nsrange
    703 {
    704     // This method exists to maintain compatibility with Leopard's Dictionary.app. <rdar://problem/6002160>
    705     return [self _convertNSRangeToDOMRange:nsrange];
    706 }
    707 
    708 - (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange
    709 {
    710     return kit([self _convertToDOMRange:nsrange].get());
    711 }
    712 
    713 - (NSRange)convertDOMRangeToNSRange:(DOMRange *)range
    714 {
    715     // This method exists to maintain compatibility with Leopard's Dictionary.app. <rdar://problem/6002160>
    716     return [self _convertDOMRangeToNSRange:range];
    717 }
    718 
    719 - (NSRange)_convertDOMRangeToNSRange:(DOMRange *)range
    720 {
    721     return [self _convertToNSRange:core(range)];
    722 }
    723 
    724 - (DOMRange *)_markDOMRange
    725 {
    726     return kit(_private->coreFrame->editor()->mark().toNormalizedRange().get());
    727 }
    728 
    729 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
    730 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
    731 // the text surrounding the deletion.
    732 - (DOMRange *)_smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
    733 {
    734     Node* startContainer = core([proposedRange startContainer]);
    735     Node* endContainer = core([proposedRange endContainer]);
    736     if (startContainer == nil || endContainer == nil)
    737         return nil;
    738 
    739     ASSERT(startContainer->document() == endContainer->document());
    740 
    741     _private->coreFrame->document()->updateLayoutIgnorePendingStylesheets();
    742 
    743     Position start(startContainer, [proposedRange startOffset]);
    744     Position end(endContainer, [proposedRange endOffset]);
    745     Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true);
    746     if (newStart.isNull())
    747         newStart = start;
    748     Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true);
    749     if (newEnd.isNull())
    750         newEnd = end;
    751 
    752     newStart = newStart.parentAnchoredEquivalent();
    753     newEnd = newEnd.parentAnchoredEquivalent();
    754 
    755     RefPtr<Range> range = _private->coreFrame->document()->createRange();
    756     int exception = 0;
    757     range->setStart(newStart.containerNode(), newStart.offsetInContainerNode(), exception);
    758     range->setEnd(newStart.containerNode(), newStart.offsetInContainerNode(), exception);
    759     return kit(range.get());
    760 }
    761 
    762 - (DOMDocumentFragment *)_documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString
    763 {
    764     if (!_private->coreFrame || !_private->coreFrame->document())
    765         return nil;
    766 
    767     return kit(createFragmentFromMarkup(_private->coreFrame->document(), markupString, baseURLString, FragmentScriptingNotAllowed).get());
    768 }
    769 
    770 - (DOMDocumentFragment *)_documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
    771 {
    772     if (!_private->coreFrame || !_private->coreFrame->document())
    773         return nil;
    774 
    775     NSEnumerator *nodeEnum = [nodes objectEnumerator];
    776     Vector<Node*> nodesVector;
    777     DOMNode *node;
    778     while ((node = [nodeEnum nextObject]))
    779         nodesVector.append(core(node));
    780 
    781     return kit(createFragmentFromNodes(_private->coreFrame->document(), nodesVector).get());
    782 }
    783 
    784 - (void)_replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
    785 {
    786     DOMDocumentFragment *fragment = kit(_private->coreFrame->document()->createDocumentFragment().get());
    787     [fragment appendChild:node];
    788     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
    789 }
    790 
    791 - (void)_insertParagraphSeparatorInQuotedContent
    792 {
    793     if (_private->coreFrame->selection()->isNone())
    794         return;
    795 
    796     TypingCommand::insertParagraphSeparatorInQuotedContent(_private->coreFrame->document());
    797     _private->coreFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
    798 }
    799 
    800 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
    801 {
    802     // FIXME: Someone with access to Apple's sources could remove this needless wrapper call.
    803     return _private->coreFrame->visiblePositionForPoint(IntPoint(point));
    804 }
    805 
    806 - (DOMRange *)_characterRangeAtPoint:(NSPoint)point
    807 {
    808     return kit(_private->coreFrame->rangeForPoint(IntPoint(point)).get());
    809 }
    810 
    811 - (DOMCSSStyleDeclaration *)_typingStyle
    812 {
    813     if (!_private->coreFrame)
    814         return nil;
    815     RefPtr<CSSMutableStyleDeclaration> typingStyle = _private->coreFrame->selection()->copyTypingStyle();
    816     if (!typingStyle)
    817         return nil;
    818     return kit(typingStyle.get());
    819 }
    820 
    821 - (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
    822 {
    823     if (!_private->coreFrame)
    824         return;
    825     _private->coreFrame->editor()->computeAndSetTypingStyle(core(style), undoAction);
    826 }
    827 
    828 - (void)_dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
    829 {
    830     if (!_private->coreFrame)
    831         return;
    832     FrameView* view = _private->coreFrame->view();
    833     if (!view)
    834         return;
    835     ASSERT([getWebView(self) _usesDocumentViews]);
    836     // FIXME: These are fake modifier keys here, but they should be real ones instead.
    837     PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]),
    838         LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
    839     _private->coreFrame->eventHandler()->dragSourceEndedAt(event, (DragOperation)operation);
    840 }
    841 
    842 - (BOOL)_canProvideDocumentSource
    843 {
    844     Frame* frame = _private->coreFrame;
    845     String mimeType = frame->document()->loader()->writer()->mimeType();
    846     PluginData* pluginData = frame->page() ? frame->page()->pluginData() : 0;
    847 
    848     if (WebCore::DOMImplementation::isTextMIMEType(mimeType) ||
    849         Image::supportsType(mimeType) ||
    850         (pluginData && pluginData->supportsMimeType(mimeType)))
    851         return NO;
    852 
    853     return YES;
    854 }
    855 
    856 - (BOOL)_canSaveAsWebArchive
    857 {
    858     // Currently, all documents that we can view source for
    859     // (HTML and XML documents) can also be saved as web archives
    860     return [self _canProvideDocumentSource];
    861 }
    862 
    863 - (void)_commitData:(NSData *)data
    864 {
    865     // FIXME: This really should be a setting.
    866     Document* document = _private->coreFrame->document();
    867     document->setShouldCreateRenderers(_private->shouldCreateRenderers);
    868 
    869     _private->coreFrame->loader()->documentLoader()->commitData((const char *)[data bytes], [data length]);
    870 }
    871 
    872 @end
    873 
    874 @implementation WebFrame (WebPrivate)
    875 
    876 // FIXME: This exists only as a convenience for Safari, consider moving there.
    877 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
    878 {
    879     Frame* coreFrame = _private->coreFrame;
    880     return coreFrame && coreFrame->tree()->isDescendantOf(core(ancestor));
    881 }
    882 
    883 - (void)_setShouldCreateRenderers:(BOOL)shouldCreateRenderers
    884 {
    885     _private->shouldCreateRenderers = shouldCreateRenderers;
    886 }
    887 
    888 - (NSColor *)_bodyBackgroundColor
    889 {
    890     Document* document = _private->coreFrame->document();
    891     if (!document)
    892         return nil;
    893     HTMLElement* body = document->body();
    894     if (!body)
    895         return nil;
    896     RenderObject* bodyRenderer = body->renderer();
    897     if (!bodyRenderer)
    898         return nil;
    899     Color color = bodyRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
    900     if (!color.isValid())
    901         return nil;
    902     return nsColor(color);
    903 }
    904 
    905 - (BOOL)_isFrameSet
    906 {
    907     Document* document = _private->coreFrame->document();
    908     return document && document->isFrameSet();
    909 }
    910 
    911 - (BOOL)_firstLayoutDone
    912 {
    913     return _private->coreFrame->loader()->stateMachine()->firstLayoutDone();
    914 }
    915 
    916 - (WebFrameLoadType)_loadType
    917 {
    918     return (WebFrameLoadType)_private->coreFrame->loader()->loadType();
    919 }
    920 
    921 - (NSRange)_selectedNSRange
    922 {
    923     return [self _convertToNSRange:_private->coreFrame->selection()->toNormalizedRange().get()];
    924 }
    925 
    926 - (void)_selectNSRange:(NSRange)range
    927 {
    928     RefPtr<Range> domRange = [self _convertToDOMRange:range];
    929     if (domRange)
    930         _private->coreFrame->selection()->setSelection(VisibleSelection(domRange.get(), SEL_DEFAULT_AFFINITY));
    931 }
    932 
    933 - (BOOL)_isDisplayingStandaloneImage
    934 {
    935     Document* document = _private->coreFrame->document();
    936     return document && document->isImageDocument();
    937 }
    938 
    939 - (unsigned)_pendingFrameUnloadEventCount
    940 {
    941     return _private->coreFrame->domWindow()->pendingUnloadEventListeners();
    942 }
    943 
    944 - (void)_setIsDisconnected:(bool)isDisconnected
    945 {
    946     _private->coreFrame->setIsDisconnected(isDisconnected);
    947 }
    948 
    949 - (void)_setExcludeFromTextSearch:(bool)exclude
    950 {
    951     _private->coreFrame->setExcludeFromTextSearch(exclude);
    952 }
    953 
    954 #if ENABLE(NETSCAPE_PLUGIN_API)
    955 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
    956 {
    957     Frame* coreFrame = core(self);
    958     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
    959         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
    960         if ([documentView isKindOfClass:[WebHTMLView class]])
    961             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
    962     }
    963 }
    964 
    965 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
    966 {
    967     Frame* coreFrame = core(self);
    968     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
    969         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
    970         if ([documentView isKindOfClass:[WebHTMLView class]])
    971             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
    972     }
    973 }
    974 #endif
    975 
    976 - (BOOL)_pauseAnimation:(NSString*)name onNode:(DOMNode *)node atTime:(NSTimeInterval)time
    977 {
    978     Frame* frame = core(self);
    979     if (!frame)
    980         return false;
    981 
    982     AnimationController* controller = frame->animation();
    983     if (!controller)
    984         return false;
    985 
    986     Node* coreNode = core(node);
    987     if (!coreNode || !coreNode->renderer())
    988         return false;
    989 
    990     return controller->pauseAnimationAtTime(coreNode->renderer(), name, time);
    991 }
    992 
    993 - (BOOL)_pauseTransitionOfProperty:(NSString*)name onNode:(DOMNode*)node atTime:(NSTimeInterval)time
    994 {
    995     Frame* frame = core(self);
    996     if (!frame)
    997         return false;
    998 
    999     AnimationController* controller = frame->animation();
   1000     if (!controller)
   1001         return false;
   1002 
   1003     Node* coreNode = core(node);
   1004     if (!coreNode || !coreNode->renderer())
   1005         return false;
   1006 
   1007     return controller->pauseTransitionAtTime(coreNode->renderer(), name, time);
   1008 }
   1009 
   1010 // Pause a given SVG animation on the target node at a specific time.
   1011 // This method is only intended to be used for testing the SVG animation system.
   1012 - (BOOL)_pauseSVGAnimation:(NSString*)elementId onSMILNode:(DOMNode *)node atTime:(NSTimeInterval)time
   1013 {
   1014     Frame* frame = core(self);
   1015     if (!frame)
   1016         return false;
   1017 
   1018     Document* document = frame->document();
   1019     if (!document || !document->svgExtensions())
   1020         return false;
   1021 
   1022     Node* coreNode = core(node);
   1023     if (!coreNode || !SVGSMILElement::isSMILElement(coreNode))
   1024         return false;
   1025 
   1026 #if ENABLE(SVG)
   1027     return document->accessSVGExtensions()->sampleAnimationAtTime(elementId, static_cast<SVGSMILElement*>(coreNode), time);
   1028 #else
   1029     return false;
   1030 #endif
   1031 }
   1032 
   1033 - (unsigned) _numberOfActiveAnimations
   1034 {
   1035     Frame* frame = core(self);
   1036     if (!frame)
   1037         return false;
   1038 
   1039     AnimationController* controller = frame->animation();
   1040     if (!controller)
   1041         return false;
   1042 
   1043     return controller->numberOfActiveAnimations();
   1044 }
   1045 
   1046 - (void) _suspendAnimations
   1047 {
   1048     Frame* frame = core(self);
   1049     if (!frame)
   1050         return;
   1051 
   1052     frame->animation()->suspendAnimations();
   1053 }
   1054 
   1055 - (void) _resumeAnimations
   1056 {
   1057     Frame* frame = core(self);
   1058     if (!frame)
   1059         return;
   1060 
   1061     frame->animation()->resumeAnimations();
   1062 }
   1063 
   1064 - (void)_replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
   1065 {
   1066     if (_private->coreFrame->selection()->isNone() || !fragment)
   1067         return;
   1068     ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting;
   1069     if (selectReplacement)
   1070         options |= ReplaceSelectionCommand::SelectReplacement;
   1071     if (smartReplace)
   1072         options |= ReplaceSelectionCommand::SmartReplace;
   1073     if (matchStyle)
   1074         options |= ReplaceSelectionCommand::MatchStyle;
   1075     applyCommand(ReplaceSelectionCommand::create(_private->coreFrame->document(), core(fragment), options));
   1076     _private->coreFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
   1077 }
   1078 
   1079 - (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
   1080 {
   1081     DOMDocumentFragment* fragment = kit(createFragmentFromText(_private->coreFrame->selection()->toNormalizedRange().get(), text).get());
   1082     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
   1083 }
   1084 
   1085 - (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
   1086 {
   1087     DOMDocumentFragment *fragment = [self _documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
   1088     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
   1089 }
   1090 
   1091 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
   1092 // punctuation when it's inserted into the receiver's text over charRange. Returns by reference
   1093 // in beforeString and afterString any whitespace that should be added, unless either or both are
   1094 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
   1095 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
   1096 {
   1097     // give back nil pointers in case of early returns
   1098     if (beforeString)
   1099         *beforeString = nil;
   1100     if (afterString)
   1101         *afterString = nil;
   1102 
   1103     // inspect destination
   1104     Node *startContainer = core([rangeToReplace startContainer]);
   1105     Node *endContainer = core([rangeToReplace endContainer]);
   1106 
   1107     Position startPos(startContainer, [rangeToReplace startOffset]);
   1108     Position endPos(endContainer, [rangeToReplace endOffset]);
   1109 
   1110     VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
   1111     VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
   1112 
   1113     // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
   1114     if (startVisiblePos.isNull() || endVisiblePos.isNull())
   1115         return;
   1116 
   1117     bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
   1118     if (addLeadingSpace)
   1119         if (UChar previousChar = startVisiblePos.previous().characterAfter())
   1120             addLeadingSpace = !isCharacterSmartReplaceExempt(previousChar, true);
   1121 
   1122     bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
   1123     if (addTrailingSpace)
   1124         if (UChar thisChar = endVisiblePos.characterAfter())
   1125             addTrailingSpace = !isCharacterSmartReplaceExempt(thisChar, false);
   1126 
   1127     // inspect source
   1128     bool hasWhitespaceAtStart = false;
   1129     bool hasWhitespaceAtEnd = false;
   1130     unsigned pasteLength = [pasteString length];
   1131     if (pasteLength > 0) {
   1132         NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
   1133 
   1134         if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
   1135             hasWhitespaceAtStart = YES;
   1136         }
   1137         if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
   1138             hasWhitespaceAtEnd = YES;
   1139         }
   1140     }
   1141 
   1142     // issue the verdict
   1143     if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
   1144         *beforeString = @" ";
   1145     if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
   1146         *afterString = @" ";
   1147 }
   1148 
   1149 - (NSMutableDictionary *)_cacheabilityDictionary
   1150 {
   1151     NSMutableDictionary *result = [NSMutableDictionary dictionary];
   1152 
   1153     FrameLoader* frameLoader = _private->coreFrame->loader();
   1154     DocumentLoader* documentLoader = frameLoader->documentLoader();
   1155     if (documentLoader && !documentLoader->mainDocumentError().isNull())
   1156         [result setObject:(NSError *)documentLoader->mainDocumentError() forKey:WebFrameMainDocumentError];
   1157 
   1158     if (frameLoader->subframeLoader()->containsPlugins())
   1159         [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasPlugins];
   1160 
   1161     if (DOMWindow* domWindow = _private->coreFrame->domWindow()) {
   1162         if (domWindow->hasEventListeners(eventNames().unloadEvent))
   1163             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasUnloadListener];
   1164 
   1165 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
   1166         if (domWindow->optionalApplicationCache())
   1167             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesApplicationCache];
   1168 #endif
   1169     }
   1170 
   1171     if (Document* document = _private->coreFrame->document()) {
   1172 #if ENABLE(DATABASE)
   1173         if (document->hasOpenDatabases())
   1174             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesDatabases];
   1175 #endif
   1176 
   1177         if (document->usingGeolocation())
   1178             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesGeolocation];
   1179 
   1180         if (!document->canSuspendActiveDOMObjects())
   1181             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameCanSuspendActiveDOMObjects];
   1182     }
   1183 
   1184     return result;
   1185 }
   1186 
   1187 - (BOOL)_allowsFollowingLink:(NSURL *)URL
   1188 {
   1189     if (!_private->coreFrame)
   1190         return YES;
   1191     return _private->coreFrame->document()->securityOrigin()->canDisplay(URL);
   1192 }
   1193 
   1194 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string withGlobalObject:(JSObjectRef)globalObjectRef inScriptWorld:(WebScriptWorld *)world
   1195 {
   1196     // Start off with some guess at a frame and a global object, we'll try to do better...!
   1197     JSDOMWindow* anyWorldGlobalObject = _private->coreFrame->script()->globalObject(mainThreadNormalWorld());
   1198 
   1199     // The global object is probably a shell object? - if so, we know how to use this!
   1200     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
   1201     if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
   1202         anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
   1203 
   1204     // Get the frame frome the global object we've settled on.
   1205     Frame* frame = anyWorldGlobalObject->impl()->frame();
   1206     ASSERT(frame->document());
   1207     JSValue result = frame->script()->executeScriptInWorld(core(world), string, true).jsValue();
   1208 
   1209     if (!frame) // In case the script removed our frame from the page.
   1210         return @"";
   1211 
   1212     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
   1213     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or
   1214     // JSEvaluateScript instead, since they have less surprising semantics.
   1215     if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
   1216         return @"";
   1217 
   1218     JSLock lock(SilenceAssertionsOnly);
   1219     return ustringToString(result.toString(anyWorldGlobalObject->globalExec()));
   1220 }
   1221 
   1222 - (JSGlobalContextRef)_globalContextForScriptWorld:(WebScriptWorld *)world
   1223 {
   1224     Frame* coreFrame = _private->coreFrame;
   1225     if (!coreFrame)
   1226         return 0;
   1227     DOMWrapperWorld* coreWorld = core(world);
   1228     if (!coreWorld)
   1229         return 0;
   1230     return toGlobalRef(coreFrame->script()->globalObject(coreWorld)->globalExec());
   1231 }
   1232 
   1233 - (void)setAllowsScrollersToOverlapContent:(BOOL)flag
   1234 {
   1235     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
   1236     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAllowsScrollersToOverlapContent:flag];
   1237 }
   1238 
   1239 - (void)setAlwaysHideHorizontalScroller:(BOOL)flag
   1240 {
   1241     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
   1242     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideHorizontalScroller:flag];
   1243 }
   1244 - (void)setAlwaysHideVerticalScroller:(BOOL)flag
   1245 {
   1246     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
   1247     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideVerticalScroller:flag];
   1248 }
   1249 
   1250 - (void)setAccessibleName:(NSString *)name
   1251 {
   1252 #if HAVE(ACCESSIBILITY)
   1253     if (!AXObjectCache::accessibilityEnabled())
   1254         return;
   1255 
   1256     if (!_private->coreFrame || !_private->coreFrame->document())
   1257         return;
   1258 
   1259     AccessibilityObject* rootObject = _private->coreFrame->document()->axObjectCache()->rootObject();
   1260     if (rootObject) {
   1261         String strName(name);
   1262         rootObject->setAccessibleName(strName);
   1263     }
   1264 #endif
   1265 }
   1266 
   1267 - (NSString*)_layerTreeAsText
   1268 {
   1269     Frame* coreFrame = _private->coreFrame;
   1270     if (!coreFrame)
   1271         return @"";
   1272 
   1273     return coreFrame->layerTreeAsText();
   1274 }
   1275 
   1276 - (BOOL)hasSpellingMarker:(int)from length:(int)length
   1277 {
   1278     Frame* coreFrame = core(self);
   1279     if (!coreFrame)
   1280         return NO;
   1281     return coreFrame->editor()->selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
   1282 }
   1283 
   1284 - (BOOL)hasGrammarMarker:(int)from length:(int)length
   1285 {
   1286     Frame* coreFrame = core(self);
   1287     if (!coreFrame)
   1288         return NO;
   1289     return coreFrame->editor()->selectionStartHasMarkerFor(DocumentMarker::Grammar, from, length);
   1290 }
   1291 
   1292 - (id)accessibilityRoot
   1293 {
   1294 #if HAVE(ACCESSIBILITY)
   1295     if (!AXObjectCache::accessibilityEnabled()) {
   1296         AXObjectCache::enableAccessibility();
   1297         AXObjectCache::setEnhancedUserInterfaceAccessibility([[NSApp accessibilityAttributeValue:NSAccessibilityEnhancedUserInterfaceAttribute] boolValue]);
   1298     }
   1299 
   1300     if (!_private->coreFrame || !_private->coreFrame->document())
   1301         return nil;
   1302 
   1303     AccessibilityObject* rootObject = _private->coreFrame->document()->axObjectCache()->rootObjectForFrame(_private->coreFrame);
   1304     if (!rootObject)
   1305         return nil;
   1306 
   1307     // The root object will be a WebCore scroll view object. In WK1, scroll views are handled
   1308     // by the system and the root object should be the web area (instead of the scroll view).
   1309     if (rootObject->isAttachment() && rootObject->firstChild())
   1310         return rootObject->firstChild()->wrapper();
   1311 
   1312     return rootObject->wrapper();
   1313 #else
   1314     return nil;
   1315 #endif
   1316 }
   1317 
   1318 - (void)_clearOpener
   1319 {
   1320     Frame* coreFrame = _private->coreFrame;
   1321     if (coreFrame)
   1322         coreFrame->loader()->setOpener(0);
   1323 }
   1324 
   1325 // Used by pagination code called from AppKit when a standalone web page is printed.
   1326 - (NSArray *)_computePageRectsWithPrintScaleFactor:(float)printScaleFactor pageSize:(NSSize)pageSize
   1327 {
   1328     if (printScaleFactor <= 0) {
   1329         LOG_ERROR("printScaleFactor has bad value %.2f", printScaleFactor);
   1330         return [NSArray array];
   1331     }
   1332 
   1333     if (!_private->coreFrame)
   1334         return [NSArray array];
   1335     if (!_private->coreFrame->document())
   1336         return [NSArray array];
   1337     if (!_private->coreFrame->view())
   1338         return [NSArray array];
   1339     if (!_private->coreFrame->view()->documentView())
   1340         return [NSArray array];
   1341 
   1342     RenderView* root = toRenderView(_private->coreFrame->document()->renderer());
   1343     if (!root)
   1344         return [NSArray array];
   1345 
   1346     float printWidth = root->style()->isHorizontalWritingMode() ? root->docWidth() / printScaleFactor : pageSize.width;
   1347     float printHeight = root->style()->isHorizontalWritingMode() ? pageSize.height : root->docHeight() / printScaleFactor;
   1348 
   1349     PrintContext printContext(_private->coreFrame);
   1350     printContext.computePageRectsWithPageSize(FloatSize(printWidth, printHeight), true);
   1351     const Vector<IntRect>& pageRects = printContext.pageRects();
   1352 
   1353     size_t size = pageRects.size();
   1354     NSMutableArray *pages = [NSMutableArray arrayWithCapacity:size];
   1355     for (size_t i = 0; i < size; ++i)
   1356         [pages addObject:[NSValue valueWithRect:NSRect(pageRects[i])]];
   1357     return pages;
   1358 }
   1359 
   1360 @end
   1361 
   1362 @implementation WebFrame
   1363 
   1364 - (id)init
   1365 {
   1366     return nil;
   1367 }
   1368 
   1369 // Should be deprecated.
   1370 - (id)initWithName:(NSString *)name webFrameView:(WebFrameView *)view webView:(WebView *)webView
   1371 {
   1372     return nil;
   1373 }
   1374 
   1375 - (void)dealloc
   1376 {
   1377     if (_private && _private->includedInWebKitStatistics)
   1378         --WebFrameCount;
   1379 
   1380     [_private release];
   1381 
   1382     [super dealloc];
   1383 }
   1384 
   1385 - (void)finalize
   1386 {
   1387     if (_private && _private->includedInWebKitStatistics)
   1388         --WebFrameCount;
   1389 
   1390     [super finalize];
   1391 }
   1392 
   1393 - (NSString *)name
   1394 {
   1395     Frame* coreFrame = _private->coreFrame;
   1396     if (!coreFrame)
   1397         return nil;
   1398     return coreFrame->tree()->uniqueName();
   1399 }
   1400 
   1401 - (WebFrameView *)frameView
   1402 {
   1403     ASSERT(!getWebView(self) || [getWebView(self) _usesDocumentViews]);
   1404     return _private->webFrameView;
   1405 }
   1406 
   1407 - (WebView *)webView
   1408 {
   1409     return getWebView(self);
   1410 }
   1411 
   1412 static bool needsMicrosoftMessengerDOMDocumentWorkaround()
   1413 {
   1414     static bool needsWorkaround = applicationIsMicrosoftMessenger() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] compare:@"7.1" options:NSNumericSearch] == NSOrderedAscending;
   1415     return needsWorkaround;
   1416 }
   1417 
   1418 - (DOMDocument *)DOMDocument
   1419 {
   1420     if (needsMicrosoftMessengerDOMDocumentWorkaround() && !pthread_main_np())
   1421         return nil;
   1422 
   1423     Frame* coreFrame = _private->coreFrame;
   1424     if (!coreFrame)
   1425         return nil;
   1426 
   1427     // FIXME: <rdar://problem/5145841> When loading a custom view/representation
   1428     // into a web frame, the old document can still be around. This makes sure that
   1429     // we'll return nil in those cases.
   1430     if (![[self _dataSource] _isDocumentHTML])
   1431         return nil;
   1432 
   1433     Document* document = coreFrame->document();
   1434 
   1435     // According to the documentation, we should return nil if the frame doesn't have a document.
   1436     // While full-frame images and plugins do have an underlying HTML document, we return nil here to be
   1437     // backwards compatible.
   1438     if (document && (document->isPluginDocument() || document->isImageDocument()))
   1439         return nil;
   1440 
   1441     return kit(coreFrame->document());
   1442 }
   1443 
   1444 - (DOMHTMLElement *)frameElement
   1445 {
   1446     Frame* coreFrame = _private->coreFrame;
   1447     if (!coreFrame)
   1448         return nil;
   1449     return kit(coreFrame->ownerElement());
   1450 }
   1451 
   1452 - (WebDataSource *)provisionalDataSource
   1453 {
   1454     Frame* coreFrame = _private->coreFrame;
   1455     return coreFrame ? dataSource(coreFrame->loader()->provisionalDocumentLoader()) : nil;
   1456 }
   1457 
   1458 - (WebDataSource *)dataSource
   1459 {
   1460     Frame* coreFrame = _private->coreFrame;
   1461     return coreFrame && coreFrame->loader()->frameHasLoaded() ? [self _dataSource] : nil;
   1462 }
   1463 
   1464 - (void)loadRequest:(NSURLRequest *)request
   1465 {
   1466     Frame* coreFrame = _private->coreFrame;
   1467     if (!coreFrame)
   1468         return;
   1469     coreFrame->loader()->load(request, false);
   1470 }
   1471 
   1472 static NSURL *createUniqueWebDataURL()
   1473 {
   1474     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
   1475     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
   1476     CFRelease(UUIDRef);
   1477     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"applewebdata://%@", UUIDString]];
   1478     CFRelease(UUIDString);
   1479     return URL;
   1480 }
   1481 
   1482 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
   1483 {
   1484     if (!pthread_main_np())
   1485         return [[self _webkit_invokeOnMainThread] _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:unreachableURL];
   1486 
   1487     KURL responseURL;
   1488     if (!baseURL) {
   1489         baseURL = blankURL();
   1490         responseURL = createUniqueWebDataURL();
   1491     }
   1492 
   1493     ResourceRequest request([baseURL absoluteURL]);
   1494 
   1495     // hack because Mail checks for this property to detect data / archive loads
   1496     [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest()];
   1497 
   1498     SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData(data), MIMEType, encodingName, [unreachableURL absoluteURL], responseURL);
   1499 
   1500     _private->coreFrame->loader()->load(request, substituteData, false);
   1501 }
   1502 
   1503 
   1504 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
   1505 {
   1506     WebCoreThreadViolationCheckRoundTwo();
   1507 
   1508     if (!MIMEType)
   1509         MIMEType = @"text/html";
   1510     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:nil];
   1511 }
   1512 
   1513 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
   1514 {
   1515     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
   1516     [self _loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL unreachableURL:unreachableURL];
   1517 }
   1518 
   1519 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
   1520 {
   1521     WebCoreThreadViolationCheckRoundTwo();
   1522 
   1523     [self _loadHTMLString:string baseURL:baseURL unreachableURL:nil];
   1524 }
   1525 
   1526 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
   1527 {
   1528     WebCoreThreadViolationCheckRoundTwo();
   1529 
   1530     [self _loadHTMLString:string baseURL:baseURL unreachableURL:unreachableURL];
   1531 }
   1532 
   1533 - (void)loadArchive:(WebArchive *)archive
   1534 {
   1535     if (LegacyWebArchive* coreArchive = [archive _coreLegacyWebArchive])
   1536         _private->coreFrame->loader()->loadArchive(coreArchive);
   1537 }
   1538 
   1539 - (void)stopLoading
   1540 {
   1541     if (!_private->coreFrame)
   1542         return;
   1543     _private->coreFrame->loader()->stopForUserCancel();
   1544 }
   1545 
   1546 - (void)reload
   1547 {
   1548     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_RELOAD_FROM_ORIGIN) && applicationIsSafari())
   1549         _private->coreFrame->loader()->reload(GetCurrentKeyModifiers() & shiftKey);
   1550     else
   1551         _private->coreFrame->loader()->reload(false);
   1552 }
   1553 
   1554 - (void)reloadFromOrigin
   1555 {
   1556     _private->coreFrame->loader()->reload(true);
   1557 }
   1558 
   1559 - (WebFrame *)findFrameNamed:(NSString *)name
   1560 {
   1561     Frame* coreFrame = _private->coreFrame;
   1562     if (!coreFrame)
   1563         return nil;
   1564     return kit(coreFrame->tree()->find(name));
   1565 }
   1566 
   1567 - (WebFrame *)parentFrame
   1568 {
   1569     Frame* coreFrame = _private->coreFrame;
   1570     if (!coreFrame)
   1571         return nil;
   1572     return [[kit(coreFrame->tree()->parent()) retain] autorelease];
   1573 }
   1574 
   1575 - (NSArray *)childFrames
   1576 {
   1577     Frame* coreFrame = _private->coreFrame;
   1578     if (!coreFrame)
   1579         return [NSArray array];
   1580     NSMutableArray *children = [NSMutableArray arrayWithCapacity:coreFrame->tree()->childCount()];
   1581     for (Frame* child = coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling())
   1582         [children addObject:kit(child)];
   1583     return children;
   1584 }
   1585 
   1586 - (WebScriptObject *)windowObject
   1587 {
   1588     Frame* coreFrame = _private->coreFrame;
   1589     if (!coreFrame)
   1590         return 0;
   1591     return coreFrame->script()->windowScriptObject();
   1592 }
   1593 
   1594 - (JSGlobalContextRef)globalContext
   1595 {
   1596     Frame* coreFrame = _private->coreFrame;
   1597     if (!coreFrame)
   1598         return 0;
   1599     return toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
   1600 }
   1601 
   1602 @end
   1603