Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
      3  * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 #include "FrameLoadDelegate.h"
     32 
     33 #include "AccessibilityController.h"
     34 #include "DumpRenderTree.h"
     35 #include "EventSender.h"
     36 #include "GCController.h"
     37 #include "LayoutTestController.h"
     38 #include "WorkQueueItem.h"
     39 #include "WorkQueue.h"
     40 #include <WebCore/COMPtr.h>
     41 #include <JavaScriptCore/Assertions.h>
     42 #include <JavaScriptCore/JavaScriptCore.h>
     43 #include <WebKit/WebKit.h>
     44 #include <wtf/Vector.h>
     45 #include <stdio.h>
     46 #include <string>
     47 
     48 using std::string;
     49 
     50 static FrameLoadDelegate* g_delegateWaitingOnTimer;
     51 
     52 string descriptionSuitableForTestResult(IWebFrame* webFrame)
     53 {
     54     COMPtr<IWebView> webView;
     55     if (FAILED(webFrame->webView(&webView)))
     56         return string();
     57 
     58     COMPtr<IWebFrame> mainFrame;
     59     if (FAILED(webView->mainFrame(&mainFrame)))
     60         return string();
     61 
     62     BSTR frameNameBSTR;
     63     if (FAILED(webFrame->name(&frameNameBSTR)) || toUTF8(frameNameBSTR).empty())
     64         return (webFrame == mainFrame) ? "main frame" : string();
     65 
     66     string frameName = (webFrame == mainFrame) ? "main frame" : "frame";
     67     frameName += " \"" + toUTF8(frameNameBSTR) + "\"";
     68 
     69     SysFreeString(frameNameBSTR);
     70     return frameName;
     71 }
     72 
     73 FrameLoadDelegate::FrameLoadDelegate()
     74     : m_refCount(1)
     75     , m_gcController(new GCController)
     76     , m_accessibilityController(new AccessibilityController)
     77 {
     78 }
     79 
     80 FrameLoadDelegate::~FrameLoadDelegate()
     81 {
     82 }
     83 
     84 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
     85 {
     86     *ppvObject = 0;
     87     if (IsEqualGUID(riid, IID_IUnknown))
     88         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
     89     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
     90         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
     91     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate))
     92         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this);
     93     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate2))
     94         *ppvObject = static_cast<IWebFrameLoadDelegatePrivate2*>(this);
     95     else
     96         return E_NOINTERFACE;
     97 
     98     AddRef();
     99     return S_OK;
    100 }
    101 
    102 ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void)
    103 {
    104     return ++m_refCount;
    105 }
    106 
    107 ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void)
    108 {
    109     ULONG newRef = --m_refCount;
    110     if (!newRef)
    111         delete(this);
    112 
    113     return newRef;
    114 }
    115 
    116 
    117 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame(
    118     /* [in] */ IWebView* webView,
    119     /* [in] */ IWebFrame* frame)
    120 {
    121     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    122         printf("%s - didStartProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
    123 
    124     // Make sure we only set this once per test.  If it gets cleared, and then set again, we might
    125     // end up doing two dumps for one test.
    126     if (!topLoadingFrame && !done)
    127         topLoadingFrame = frame;
    128 
    129     return S_OK;
    130 }
    131 
    132 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame(
    133     /* [in] */ IWebView *webView,
    134     /* [in] */ IWebFrame *frame)
    135 {
    136     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    137         printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
    138 
    139     return S_OK;
    140 }
    141 
    142 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError(
    143     /* [in] */ IWebView *webView,
    144     /* [in] */ IWebError *error,
    145     /* [in] */ IWebFrame *frame)
    146 {
    147     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    148         printf("%s - didFailProvisionalLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
    149 
    150     locationChangeDone(error, frame);
    151     return S_OK;
    152 }
    153 
    154 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame(
    155     /* [in] */ IWebView *webView,
    156     /* [in] */ IWebFrame *frame)
    157 {
    158     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    159         printf("%s - didCommitLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
    160 
    161     COMPtr<IWebViewPrivate> webViewPrivate;
    162     HRESULT hr = webView->QueryInterface(&webViewPrivate);
    163     if (FAILED(hr))
    164         return hr;
    165     webViewPrivate->updateFocusedAndActiveState();
    166 
    167     return S_OK;
    168 }
    169 
    170 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveTitle(
    171     /* [in] */ IWebView *webView,
    172     /* [in] */ BSTR title,
    173     /* [in] */ IWebFrame *frame)
    174 {
    175     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    176         printf("%s - didReceiveTitle: %S\n", descriptionSuitableForTestResult(frame).c_str(), title);
    177 
    178     if (::gLayoutTestController->dumpTitleChanges() && !done)
    179         printf("TITLE CHANGED: %S\n", title ? title : L"");
    180     return S_OK;
    181 }
    182 
    183 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didChangeIcons(
    184     /* [in] */ IWebView* webView,
    185     /* [in] */ IWebFrame* frame)
    186 {
    187     if (!done && gLayoutTestController->dumpIconChanges())
    188         printf("%s - didChangeIcons\n", descriptionSuitableForTestResult(frame).c_str());
    189 
    190     return S_OK;
    191 }
    192 
    193 void FrameLoadDelegate::processWork()
    194 {
    195     // if another load started, then wait for it to complete.
    196     if (topLoadingFrame)
    197         return;
    198 
    199     // if we finish all the commands, we're ready to dump state
    200     if (WorkQueue::shared()->processWork() && !::gLayoutTestController->waitToDump())
    201         dump();
    202 }
    203 
    204 void FrameLoadDelegate::resetToConsistentState()
    205 {
    206     m_accessibilityController->resetToConsistentState();
    207 }
    208 
    209 typedef Vector<COMPtr<FrameLoadDelegate> > DelegateVector;
    210 static DelegateVector& delegatesWithDelayedWork()
    211 {
    212     DEFINE_STATIC_LOCAL(DelegateVector, delegates, ());
    213     return delegates;
    214 }
    215 
    216 static UINT_PTR processWorkTimerID;
    217 
    218 static void CALLBACK processWorkTimer(HWND hwnd, UINT, UINT_PTR id, DWORD)
    219 {
    220     ASSERT_ARG(id, id == processWorkTimerID);
    221     ::KillTimer(hwnd, id);
    222     processWorkTimerID = 0;
    223 
    224     DelegateVector delegates;
    225     delegates.swap(delegatesWithDelayedWork());
    226 
    227     for (size_t i = 0; i < delegates.size(); ++i)
    228         delegates[i]->processWork();
    229 }
    230 
    231 void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
    232 {
    233     if (frame != topLoadingFrame)
    234         return;
    235 
    236     topLoadingFrame = 0;
    237     WorkQueue::shared()->setFrozen(true);
    238 
    239     if (::gLayoutTestController->waitToDump())
    240         return;
    241 
    242     if (WorkQueue::shared()->count()) {
    243         if (!processWorkTimerID)
    244             processWorkTimerID = ::SetTimer(0, 0, 0, processWorkTimer);
    245         delegatesWithDelayedWork().append(this);
    246         return;
    247     }
    248 
    249     dump();
    250 }
    251 
    252 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame(
    253     /* [in] */ IWebView* webView,
    254     /* [in] */ IWebFrame* frame)
    255 {
    256     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    257         printf("%s - didFinishLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
    258 
    259     locationChangeDone(0, frame);
    260     return S_OK;
    261 }
    262 
    263 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError(
    264     /* [in] */ IWebView* webView,
    265     /* [in] */ IWebError* error,
    266     /* [in] */ IWebFrame* frame)
    267 {
    268     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    269         printf("%s - didFailLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
    270 
    271     locationChangeDone(error, frame);
    272     return S_OK;
    273 }
    274 
    275 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willPerformClientRedirectToURL(
    276     /* [in] */ IWebView *webView,
    277     /* [in] */ BSTR url,
    278     /* [in] */ double delaySeconds,
    279     /* [in] */ DATE fireDate,
    280     /* [in] */ IWebFrame *frame)
    281 {
    282     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    283         printf("%s - willPerformClientRedirectToURL: %S \n", descriptionSuitableForTestResult(frame).c_str(),
    284                 urlSuitableForTestResult(std::wstring(url, ::SysStringLen(url))).c_str());
    285 
    286     return S_OK;
    287 }
    288 
    289 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCancelClientRedirectForFrame(
    290     /* [in] */ IWebView *webView,
    291     /* [in] */ IWebFrame *frame)
    292 {
    293     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    294         printf("%s - didCancelClientRedirectForFrame\n", descriptionSuitableForTestResult(frame).c_str());
    295 
    296     return S_OK;
    297 }
    298 
    299 
    300 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame(
    301     /* [in] */ IWebView *webView,
    302     /* [in] */ IWebFrame *frame)
    303 {
    304     return E_NOTIMPL;
    305 }
    306 
    307 HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*)
    308 {
    309     return E_NOTIMPL;
    310 }
    311 
    312 HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world)
    313 {
    314     ASSERT_ARG(webView, webView);
    315     ASSERT_ARG(frame, frame);
    316     ASSERT_ARG(world, world);
    317     if (!webView || !frame || !world)
    318         return E_POINTER;
    319 
    320     COMPtr<IWebScriptWorld> standardWorld;
    321     if (FAILED(world->standardWorld(&standardWorld)))
    322         return S_OK;
    323 
    324     if (world == standardWorld)
    325         didClearWindowObjectForFrameInStandardWorld(frame);
    326     else
    327         didClearWindowObjectForFrameInIsolatedWorld(frame, world);
    328     return S_OK;
    329 }
    330 
    331 void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world)
    332 {
    333     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
    334     if (!framePrivate)
    335         return;
    336 
    337     JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world);
    338     if (!ctx)
    339         return;
    340 
    341     JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
    342     if (!globalObject)
    343         return;
    344 
    345     JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
    346     return;
    347 }
    348 
    349 void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame)
    350 {
    351     JSGlobalContextRef context = frame->globalContext();
    352     JSObjectRef windowObject = JSContextGetGlobalObject(context);
    353 
    354     IWebFrame* parentFrame = 0;
    355     frame->parentFrame(&parentFrame);
    356 
    357     JSValueRef exception = 0;
    358 
    359     ::gLayoutTestController->makeWindowObject(context, windowObject, &exception);
    360     ASSERT(!exception);
    361 
    362     m_gcController->makeWindowObject(context, windowObject, &exception);
    363     ASSERT(!exception);
    364 
    365     m_accessibilityController->makeWindowObject(context, windowObject, &exception);
    366     ASSERT(!exception);
    367 
    368     JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
    369     JSValueRef eventSender = makeEventSender(context, !parentFrame);
    370     JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
    371     JSStringRelease(eventSenderStr);
    372 }
    373 
    374 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame(
    375     /* [in] */ IWebView *sender,
    376     /* [in] */ IWebFrame *frame)
    377 {
    378     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    379         printf("%s - didFinishDocumentLoadForFrame\n",
    380                 descriptionSuitableForTestResult(frame).c_str());
    381     if (!done) {
    382         COMPtr<IWebFramePrivate> webFramePrivate;
    383         HRESULT hr = frame->QueryInterface(&webFramePrivate);
    384         if (FAILED(hr))
    385             return hr;
    386         unsigned pendingFrameUnloadEvents;
    387         hr = webFramePrivate->pendingFrameUnloadEventCount(&pendingFrameUnloadEvents);
    388         if (FAILED(hr))
    389             return hr;
    390         if (pendingFrameUnloadEvents)
    391             printf("%s - has %u onunload handler(s)\n",
    392                     descriptionSuitableForTestResult(frame).c_str(), pendingFrameUnloadEvents);
    393     }
    394 
    395     return S_OK;
    396 }
    397 
    398 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame(
    399     /* [in] */ IWebView *sender,
    400     /* [in] */ IWebFrame *frame)
    401 {
    402     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    403         printf("%s - didHandleOnloadEventsForFrame\n",
    404                 descriptionSuitableForTestResult(frame).c_str());
    405 
    406     return S_OK;
    407 }
    408 
    409 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFirstVisuallyNonEmptyLayoutInFrame(
    410     /* [in] */ IWebView *sender,
    411     /* [in] */ IWebFrame *frame)
    412 {
    413     return S_OK;
    414 }
    415 
    416 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didDisplayInsecureContent(
    417     /* [in] */ IWebView *sender)
    418 {
    419     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    420         printf("didDisplayInsecureContent\n");
    421 
    422     return S_OK;
    423 }
    424 
    425 HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didRunInsecureContent(
    426     /* [in] */ IWebView *sender,
    427     /* [in] */ IWebSecurityOrigin *origin)
    428 {
    429     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
    430         printf("didRunInsecureContent\n");
    431 
    432     return S_OK;
    433 }
    434 
    435