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