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