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