Home | History | Annotate | Download | only in WebPage
      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