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