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 101 using namespace std; 102 using namespace WebCore; 103 using namespace HTMLNames; 104 105 using JSC::JSGlobalObject; 106 using JSC::JSLock; 107 using JSC::JSValue; 108 using JSC::SilenceAssertionsOnly; 109 110 /* 111 Here is the current behavior matrix for four types of navigations: 112 113 Standard 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 120 Back/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 127 Reload (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 134 Repeat 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 142 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey"; 143 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey"; 144 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey"; 145 146 NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey"; 147 NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey"; 148 NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey"; 149 NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey"; 150 NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey"; 151 NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey"; 152 NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey"; 153 154 // FIXME: Remove when this key becomes publicly defined 155 NSString *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 184 EditableLinkBehavior 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 202 WebCore::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 216 TextDirectionSubmenuInclusionBehavior 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 232 Frame* core(WebFrame *frame) 233 { 234 return frame ? frame->_private->coreFrame : 0; 235 } 236 237 WebFrame *kit(Frame* frame) 238 { 239 return frame ? static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame() : nil; 240 } 241 242 Page* core(WebView *webView) 243 { 244 return [webView page]; 245 } 246 247 WebView *kit(Page* page) 248 { 249 return page ? static_cast<WebView*>(page->chrome()->client()->webView()) : nil; 250 } 251 252 WebView *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 484 static 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 1412 static 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 1472 static 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