Home | History | Annotate | Download | only in InjectedBundle
      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 "InjectedBundle.h"
     28 
     29 #include "Arguments.h"
     30 #include "ImmutableArray.h"
     31 #include "InjectedBundleMessageKinds.h"
     32 #include "InjectedBundleScriptWorld.h"
     33 #include "InjectedBundleUserMessageCoders.h"
     34 #include "WKAPICast.h"
     35 #include "WKBundleAPICast.h"
     36 #include "WebContextMessageKinds.h"
     37 #include "WebCoreArgumentCoders.h"
     38 #include "WebDatabaseManager.h"
     39 #include "WebFrame.h"
     40 #include "WebPage.h"
     41 #include "WebPreferencesStore.h"
     42 #include "WebProcess.h"
     43 #include <JavaScriptCore/APICast.h>
     44 #include <JavaScriptCore/JSLock.h>
     45 #include <WebCore/Frame.h>
     46 #include <WebCore/FrameView.h>
     47 #include <WebCore/GCController.h>
     48 #include <WebCore/JSDOMWindow.h>
     49 #include <WebCore/Page.h>
     50 #include <WebCore/PageGroup.h>
     51 #include <WebCore/PrintContext.h>
     52 #include <WebCore/Settings.h>
     53 #include <wtf/OwnArrayPtr.h>
     54 #include <wtf/PassOwnArrayPtr.h>
     55 
     56 using namespace WebCore;
     57 using namespace JSC;
     58 
     59 namespace WebKit {
     60 
     61 InjectedBundle::InjectedBundle(const String& path)
     62     : m_path(path)
     63     , m_platformBundle(0)
     64 {
     65     initializeClient(0);
     66 }
     67 
     68 InjectedBundle::~InjectedBundle()
     69 {
     70 }
     71 
     72 void InjectedBundle::initializeClient(WKBundleClient* client)
     73 {
     74     m_client.initialize(client);
     75 }
     76 
     77 void InjectedBundle::postMessage(const String& messageName, APIObject* messageBody)
     78 {
     79     WebProcess::shared().connection()->deprecatedSend(WebContextLegacyMessage::PostMessage, 0, CoreIPC::In(messageName, InjectedBundleUserMessageEncoder(messageBody)));
     80 }
     81 
     82 void InjectedBundle::postSynchronousMessage(const String& messageName, APIObject* messageBody, RefPtr<APIObject>& returnData)
     83 {
     84     RefPtr<APIObject> returnDataTmp;
     85     InjectedBundleUserMessageDecoder messageDecoder(returnDataTmp);
     86 
     87     bool succeeded = WebProcess::shared().connection()->deprecatedSendSync(WebContextLegacyMessage::PostSynchronousMessage, 0, CoreIPC::In(messageName, InjectedBundleUserMessageEncoder(messageBody)), CoreIPC::Out(messageDecoder));
     88 
     89     if (!succeeded)
     90         return;
     91 
     92     returnData = returnDataTmp;
     93 }
     94 
     95 void InjectedBundle::setShouldTrackVisitedLinks(bool shouldTrackVisitedLinks)
     96 {
     97     PageGroup::setShouldTrackVisitedLinks(shouldTrackVisitedLinks);
     98 }
     99 
    100 void InjectedBundle::removeAllVisitedLinks()
    101 {
    102     PageGroup::removeAllVisitedLinks();
    103 }
    104 
    105 void InjectedBundle::overrideXSSAuditorEnabledForTestRunner(WebPageGroupProxy* pageGroup, bool enabled)
    106 {
    107     // Override the preference for all future pages.
    108     WebPreferencesStore::overrideXSSAuditorEnabledForTestRunner(enabled);
    109 
    110     // Change the setting for existing ones.
    111     const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroup->identifier())->pages();
    112     for (HashSet<Page*>::iterator iter = pages.begin(); iter != pages.end(); ++iter)
    113         (*iter)->settings()->setXSSAuditorEnabled(enabled);
    114 }
    115 
    116 void InjectedBundle::overrideAllowUniversalAccessFromFileURLsForTestRunner(WebPageGroupProxy* pageGroup, bool enabled)
    117 {
    118     // Override the preference for all future pages.
    119     WebPreferencesStore::overrideAllowUniversalAccessFromFileURLsForTestRunner(enabled);
    120 
    121     // Change the setting for existing ones.
    122     const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroup->identifier())->pages();
    123     for (HashSet<Page*>::iterator iter = pages.begin(); iter != pages.end(); ++iter)
    124         (*iter)->settings()->setAllowUniversalAccessFromFileURLs(enabled);
    125 }
    126 
    127 void InjectedBundle::setAllowFileAccessFromFileURLs(WebPageGroupProxy* pageGroup, bool enabled)
    128 {
    129     // Override the preference for all future pages.
    130     WebPreferencesStore::overrideAllowFileAccessFromFileURLsForTestRunner(enabled);
    131 
    132     // Change the setting for existing ones.
    133     const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroup->identifier())->pages();
    134     for (HashSet<Page*>::iterator iter = pages.begin(); iter != pages.end(); ++iter)
    135         (*iter)->settings()->setAllowFileAccessFromFileURLs(enabled);
    136 }
    137 
    138 void InjectedBundle::clearAllDatabases()
    139 {
    140     WebDatabaseManager::shared().deleteAllDatabases();
    141 }
    142 
    143 void InjectedBundle::setDatabaseQuota(uint64_t quota)
    144 {
    145     WebDatabaseManager::shared().setQuotaForOrigin("file:///", quota);
    146 }
    147 
    148 int InjectedBundle::numberOfPages(WebFrame* frame, double pageWidthInPixels, double pageHeightInPixels)
    149 {
    150     Frame* coreFrame = frame ? frame->coreFrame() : 0;
    151     if (!coreFrame)
    152         return -1;
    153     if (!pageWidthInPixels)
    154         pageWidthInPixels = coreFrame->view()->width();
    155     if (!pageHeightInPixels)
    156         pageHeightInPixels = coreFrame->view()->height();
    157 
    158     return PrintContext::numberOfPages(coreFrame, FloatSize(pageWidthInPixels, pageHeightInPixels));
    159 }
    160 
    161 int InjectedBundle::pageNumberForElementById(WebFrame* frame, const String& id, double pageWidthInPixels, double pageHeightInPixels)
    162 {
    163     Frame* coreFrame = frame ? frame->coreFrame() : 0;
    164     if (!coreFrame)
    165         return -1;
    166 
    167     Element* element = coreFrame->document()->getElementById(AtomicString(id));
    168     if (!element)
    169         return -1;
    170 
    171     if (!pageWidthInPixels)
    172         pageWidthInPixels = coreFrame->view()->width();
    173     if (!pageHeightInPixels)
    174         pageHeightInPixels = coreFrame->view()->height();
    175 
    176     return PrintContext::pageNumberForElement(element, FloatSize(pageWidthInPixels, pageHeightInPixels));
    177 }
    178 
    179 String InjectedBundle::pageSizeAndMarginsInPixels(WebFrame* frame, int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
    180 {
    181     Frame* coreFrame = frame ? frame->coreFrame() : 0;
    182     if (!coreFrame)
    183         return String();
    184 
    185     return PrintContext::pageSizeAndMarginsInPixels(coreFrame, pageIndex, width, height, marginTop, marginRight, marginBottom, marginLeft);
    186 }
    187 
    188 bool InjectedBundle::isPageBoxVisible(WebFrame* frame, int pageIndex)
    189 {
    190     Frame* coreFrame = frame ? frame->coreFrame() : 0;
    191     if (!coreFrame)
    192         return false;
    193 
    194     return PrintContext::isPageBoxVisible(coreFrame, pageIndex);
    195 }
    196 
    197 static PassOwnPtr<Vector<String> > toStringVector(ImmutableArray* patterns)
    198 {
    199     if (!patterns)
    200         return 0;
    201 
    202     size_t size =  patterns->size();
    203     if (!size)
    204         return 0;
    205 
    206     Vector<String>* patternsVector = new Vector<String>;
    207     patternsVector->reserveInitialCapacity(size);
    208     for (size_t i = 0; i < size; ++i) {
    209         WebString* entry = patterns->at<WebString>(i);
    210         if (entry)
    211             patternsVector->uncheckedAppend(entry->string());
    212     }
    213     return patternsVector;
    214 }
    215 
    216 void InjectedBundle::addUserScript(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& source, const String& url, ImmutableArray* whitelist, ImmutableArray* blacklist, WebCore::UserScriptInjectionTime injectionTime, WebCore::UserContentInjectedFrames injectedFrames)
    217 {
    218     // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version.
    219     PageGroup::pageGroup(pageGroup->identifier())->addUserScriptToWorld(scriptWorld->coreWorld(), source, KURL(KURL(), url), toStringVector(whitelist), toStringVector(blacklist), injectionTime, injectedFrames);
    220 }
    221 
    222 void InjectedBundle::addUserStyleSheet(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& source, const String& url, ImmutableArray* whitelist, ImmutableArray* blacklist, WebCore::UserContentInjectedFrames injectedFrames)
    223 {
    224     // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version.
    225     PageGroup::pageGroup(pageGroup->identifier())->addUserStyleSheetToWorld(scriptWorld->coreWorld(), source, KURL(KURL(), url), toStringVector(whitelist), toStringVector(blacklist), injectedFrames);
    226 }
    227 
    228 void InjectedBundle::removeUserScript(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& url)
    229 {
    230     // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version.
    231     PageGroup::pageGroup(pageGroup->identifier())->removeUserScriptFromWorld(scriptWorld->coreWorld(), KURL(KURL(), url));
    232 }
    233 
    234 void InjectedBundle::removeUserStyleSheet(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& url)
    235 {
    236     // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version.
    237     PageGroup::pageGroup(pageGroup->identifier())->removeUserStyleSheetFromWorld(scriptWorld->coreWorld(), KURL(KURL(), url));
    238 }
    239 
    240 void InjectedBundle::removeUserScripts(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld)
    241 {
    242     PageGroup::pageGroup(pageGroup->identifier())->removeUserScriptsFromWorld(scriptWorld->coreWorld());
    243 }
    244 
    245 void InjectedBundle::removeUserStyleSheets(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld)
    246 {
    247     PageGroup::pageGroup(pageGroup->identifier())->removeUserStyleSheetsFromWorld(scriptWorld->coreWorld());
    248 }
    249 
    250 void InjectedBundle::removeAllUserContent(WebPageGroupProxy* pageGroup)
    251 {
    252     PageGroup::pageGroup(pageGroup->identifier())->removeAllUserContent();
    253 }
    254 
    255 void InjectedBundle::garbageCollectJavaScriptObjects()
    256 {
    257     gcController().garbageCollectNow();
    258 }
    259 
    260 void InjectedBundle::garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(bool waitUntilDone)
    261 {
    262     gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
    263 }
    264 
    265 size_t InjectedBundle::javaScriptObjectsCount()
    266 {
    267     JSLock lock(SilenceAssertionsOnly);
    268     return JSDOMWindow::commonJSGlobalData()->heap.objectCount();
    269 }
    270 
    271 void InjectedBundle::reportException(JSContextRef context, JSValueRef exception)
    272 {
    273     if (!context || !exception)
    274         return;
    275 
    276     JSLock lock(JSC::SilenceAssertionsOnly);
    277     JSC::ExecState* execState = toJS(context);
    278 
    279     // Make sure the context has a DOMWindow global object, otherwise this context didn't originate from a Page.
    280     if (!toJSDOMWindow(execState->lexicalGlobalObject()))
    281         return;
    282 
    283     WebCore::reportException(execState, toJS(execState, exception));
    284 }
    285 
    286 void InjectedBundle::didCreatePage(WebPage* page)
    287 {
    288     m_client.didCreatePage(this, page);
    289 }
    290 
    291 void InjectedBundle::willDestroyPage(WebPage* page)
    292 {
    293     m_client.willDestroyPage(this, page);
    294 }
    295 
    296 void InjectedBundle::didInitializePageGroup(WebPageGroupProxy* pageGroup)
    297 {
    298     m_client.didInitializePageGroup(this, pageGroup);
    299 }
    300 
    301 void InjectedBundle::didReceiveMessage(const String& messageName, APIObject* messageBody)
    302 {
    303     m_client.didReceiveMessage(this, messageName, messageBody);
    304 }
    305 
    306 void InjectedBundle::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
    307 {
    308     switch (messageID.get<InjectedBundleMessage::Kind>()) {
    309         case InjectedBundleMessage::PostMessage: {
    310             String messageName;
    311             RefPtr<APIObject> messageBody;
    312             InjectedBundleUserMessageDecoder messageDecoder(messageBody);
    313             if (!arguments->decode(CoreIPC::Out(messageName, messageDecoder)))
    314                 return;
    315 
    316             didReceiveMessage(messageName, messageBody.get());
    317             return;
    318         }
    319     }
    320 
    321     ASSERT_NOT_REACHED();
    322 }
    323 
    324 } // namespace WebKit
    325