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