1 /* 2 * Copyright (C) 2010 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "WebFrame.h" 28 29 #include "DownloadManager.h" 30 #include "InjectedBundleNodeHandle.h" 31 #include "InjectedBundleRangeHandle.h" 32 #include "InjectedBundleScriptWorld.h" 33 #include "WebChromeClient.h" 34 #include "WebPage.h" 35 #include "WebPageProxyMessages.h" 36 #include "WebProcess.h" 37 #include <JavaScriptCore/APICast.h> 38 #include <JavaScriptCore/JSContextRef.h> 39 #include <JavaScriptCore/JSLock.h> 40 #include <JavaScriptCore/JSValueRef.h> 41 #include <WebCore/AnimationController.h> 42 #include <WebCore/ArchiveResource.h> 43 #include <WebCore/CSSComputedStyleDeclaration.h> 44 #include <WebCore/Chrome.h> 45 #include <WebCore/DocumentLoader.h> 46 #include <WebCore/Frame.h> 47 #include <WebCore/FrameView.h> 48 #include <WebCore/HTMLFrameOwnerElement.h> 49 #include <WebCore/JSCSSStyleDeclaration.h> 50 #include <WebCore/JSElement.h> 51 #include <WebCore/JSRange.h> 52 #include <WebCore/Page.h> 53 #include <WebCore/RenderTreeAsText.h> 54 #include <WebCore/TextIterator.h> 55 #include <WebCore/TextResourceDecoder.h> 56 #include <wtf/text/StringBuilder.h> 57 58 #ifndef NDEBUG 59 #include <wtf/RefCountedLeakCounter.h> 60 #endif 61 62 using namespace JSC; 63 using namespace WebCore; 64 65 namespace WebKit { 66 67 #ifndef NDEBUG 68 static WTF::RefCountedLeakCounter webFrameCounter("WebFrame"); 69 #endif 70 71 static uint64_t generateFrameID() 72 { 73 static uint64_t uniqueFrameID = 1; 74 return uniqueFrameID++; 75 } 76 77 static uint64_t generateListenerID() 78 { 79 static uint64_t uniqueListenerID = 1; 80 return uniqueListenerID++; 81 } 82 83 PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page) 84 { 85 RefPtr<WebFrame> frame = create(); 86 87 page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID())); 88 89 frame->init(page, String(), 0); 90 91 return frame.release(); 92 } 93 94 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement) 95 { 96 RefPtr<WebFrame> frame = create(); 97 98 WebFrame* parentFrame = static_cast<WebFrameLoaderClient*>(ownerElement->document()->frame()->loader()->client())->webFrame(); 99 page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID(), parentFrame->frameID())); 100 101 frame->init(page, frameName, ownerElement); 102 103 return frame.release(); 104 } 105 106 PassRefPtr<WebFrame> WebFrame::create() 107 { 108 RefPtr<WebFrame> frame = adoptRef(new WebFrame); 109 110 // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed(). 111 frame->ref(); 112 113 return frame.release(); 114 } 115 116 WebFrame::WebFrame() 117 : m_coreFrame(0) 118 , m_policyListenerID(0) 119 , m_policyFunction(0) 120 , m_policyDownloadID(0) 121 , m_frameLoaderClient(this) 122 , m_loadListener(0) 123 , m_frameID(generateFrameID()) 124 { 125 WebProcess::shared().addWebFrame(m_frameID, this); 126 127 #ifndef NDEBUG 128 webFrameCounter.increment(); 129 #endif 130 } 131 132 WebFrame::~WebFrame() 133 { 134 ASSERT(!m_coreFrame); 135 136 #ifndef NDEBUG 137 webFrameCounter.decrement(); 138 #endif 139 } 140 141 void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement) 142 { 143 RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient); 144 m_coreFrame = frame.get(); 145 146 frame->tree()->setName(frameName); 147 148 if (ownerElement) { 149 ASSERT(ownerElement->document()->frame()); 150 ownerElement->document()->frame()->tree()->appendChild(frame); 151 } 152 153 frame->init(); 154 } 155 156 WebPage* WebFrame::page() const 157 { 158 if (!m_coreFrame) 159 return 0; 160 161 if (WebCore::Page* page = m_coreFrame->page()) 162 return static_cast<WebChromeClient*>(page->chrome()->client())->page(); 163 164 return 0; 165 } 166 167 void WebFrame::invalidate() 168 { 169 WebProcess::shared().removeWebFrame(m_frameID); 170 m_coreFrame = 0; 171 } 172 173 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction) 174 { 175 // FIXME: <rdar://5634381> We need to support multiple active policy listeners. 176 177 invalidatePolicyListener(); 178 179 m_policyListenerID = generateListenerID(); 180 m_policyFunction = policyFunction; 181 return m_policyListenerID; 182 } 183 184 void WebFrame::invalidatePolicyListener() 185 { 186 if (!m_policyListenerID) 187 return; 188 189 m_policyDownloadID = 0; 190 m_policyListenerID = 0; 191 m_policyFunction = 0; 192 } 193 194 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID) 195 { 196 if (!m_coreFrame) 197 return; 198 199 if (!m_policyListenerID) 200 return; 201 202 if (listenerID != m_policyListenerID) 203 return; 204 205 ASSERT(m_policyFunction); 206 207 FramePolicyFunction function = m_policyFunction; 208 209 invalidatePolicyListener(); 210 211 m_policyDownloadID = downloadID; 212 213 (m_coreFrame->loader()->policyChecker()->*function)(action); 214 } 215 216 void WebFrame::startDownload(const WebCore::ResourceRequest& request) 217 { 218 ASSERT(m_policyDownloadID); 219 220 DownloadManager::shared().startDownload(m_policyDownloadID, page(), request); 221 222 m_policyDownloadID = 0; 223 } 224 225 void WebFrame::convertHandleToDownload(ResourceHandle* handle, const ResourceRequest& request, const ResourceRequest& initialRequest, const ResourceResponse& response) 226 { 227 ASSERT(m_policyDownloadID); 228 229 DownloadManager::shared().convertHandleToDownload(m_policyDownloadID, page(), handle, request, initialRequest, response); 230 m_policyDownloadID = 0; 231 } 232 233 String WebFrame::source() const 234 { 235 if (!m_coreFrame) 236 return String(); 237 Document* document = m_coreFrame->document(); 238 if (!document) 239 return String(); 240 TextResourceDecoder* decoder = document->decoder(); 241 if (!decoder) 242 return String(); 243 DocumentLoader* documentLoader = m_coreFrame->loader()->activeDocumentLoader(); 244 if (!documentLoader) 245 return String(); 246 RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData(); 247 if (!mainResourceData) 248 return String(); 249 return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size()); 250 } 251 252 String WebFrame::contentsAsString() const 253 { 254 if (!m_coreFrame) 255 return String(); 256 257 if (isFrameSet()) { 258 StringBuilder builder; 259 for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { 260 if (!builder.isEmpty()) 261 builder.append(' '); 262 builder.append(static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame()->contentsAsString()); 263 } 264 // FIXME: It may make sense to use toStringPreserveCapacity() here. 265 return builder.toString(); 266 } 267 268 Document* document = m_coreFrame->document(); 269 if (!document) 270 return String(); 271 272 RefPtr<Element> documentElement = document->documentElement(); 273 if (!documentElement) 274 return String(); 275 276 RefPtr<Range> range = document->createRange(); 277 278 ExceptionCode ec = 0; 279 range->selectNode(documentElement.get(), ec); 280 if (ec) 281 return String(); 282 283 return plainText(range.get()); 284 } 285 286 String WebFrame::selectionAsString() const 287 { 288 if (!m_coreFrame) 289 return String(); 290 291 return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText()); 292 } 293 294 IntSize WebFrame::size() const 295 { 296 if (!m_coreFrame) 297 return IntSize(); 298 299 FrameView* frameView = m_coreFrame->view(); 300 if (!frameView) 301 return IntSize(); 302 303 return frameView->contentsSize(); 304 } 305 306 bool WebFrame::isFrameSet() const 307 { 308 if (!m_coreFrame) 309 return false; 310 311 Document* document = m_coreFrame->document(); 312 if (!document) 313 return false; 314 return document->isFrameSet(); 315 } 316 317 bool WebFrame::isMainFrame() const 318 { 319 if (WebPage* p = page()) 320 return p->mainFrame() == this; 321 322 return false; 323 } 324 325 String WebFrame::name() const 326 { 327 if (!m_coreFrame) 328 return String(); 329 330 return m_coreFrame->tree()->uniqueName(); 331 } 332 333 String WebFrame::url() const 334 { 335 if (!m_coreFrame) 336 return String(); 337 338 DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader(); 339 if (!documentLoader) 340 return String(); 341 342 return documentLoader->url().string(); 343 } 344 345 String WebFrame::innerText() const 346 { 347 if (!m_coreFrame) 348 return String(); 349 350 if (!m_coreFrame->document()->documentElement()) 351 return String(); 352 353 return m_coreFrame->document()->documentElement()->innerText(); 354 } 355 356 PassRefPtr<ImmutableArray> WebFrame::childFrames() 357 { 358 if (!m_coreFrame) 359 return ImmutableArray::create(); 360 361 size_t size = m_coreFrame->tree()->childCount(); 362 if (!size) 363 return ImmutableArray::create(); 364 365 Vector<RefPtr<APIObject> > vector; 366 vector.reserveInitialCapacity(size); 367 368 for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { 369 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame(); 370 vector.uncheckedAppend(webFrame); 371 } 372 373 return ImmutableArray::adopt(vector); 374 } 375 376 unsigned WebFrame::numberOfActiveAnimations() const 377 { 378 if (!m_coreFrame) 379 return 0; 380 381 AnimationController* controller = m_coreFrame->animation(); 382 if (!controller) 383 return 0; 384 385 return controller->numberOfActiveAnimations(); 386 } 387 388 bool WebFrame::pauseAnimationOnElementWithId(const String& animationName, const String& elementID, double time) 389 { 390 if (!m_coreFrame) 391 return false; 392 393 AnimationController* controller = m_coreFrame->animation(); 394 if (!controller) 395 return false; 396 397 if (!m_coreFrame->document()) 398 return false; 399 400 Node* coreNode = m_coreFrame->document()->getElementById(elementID); 401 if (!coreNode || !coreNode->renderer()) 402 return false; 403 404 return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time); 405 } 406 407 void WebFrame::suspendAnimations() 408 { 409 if (!m_coreFrame) 410 return; 411 412 AnimationController* controller = m_coreFrame->animation(); 413 if (!controller) 414 return; 415 416 controller->suspendAnimations(); 417 } 418 419 void WebFrame::resumeAnimations() 420 { 421 if (!m_coreFrame) 422 return; 423 424 AnimationController* controller = m_coreFrame->animation(); 425 if (!controller) 426 return; 427 428 controller->resumeAnimations(); 429 } 430 431 String WebFrame::layerTreeAsText() const 432 { 433 if (!m_coreFrame) 434 return ""; 435 436 return m_coreFrame->layerTreeAsText(); 437 } 438 439 unsigned WebFrame::pendingUnloadCount() const 440 { 441 if (!m_coreFrame) 442 return 0; 443 444 return m_coreFrame->domWindow()->pendingUnloadEventListeners(); 445 } 446 447 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const 448 { 449 if (!m_coreFrame) 450 return true; 451 452 return m_coreFrame->document()->securityOrigin()->canDisplay(url); 453 } 454 455 JSGlobalContextRef WebFrame::jsContext() 456 { 457 return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()); 458 } 459 460 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world) 461 { 462 return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec()); 463 } 464 465 IntRect WebFrame::contentBounds() const 466 { 467 if (!m_coreFrame) 468 return IntRect(); 469 470 FrameView* view = m_coreFrame->view(); 471 if (!view) 472 return IntRect(); 473 474 return IntRect(0, 0, view->contentsWidth(), view->contentsHeight()); 475 } 476 477 IntRect WebFrame::visibleContentBounds() const 478 { 479 if (!m_coreFrame) 480 return IntRect(); 481 482 FrameView* view = m_coreFrame->view(); 483 if (!view) 484 return IntRect(); 485 486 IntRect contentRect = view->visibleContentRect(true); 487 return IntRect(0, 0, contentRect.width(), contentRect.height()); 488 } 489 490 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const 491 { 492 if (!m_coreFrame) 493 return IntRect(); 494 495 FrameView* view = m_coreFrame->view(); 496 if (!view) 497 return IntRect(); 498 499 IntRect contentRect = view->visibleContentRect(false); 500 return IntRect(0, 0, contentRect.width(), contentRect.height()); 501 } 502 503 IntSize WebFrame::scrollOffset() const 504 { 505 if (!m_coreFrame) 506 return IntSize(); 507 508 FrameView* view = m_coreFrame->view(); 509 if (!view) 510 return IntSize(); 511 512 return view->scrollOffset(); 513 } 514 515 bool WebFrame::hasHorizontalScrollbar() const 516 { 517 if (!m_coreFrame) 518 return false; 519 520 FrameView* view = m_coreFrame->view(); 521 if (!view) 522 return false; 523 524 return view->horizontalScrollbar(); 525 } 526 527 bool WebFrame::hasVerticalScrollbar() const 528 { 529 if (!m_coreFrame) 530 return false; 531 532 FrameView* view = m_coreFrame->view(); 533 if (!view) 534 return false; 535 536 return view->verticalScrollbar(); 537 } 538 539 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha) 540 { 541 if (!m_coreFrame) 542 return false; 543 Document* document = m_coreFrame->document(); 544 if (!document) 545 return false; 546 547 Element* rootElementToUse = document->body(); 548 if (!rootElementToUse) 549 rootElementToUse = document->documentElement(); 550 if (!rootElementToUse) 551 return false; 552 553 RenderObject* renderer = rootElementToUse->renderer(); 554 if (!renderer) 555 return false; 556 Color color = renderer->style()->visitedDependentColor(CSSPropertyBackgroundColor); 557 if (!color.isValid()) 558 return false; 559 560 color.getRGBA(*red, *green, *blue, *alpha); 561 return true; 562 } 563 564 WebFrame* WebFrame::frameForContext(JSContextRef context) 565 { 566 JSObjectRef globalObjectRef = JSContextGetGlobalObject(context); 567 JSC::JSObject* globalObjectObj = toJS(globalObjectRef); 568 if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0) 569 return 0; 570 571 Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame(); 572 return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame(); 573 } 574 575 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world) 576 { 577 if (!m_coreFrame) 578 return 0; 579 580 JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld()); 581 ExecState* exec = globalObject->globalExec(); 582 583 JSLock lock(SilenceAssertionsOnly); 584 return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode())); 585 } 586 587 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world) 588 { 589 if (!m_coreFrame) 590 return 0; 591 592 JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld()); 593 ExecState* exec = globalObject->globalExec(); 594 595 JSLock lock(SilenceAssertionsOnly); 596 return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange())); 597 } 598 599 JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element) 600 { 601 if (!m_coreFrame) 602 return 0; 603 604 JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld()); 605 ExecState* exec = globalObject->globalExec(); 606 607 if (!toJS(element)->inherits(&JSElement::s_info)) 608 return JSValueMakeUndefined(toRef(exec)); 609 610 RefPtr<CSSComputedStyleDeclaration> style = computedStyle(static_cast<JSElement*>(toJS(element))->impl(), true); 611 612 JSLock lock(SilenceAssertionsOnly); 613 return toRef(exec, toJS(exec, globalObject, style.get())); 614 } 615 616 String WebFrame::counterValue(JSObjectRef element) 617 { 618 if (!toJS(element)->inherits(&JSElement::s_info)) 619 return String(); 620 621 return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl()); 622 } 623 624 String WebFrame::markerText(JSObjectRef element) 625 { 626 if (!toJS(element)->inherits(&JSElement::s_info)) 627 return String(); 628 629 return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl()); 630 } 631 632 String WebFrame::provisionalURL() const 633 { 634 if (!m_coreFrame) 635 return String(); 636 637 return m_coreFrame->loader()->provisionalDocumentLoader()->url().string(); 638 } 639 640 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const 641 { 642 if (!m_coreFrame) 643 return String(); 644 645 DocumentLoader* loader = m_coreFrame->loader()->documentLoader(); 646 if (!loader) 647 return String(); 648 649 // First, try the main resource. 650 if (loader->url() == url) 651 return loader->response().suggestedFilename(); 652 653 // Next, try subresources. 654 RefPtr<ArchiveResource> resource = loader->subresource(url); 655 if (!resource) 656 return String(); 657 658 return resource->response().suggestedFilename(); 659 } 660 661 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const 662 { 663 if (!m_coreFrame) 664 return String(); 665 666 DocumentLoader* loader = m_coreFrame->loader()->documentLoader(); 667 if (!loader) 668 return String(); 669 670 // First, try the main resource. 671 if (loader->url() == url) 672 return loader->response().mimeType(); 673 674 // Next, try subresources. 675 RefPtr<ArchiveResource> resource = loader->subresource(url); 676 if (resource) 677 return resource->mimeType(); 678 679 return page()->cachedResponseMIMETypeForURL(url); 680 } 681 682 } // namespace WebKit 683