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 95using namespace std; 96using namespace WebCore; 97using namespace HTMLNames; 98 99using JSC::JSGlobalObject; 100using JSC::JSLock; 101using JSC::JSValue; 102using JSC::SilenceAssertionsOnly; 103 104/* 105Here is the current behavior matrix for four types of navigations: 106 107Standard 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 114Back/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 121Reload (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 128Repeat 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 136NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey"; 137NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey"; 138NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey"; 139 140NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey"; 141NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey"; 142NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey"; 143NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey"; 144NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey"; 145NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey"; 146NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey"; 147 148// FIXME: Remove when this key becomes publicly defined 149NSString *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 178EditableLinkBehavior 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 196TextDirectionSubmenuInclusionBehavior 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 212Frame* core(WebFrame *frame) 213{ 214 return frame ? frame->_private->coreFrame : 0; 215} 216 217WebFrame *kit(Frame* frame) 218{ 219 return frame ? static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame() : nil; 220} 221 222Page* core(WebView *webView) 223{ 224 return [webView page]; 225} 226 227WebView *kit(Page* page) 228{ 229 return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : nil; 230} 231 232WebView *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 456static 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 it’s inserted into the receiver’s 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 1309static 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 1369static 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