[Win] Implement a page load profiling tool
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 13 Oct 2014 23:10:20 +0000 (23:10 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 13 Oct 2014 23:10:20 +0000 (23:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=137673

Reviewed by Dean Jackson.

Source/WebKit/win:

Add a new predicate (isMainFrame) to the IWebFrame interface so
that we can make decisions about a frames position in the page
load hierarchy in client programs.

* Interfaces/IWebFrame.idl: Added new isMainFrame
predicate to interface definition.
* WebFrame.cpp:
(WebFrame::isMainFrame): Added.
* WebFrame.h:

Tools:

Add a tool to capture and summarize page load statistics.

* WinLauncher/Common.cpp:
(parseCommandLine): Move from WinMain.cpp so that it can
be shared with internal tools.
* WinLauncher/PageLoadTestClient.cpp: Added.
(PageLoadTestClient::PageLoadTestClient):
(PageLoadTestClient::pageLoadStartedAtTime):
(PageLoadTestClient::didStartProvisionalLoad):
(PageLoadTestClient::didCommitLoad):
(PageLoadTestClient::didFirstLayoutForMainFrame):
(PageLoadTestClient::didHandleOnLoadEvents):
(PageLoadTestClient::didFinishLoad):
(PageLoadTestClient::didFailLoad):
(PageLoadTestClient::didInitiateResourceLoad):
(PageLoadTestClient::didEndResourceLoad):
(PageLoadTestClient::pageLoadEndedAtTime):
(PageLoadTestClient::endPageLoad):
(PageLoadTestClient::clearPageLoadState):
(PageLoadTestClient::shouldConsiderPageLoadEnded):
(PageLoadTestClient::maybeEndPageLoadSoon):
(PageLoadTestClient::setPageURL):
(PageLoadTestClient::dumpRunStatistics):
* WinLauncher/PrintWebUIDelegate.cpp:
(PrintWebUIDelegate::createWebViewWithRequest): Handle
nullptr URL properly.
* WinLauncher/ResourceLoadDelegate.cpp: Added.
(ResourceLoadDelegate::QueryInterface):
(ResourceLoadDelegate::AddRef):
(ResourceLoadDelegate::Release):
(ResourceLoadDelegate::identifierForInitialRequest):
(ResourceLoadDelegate::willSendRequest):
(ResourceLoadDelegate::didReceiveAuthenticationChallenge):
(ResourceLoadDelegate::didCancelAuthenticationChallenge):
(ResourceLoadDelegate::didReceiveResponse):
(ResourceLoadDelegate::didReceiveContentLength):
(ResourceLoadDelegate::didFinishLoadingFromDataSource):
(ResourceLoadDelegate::didFailLoadingWithError):
(ResourceLoadDelegate::plugInFailedWithError):
* WinLauncher/ResourceLoadDelegate.h: Added.
(ResourceLoadDelegate::ResourceLoadDelegate):
* WinLauncher/WinLauncher.cpp:
(WinLauncher::WinLauncher): Accept argument to indicate we want to capture
page loading statistics.
(WinLauncher::setFrameLoadDelegatePrivate): Get rid of stub implementation
and set private load delegate state.
(WinLauncher::setResourceLoadDelegate): Replace stub with a full implementation
that sets the view's resource load delegate.
(WinLauncher::loadURL): If no URL is passed, load the test document.
* WinLauncher/WinLauncher.h:
(WinLauncher::pageLoadTestClient):
* WinLauncher/WinLauncher.vcxproj/WinLauncherLib.vcxproj: Updated for new source files.
* WinLauncher/WinLauncher.vcxproj/WinLauncherLib.vcxproj.filters: Ditto.
* WinLauncher/WinLauncherWebHost.cpp:
(WinLauncherWebHost::updateAddressBar): Hook into page load statistics routine.
(WinLauncherWebHost::loadURL): Moved 'SendMessage' call to its own method so that
it could be used from other source files.
(WinLauncherWebHost::didFinishLoadForFrame): Added overload to capture statistics.
(WinLauncherWebHost::didStartProvisionalLoadForFrame): Ditto.
(WinLauncherWebHost::didFailLoadWithError): Ditto.
(WinLauncherWebHost::didHandleOnloadEventsForFrame): Ditto.
(WinLauncherWebHost::didFirstLayoutInFrame): Ditto.
(WinLauncherWebHost::didFinishDocumentLoadForFrame): Ditto.
(WinLauncherWebHost::didFirstVisuallyNonEmptyLayoutInFrame): Ditto.
(WinLauncherWebHost::didStartProvisionalLoadForFrame): Deleted.
* WinLauncher/WinLauncherWebHost.h:
* WinLauncher/WinMain.cpp:
(wWinMain): Create and use new delegates for gathering page load data.
* WinLauncher/stdafx.h: Need to add <wtf/Platform> include for various macros used in build.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@174664 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
Source/WebKit/win/ChangeLog
Source/WebKit/win/Interfaces/IWebFrame.idl
Source/WebKit/win/WebFrame.cpp
Source/WebKit/win/WebFrame.h
Tools/ChangeLog
Tools/WinLauncher/Common.cpp
Tools/WinLauncher/PageLoadTestClient.cpp [new file with mode: 0644]
Tools/WinLauncher/PageLoadTestClient.h [new file with mode: 0644]
Tools/WinLauncher/PrintWebUIDelegate.cpp
Tools/WinLauncher/ResourceLoadDelegate.cpp [new file with mode: 0644]
Tools/WinLauncher/ResourceLoadDelegate.h [new file with mode: 0644]
Tools/WinLauncher/WinLauncher.cpp
Tools/WinLauncher/WinLauncher.h
Tools/WinLauncher/WinLauncher.vcxproj/WinLauncherLib.vcxproj
Tools/WinLauncher/WinLauncher.vcxproj/WinLauncherLib.vcxproj.filters
Tools/WinLauncher/WinLauncherWebHost.cpp
Tools/WinLauncher/WinLauncherWebHost.h
Tools/WinLauncher/WinMain.cpp
Tools/WinLauncher/stdafx.h

index 3e1eb2e..1834d8d 100644 (file)
@@ -1,3 +1,20 @@
+2014-10-13  Brent Fulgham  <bfulgham@apple.com>
+
+        [Win] Implement a page load profiling tool
+        https://bugs.webkit.org/show_bug.cgi?id=137673
+
+        Reviewed by Dean Jackson.
+
+        Add a new predicate (isMainFrame) to the IWebFrame interface so
+        that we can make decisions about a frames position in the page
+        load hierarchy in client programs.
+
+        * Interfaces/IWebFrame.idl: Added new isMainFrame
+        predicate to interface definition.
+        * WebFrame.cpp:
+        (WebFrame::isMainFrame): Added.
+        * WebFrame.h:
+
 2014-10-13  Chris Dumez  <cdumez@apple.com>
 
         Use is<>() / downcast<>() for PlatformCALayer subclasses
index b6ed633..6382279 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2014 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -268,4 +268,10 @@ interface IWebFrame : IUnknown
         - (DOMWindow *)DOMWindow;
     */
     HRESULT DOMWindow([out, retval] IDOMWindow** window);
+
+    /*!
+    @method isMainFrame
+    @description Returns TRUE if the frame is the main frame.
+    */
+    HRESULT isMainFrame([out, retval] BOOL* flag);
 }
index 5d21fd0..8cfc3a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2009, 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2009, 2011, 2013-2014 Apple Inc. All rights reserved.
  * Copyright (C) Research In Motion Limited 2009. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -2097,3 +2097,13 @@ void WebFrame::updateBackground()
     coreFrame->view()->updateBackgroundRecursively(backgroundColor, webView()->transparent());
 }
 
+HRESULT WebFrame::isMainFrame(BOOL* value)
+{
+    if (!value)
+        return E_POINTER;
+
+    Frame* coreFrame = core(this);
+    *value = coreFrame->isMainFrame();
+
+    return S_OK;
+}
index 8d82c3d..4f9ca9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2011, 2013-2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -287,6 +287,8 @@ public:
     virtual HRESULT STDMETHODCALLTYPE selectAll();
     
     virtual HRESULT STDMETHODCALLTYPE deselectAll();
+
+    virtual HRESULT STDMETHODCALLTYPE isMainFrame(BOOL*);
     
     // FrameLoaderClient
     virtual void frameLoaderDestroyed();
index ed126f8..b0c56f0 100644 (file)
@@ -1,3 +1,80 @@
+2014-10-13  Brent Fulgham  <bfulgham@apple.com>
+
+        [Win] Implement a page load profiling tool
+        https://bugs.webkit.org/show_bug.cgi?id=137673
+
+        Reviewed by Dean Jackson.
+
+        Add a tool to capture and summarize page load statistics.
+
+        * WinLauncher/Common.cpp:
+        (parseCommandLine): Move from WinMain.cpp so that it can
+        be shared with internal tools.
+        * WinLauncher/PageLoadTestClient.cpp: Added.
+        (PageLoadTestClient::PageLoadTestClient):
+        (PageLoadTestClient::pageLoadStartedAtTime):
+        (PageLoadTestClient::didStartProvisionalLoad):
+        (PageLoadTestClient::didCommitLoad):
+        (PageLoadTestClient::didFirstLayoutForMainFrame):
+        (PageLoadTestClient::didHandleOnLoadEvents):
+        (PageLoadTestClient::didFinishLoad):
+        (PageLoadTestClient::didFailLoad):
+        (PageLoadTestClient::didInitiateResourceLoad):
+        (PageLoadTestClient::didEndResourceLoad):
+        (PageLoadTestClient::pageLoadEndedAtTime):
+        (PageLoadTestClient::endPageLoad):
+        (PageLoadTestClient::clearPageLoadState):
+        (PageLoadTestClient::shouldConsiderPageLoadEnded):
+        (PageLoadTestClient::maybeEndPageLoadSoon):
+        (PageLoadTestClient::setPageURL):
+        (PageLoadTestClient::dumpRunStatistics):
+        * WinLauncher/PrintWebUIDelegate.cpp:
+        (PrintWebUIDelegate::createWebViewWithRequest): Handle
+        nullptr URL properly.
+        * WinLauncher/ResourceLoadDelegate.cpp: Added.
+        (ResourceLoadDelegate::QueryInterface):
+        (ResourceLoadDelegate::AddRef):
+        (ResourceLoadDelegate::Release):
+        (ResourceLoadDelegate::identifierForInitialRequest):
+        (ResourceLoadDelegate::willSendRequest):
+        (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+        (ResourceLoadDelegate::didCancelAuthenticationChallenge):
+        (ResourceLoadDelegate::didReceiveResponse):
+        (ResourceLoadDelegate::didReceiveContentLength):
+        (ResourceLoadDelegate::didFinishLoadingFromDataSource):
+        (ResourceLoadDelegate::didFailLoadingWithError):
+        (ResourceLoadDelegate::plugInFailedWithError):
+        * WinLauncher/ResourceLoadDelegate.h: Added.
+        (ResourceLoadDelegate::ResourceLoadDelegate):
+        * WinLauncher/WinLauncher.cpp:
+        (WinLauncher::WinLauncher): Accept argument to indicate we want to capture
+        page loading statistics.
+        (WinLauncher::setFrameLoadDelegatePrivate): Get rid of stub implementation
+        and set private load delegate state.
+        (WinLauncher::setResourceLoadDelegate): Replace stub with a full implementation
+        that sets the view's resource load delegate.
+        (WinLauncher::loadURL): If no URL is passed, load the test document.
+        * WinLauncher/WinLauncher.h:
+        (WinLauncher::pageLoadTestClient):
+        * WinLauncher/WinLauncher.vcxproj/WinLauncherLib.vcxproj: Updated for new source files.
+        * WinLauncher/WinLauncher.vcxproj/WinLauncherLib.vcxproj.filters: Ditto.
+        * WinLauncher/WinLauncherWebHost.cpp:
+        (WinLauncherWebHost::updateAddressBar): Hook into page load statistics routine.
+        (WinLauncherWebHost::loadURL): Moved 'SendMessage' call to its own method so that
+        it could be used from other source files.
+        (WinLauncherWebHost::didFinishLoadForFrame): Added overload to capture statistics.
+        (WinLauncherWebHost::didStartProvisionalLoadForFrame): Ditto.
+        (WinLauncherWebHost::didFailLoadWithError): Ditto.
+        (WinLauncherWebHost::didHandleOnloadEventsForFrame): Ditto.
+        (WinLauncherWebHost::didFirstLayoutInFrame): Ditto.
+        (WinLauncherWebHost::didFinishDocumentLoadForFrame): Ditto.
+        (WinLauncherWebHost::didFirstVisuallyNonEmptyLayoutInFrame): Ditto.
+        (WinLauncherWebHost::didStartProvisionalLoadForFrame): Deleted.
+        * WinLauncher/WinLauncherWebHost.h:
+        * WinLauncher/WinMain.cpp:
+        (wWinMain): Create and use new delegates for gathering page load data.
+        * WinLauncher/stdafx.h: Need to add <wtf/Platform> include for various macros used in build.
+
 2014-10-13  Simon Fraser  <simon.fraser@apple.com>
 
         Improve the test image diffs page
index 7ac71aa..dd3feaf 100644 (file)
@@ -29,6 +29,7 @@
 #include "AccessibilityDelegate.h"
 #include "DOMDefaultImpl.h"
 #include "PrintWebUIDelegate.h"
+#include "ResourceLoadDelegate.h"
 #include "WinLauncher.h"
 #include "WinLauncherReplace.h"
 #include <WebKit/WebKitCOMAPI.h>
@@ -685,6 +686,26 @@ static void updateStatistics(HWND dialog)
         setWindowText(dialog, IDC_SITE_ICONS_WITH_DATA, count);
 }
 
+static void parseCommandLine(bool& usesLayeredWebView, bool& useFullDesktop, bool& pageLoadTesting, _bstr_t& requestedURL)
+{
+    usesLayeredWebView = false;
+    useFullDesktop = false;
+    pageLoadTesting = false;
+
+    int argc = 0;
+    WCHAR** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+    for (int i = 1; i < argc; ++i) {
+        if (!wcsicmp(argv[i], L"--transparent"))
+            usesLayeredWebView = true;
+        else if (!wcsicmp(argv[i], L"--desktop"))
+            useFullDesktop = true;
+        else if (!requestedURL)
+            requestedURL = argv[i];
+        else if (!wcsicmp(argv[i], L"--performance"))
+            pageLoadTesting = true;
+    }
+}
+
 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpstrCmdLine, int nCmdShow)
 {
     return wWinMain(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow);
diff --git a/Tools/WinLauncher/PageLoadTestClient.cpp b/Tools/WinLauncher/PageLoadTestClient.cpp
new file mode 100644 (file)
index 0000000..408d1f2
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+* Copyright (C) 2014 Apple Inc.  All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "stdafx.h"
+#include "PageLoadTestClient.h"
+
+#include "WinLauncher.h"
+#include <WebCore/PlatformExportMacros.h>
+#include <wtf/Assertions.h>
+#include <wtf/FilePrintStream.h>
+#include <cmath>
+
+static const CFTimeInterval waitForNewResourceLoadDuration = 0.1;
+
+PageLoadTestClient::PageLoadTestClient(WinLauncher* host, bool pageLoadTesting)
+    : m_host(host)
+    , m_pageLoadEndTime(0)
+    , m_totalTime(0)
+    , m_totalSquareRootsOfTime(0)
+    , m_longestTime(0)
+    , m_geometricMeanProductSum(1.0)
+    , m_frames(0)
+    , m_onLoadEvents(0)
+    , m_currentURLIndex(0)
+    , m_currentRepetition(0)
+    , m_pagesTimed(0)
+    , m_repetitions(pageLoadTesting ? 20 : 1)
+    , m_waitForLoadToReallyEnd(this, &PageLoadTestClient::endPageLoad)
+    , m_currentPageLoadFinished(false)
+    , m_pageLoadTesting(pageLoadTesting)
+{
+}
+
+void PageLoadTestClient::pageLoadStartedAtTime(CFAbsoluteTime startTime)
+{
+    m_startTimes.append(startTime);
+}
+
+void PageLoadTestClient::didStartProvisionalLoad(IWebFrame& frame)
+{
+    BOOL mainFrame;
+    if (FAILED(frame.isMainFrame(&mainFrame)))
+        return;
+
+    if (mainFrame) {
+        clearPageLoadState();
+        pageLoadStartedAtTime(CFAbsoluteTimeGetCurrent());
+    }
+}
+
+void PageLoadTestClient::didCommitLoad()
+{
+    ++m_frames;
+}
+
+void PageLoadTestClient::didFirstLayoutForMainFrame()
+{
+    // Nothing to do
+}
+
+void PageLoadTestClient::didHandleOnLoadEvents()
+{
+    ++m_onLoadEvents;
+    maybeEndPageLoadSoon();
+}
+
+void PageLoadTestClient::didFinishLoad()
+{
+    m_currentPageLoadFinished = true;
+    maybeEndPageLoadSoon();
+}
+
+void PageLoadTestClient::didFailLoad()
+{
+    --m_frames;
+}
+
+void PageLoadTestClient::didInitiateResourceLoad(uint64_t resourceIdentifier)
+{
+    if (!resourceIdentifier) {
+        WTFLogAlways("Saw resourceIdentifier=0. This must be a bug in the loader code. The results may be invalid.");
+        return;
+    }
+    m_loadingSubresources.add(resourceIdentifier);
+}
+
+void PageLoadTestClient::didEndResourceLoad(uint64_t resourceIdentifier)
+{
+    if (!resourceIdentifier) {
+        WTFLogAlways("Saw resourceIdentifier=0. This must be a bug in the loader code. The results may be invalid.");
+        return;
+    }
+    auto found = m_loadingSubresources.find(resourceIdentifier);
+    if (found == m_loadingSubresources.end())
+        return;
+    m_loadingSubresources.remove(found);
+    maybeEndPageLoadSoon();
+}
+
+void PageLoadTestClient::pageLoadEndedAtTime(CFAbsoluteTime endTime)
+{
+    ASSERT(m_endTimes.size() == m_currentRepetition);
+    m_endTimes.append(endTime);
+
+    if (m_currentRepetition) {
+        CFTimeInterval pageLoadTime = (m_endTimes[m_currentRepetition] - m_startTimes[m_currentRepetition]);
+        if (pageLoadTime > m_longestTime)
+            m_longestTime = pageLoadTime;
+
+        m_totalTime += pageLoadTime;
+        m_totalSquareRootsOfTime += std::sqrt(pageLoadTime);
+        m_pagesTimed++;
+        m_geometricMeanProductSum *= pageLoadTime;
+    }
+
+    if (m_pageLoadTesting) {
+        ++m_currentRepetition;
+        if (m_currentRepetition != m_repetitions)
+            m_host->loadURL(m_url);
+        else {
+            dumpRunStatistics();
+            m_host->exitProgram();
+        }
+    }
+}
+
+void PageLoadTestClient::endPageLoad(Timer<PageLoadTestClient>* timer)
+{
+    ASSERT_UNUSED(timer, timer == &m_waitForLoadToReallyEnd);
+
+    if (!shouldConsiderPageLoadEnded())
+        return;
+    pageLoadEndedAtTime(m_pageLoadEndTime);
+    clearPageLoadState();
+}
+
+void PageLoadTestClient::clearPageLoadState()
+{
+    m_currentPageLoadFinished = false;
+    m_frames = 0;
+    m_onLoadEvents = 0;
+    m_pageLoadEndTime = 0;
+    m_loadingSubresources.clear();
+    m_waitForLoadToReallyEnd.invalidate();
+}
+
+bool PageLoadTestClient::shouldConsiderPageLoadEnded() const
+{
+    return m_currentPageLoadFinished && m_onLoadEvents == m_frames && m_loadingSubresources.isEmpty();
+}
+
+void PageLoadTestClient::maybeEndPageLoadSoon()
+{
+    if (!shouldConsiderPageLoadEnded())
+        return;
+    m_pageLoadEndTime = CFAbsoluteTimeGetCurrent();
+    if (m_waitForLoadToReallyEnd.isValid())
+        m_waitForLoadToReallyEnd.invalidate();
+    m_waitForLoadToReallyEnd.schedule(waitForNewResourceLoadDuration, false);
+}
+
+#if OS(WINDOWS)
+void PageLoadTestClient::setPageURL(const _bstr_t& pageURL)
+{
+    m_url = pageURL;
+}
+#endif
+
+void PageLoadTestClient::dumpRunStatistics()
+{
+    const long maxPathLength = 1024;
+
+    char filenameSuffix[maxPathLength + 1];
+
+#if PLATFORM(WIN)
+    DWORD pid = GetCurrentProcessId();
+    _snprintf(filenameSuffix, sizeof(filenameSuffix), ".%d.txt", pid);
+#else
+    long pid = getpid();
+    snprintf(filenameSuffix, sizeof(filenameSuffix), ".%d.txt", pid);
+#endif
+
+    const char* filename = "webkit_performance_log";
+    char actualFilename[maxPathLength + 1];
+
+#if PLATFORM(WIN)
+    _snprintf(actualFilename, sizeof(actualFilename), "%s%s", filename, filenameSuffix);
+#else
+    snprintf(actualFilename, sizeof(actualFilename), "%s%s", filename, filenameSuffix);
+#endif
+
+    std::unique_ptr<WTF::FilePrintStream> file = WTF::FilePrintStream::open(actualFilename, "w");
+    if (!file) {
+        WTFLogAlways("Warning: Could not open page load performance data file %s for writing.\n", actualFilename);
+        return;
+    }
+
+    WTFLogAlways("*** Page load performance data output to \"%s\" ***\n", actualFilename);
+
+    file->print("INDIVIDUAL URL LOAD TIMES:\n");
+
+    CFTimeInterval pageLoadTime = m_endTimes.last() - m_startTimes.last();
+    file->printf("Load Time = %.1f ms\t%s\n", pageLoadTime * 1000.0, static_cast<const char*>(m_url));
+
+    double meanTime = 0;
+    double squareMeanRootTime = 0;
+    double geometricMeanTime = 0;
+    if (m_pagesTimed) {
+        meanTime = m_totalTime / m_pagesTimed;
+        squareMeanRootTime = (m_totalSquareRootsOfTime / m_pagesTimed) * (m_totalSquareRootsOfTime / m_pagesTimed);
+        geometricMeanTime = std::pow(m_geometricMeanProductSum, (1.0 / m_pagesTimed));
+    }
+
+    file->printf("FINISHED:    Total Time = %.1f ms\n", m_totalTime * 1000.0);
+    file->printf("           Longest Time = %.1f ms\n", m_longestTime * 1000.0);
+    file->printf("              Mean Time = %.1f ms\n", meanTime * 1000.0);
+    file->printf("  Square-Mean-Root Time = %.1f ms\n", squareMeanRootTime * 1000.0);
+    file->printf("    Geometric Mean Time = %.1f ms\n", geometricMeanTime * 1000.0);
+    file->printf("---------------------------------------------------------------------------------------------------\n");
+
+    file->flush();
+}
diff --git a/Tools/WinLauncher/PageLoadTestClient.h b/Tools/WinLauncher/PageLoadTestClient.h
new file mode 100644 (file)
index 0000000..763387f
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+* Copyright (C) 2014 Apple Inc. All Rights Reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PageLoadTestClient_h
+#define PageLoadTestClient_h
+
+#include <CoreFoundation/CFDate.h>
+#include <WebKit/WebKit.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+
+template <class TimerFiredClass>
+class Timer {
+    WTF_MAKE_NONCOPYABLE(Timer);
+public:
+    typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
+
+    Timer(TimerFiredClass* object, TimerFiredFunction function)
+        : m_object(object)
+        , m_function(function)
+    {
+        ASSERT_ARG(object, object);
+        ASSERT_ARG(function, function);
+    }
+
+    ~Timer() { invalidate(); }
+
+    void invalidate()
+    {
+        if (!isValid())
+            return;
+
+        CFRunLoopTimerInvalidate(m_timer.get());
+        m_timer = nullptr;
+    }
+
+    bool isValid() const
+    {
+        return m_timer && CFRunLoopTimerIsValid(m_timer.get());
+    }
+
+    void schedule(CFTimeInterval interval, bool repeating)
+    {
+        ASSERT(!isValid());
+
+        CFTimeInterval repeatInterval = repeating ? interval : 0;
+        CFRunLoopTimerContext context = { 0, this, 0, 0, 0 };
+        m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, repeatInterval, 0, 0, runLoopTimerFired, &context));
+
+        CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_timer.get(), kCFRunLoopCommonModes);
+    }
+
+private:
+    void fire() { (m_object->*m_function)(this); }
+
+    static void runLoopTimerFired(CFRunLoopTimerRef timerRef, void* info)
+    {
+        Timer* timer = static_cast<Timer*>(info);
+        ASSERT_ARG(timerRef, timer->m_timer == timerRef);
+
+        if (!CFRunLoopTimerDoesRepeat(timerRef))
+            CFRunLoopTimerInvalidate(timerRef);
+
+#ifdef __OBJC__
+        @autoreleasepool
+#endif
+        {
+            timer->fire();
+        }
+    }
+
+    TimerFiredClass* m_object;
+    TimerFiredFunction m_function;
+
+    RetainPtr<CFRunLoopTimerRef> m_timer;
+};
+
+class WinLauncher;
+
+class PageLoadTestClient {
+    WTF_MAKE_NONCOPYABLE(PageLoadTestClient);
+public:
+    PageLoadTestClient(WinLauncher* host, bool pageLoadTesting = false);
+
+#if OS(WINDOWS)
+    void setPageURL(const _bstr_t&);
+#endif
+
+    void didStartProvisionalLoad(IWebFrame&);
+    void didCommitLoad();
+    void didFirstLayoutForMainFrame();
+    void didHandleOnLoadEvents();
+    void didFinishLoad();
+    void didFailLoad();
+    void didInitiateResourceLoad(uint64_t);
+    void didEndResourceLoad(uint64_t);
+
+private:
+    void endPageLoad(Timer<PageLoadTestClient>*);
+    void maybeEndPageLoadSoon();
+    void clearPageLoadState();
+    bool shouldConsiderPageLoadEnded() const;
+
+    virtual void pageLoadStartedAtTime(CFAbsoluteTime);
+    virtual void pageLoadEndedAtTime(CFAbsoluteTime);
+    void dumpRunStatistics();
+
+    WinLauncher* m_host;
+    CFAbsoluteTime m_pageLoadEndTime;
+    CFTimeInterval m_totalTime;
+    CFTimeInterval m_totalSquareRootsOfTime;
+    CFTimeInterval m_longestTime;
+    Vector<CFAbsoluteTime> m_startTimes;
+    Vector<CFAbsoluteTime> m_endTimes;
+    HashSet<uint64_t> m_loadingSubresources;
+    Timer<PageLoadTestClient> m_waitForLoadToReallyEnd;
+#if OS(WINDOWS)
+    _bstr_t m_url;
+#endif
+    double m_geometricMeanProductSum;
+    unsigned m_frames;
+    unsigned m_onLoadEvents;
+    unsigned m_currentURLIndex;
+    unsigned m_currentRepetition;
+    unsigned m_pagesTimed;
+    unsigned m_repetitions;
+
+    bool m_currentPageLoadFinished;
+    bool m_pageLoadTesting;
+};
+
+#endif // PageLoadTestClient_h
index 80a0fc2..5c867a2 100644 (file)
@@ -49,7 +49,7 @@ HRESULT STDMETHODCALLTYPE PrintWebUIDelegate::runJavaScriptConfirmPanelWithMessa
     return S_OK;
 }
 
-HRESULT STDMETHODCALLTYPE PrintWebUIDelegate::createWebViewWithRequest(IWebView*, IWebURLRequest* request, IWebView**)
+HRESULT PrintWebUIDelegate::createWebViewWithRequest(IWebView*, IWebURLRequest* request, IWebView**)
 {
     if (!request)
         return E_POINTER;
@@ -64,6 +64,9 @@ HRESULT STDMETHODCALLTYPE PrintWebUIDelegate::createWebViewWithRequest(IWebView*
     if (FAILED(hr))
         return E_FAIL;
 
+    if (!url)
+        return S_OK;
+
     std::wstring command = std::wstring(L"\"") + executablePath + L"\" " + (const wchar_t*)url;
 
     PROCESS_INFORMATION processInformation;
diff --git a/Tools/WinLauncher/ResourceLoadDelegate.cpp b/Tools/WinLauncher/ResourceLoadDelegate.cpp
new file mode 100644 (file)
index 0000000..7e26fc4
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+* Copyright (C) 2014 Apple Inc. All Rights Reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "stdafx.h"
+#include "ResourceLoadDelegate.h"
+
+#include "PageLoadTestClient.h"
+#include "WinLauncher.h"
+#include <WebKit/WebKitCOMAPI.h>
+#include <comip.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <objbase.h>
+#include <shlwapi.h>
+#include <wininet.h>
+
+HRESULT ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+    *ppvObject = 0;
+    if (IsEqualIID(riid, IID_IUnknown))
+        *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
+    else if (IsEqualIID(riid, IID_IWebResourceLoadDelegate))
+        *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
+    else
+        return E_NOINTERFACE;
+
+    AddRef();
+    return S_OK;
+}
+
+ULONG ResourceLoadDelegate::AddRef(void)
+{
+    return ++m_refCount;
+}
+
+ULONG ResourceLoadDelegate::Release(void)
+{
+    ULONG newRef = --m_refCount;
+    if (!newRef)
+        delete this;
+
+    return newRef;
+}
+
+HRESULT ResourceLoadDelegate::identifierForInitialRequest(IWebView*, IWebURLRequest*, IWebDataSource*, unsigned long identifier)
+{
+    if (!m_client)
+        return E_FAIL;
+
+    m_client->pageLoadTestClient().didInitiateResourceLoad(identifier);
+
+    return S_OK;
+}
+
+HRESULT ResourceLoadDelegate::willSendRequest(IWebView*, unsigned long, IWebURLRequest*, IWebURLResponse*, IWebDataSource*, IWebURLRequest**)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT ResourceLoadDelegate::didReceiveAuthenticationChallenge(IWebView*, unsigned long, IWebURLAuthenticationChallenge*, IWebDataSource*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT ResourceLoadDelegate::didCancelAuthenticationChallenge(IWebView*, unsigned long, IWebURLAuthenticationChallenge*, IWebDataSource*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT ResourceLoadDelegate::didReceiveResponse(IWebView*, unsigned long, IWebURLResponse*, IWebDataSource*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT ResourceLoadDelegate::didReceiveContentLength(IWebView*, unsigned long, UINT, IWebDataSource*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT ResourceLoadDelegate::didFinishLoadingFromDataSource(IWebView*, unsigned long identifier, IWebDataSource*)
+{
+    if (!m_client)
+        return E_FAIL;
+
+    m_client->pageLoadTestClient().didEndResourceLoad(identifier);
+
+    return S_OK;
+}
+
+HRESULT ResourceLoadDelegate::didFailLoadingWithError(IWebView*, unsigned long identifier, IWebError*, IWebDataSource*)
+{
+    if (!m_client)
+        return E_FAIL;
+
+    m_client->pageLoadTestClient().didEndResourceLoad(identifier);
+
+    return S_OK;
+}
+
+HRESULT ResourceLoadDelegate::plugInFailedWithError(IWebView*, IWebError*, IWebDataSource*)
+{
+    return E_NOTIMPL;
+}
diff --git a/Tools/WinLauncher/ResourceLoadDelegate.h b/Tools/WinLauncher/ResourceLoadDelegate.h
new file mode 100644 (file)
index 0000000..c5257f5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+* Copyright (C) 2014 Apple Inc. All Rights Reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ResourceLoadDelegate_h
+#define ResourceLoadDelegate_h
+
+#include <WebKit/WebKit.h>
+
+class WinLauncher;
+
+class ResourceLoadDelegate : public IWebResourceLoadDelegate {
+public:
+    ResourceLoadDelegate(WinLauncher* client)
+        : m_refCount(1), m_client(client) { }
+
+    // IUnknown
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+    virtual ULONG STDMETHODCALLTYPE AddRef(void);
+    virtual ULONG STDMETHODCALLTYPE Release(void);
+
+    // IWebResourceLoadDelegate
+    virtual HRESULT STDMETHODCALLTYPE identifierForInitialRequest(IWebView*, IWebURLRequest*, IWebDataSource*, unsigned long identifier);
+    virtual HRESULT STDMETHODCALLTYPE willSendRequest(IWebView*, unsigned long identifier, IWebURLRequest*, IWebURLResponse* redirectResponse, IWebDataSource*, IWebURLRequest** newRequest);
+    virtual HRESULT STDMETHODCALLTYPE didReceiveAuthenticationChallenge(IWebView*, unsigned long identifier, IWebURLAuthenticationChallenge*, IWebDataSource*);
+    virtual HRESULT STDMETHODCALLTYPE didCancelAuthenticationChallenge(IWebView*, unsigned long identifier, IWebURLAuthenticationChallenge*, IWebDataSource*);
+    virtual HRESULT STDMETHODCALLTYPE didReceiveResponse(IWebView*, unsigned long identifier, IWebURLResponse*, IWebDataSource*);
+    virtual HRESULT STDMETHODCALLTYPE didReceiveContentLength(IWebView*, unsigned long identifier, UINT length, IWebDataSource*);
+    virtual HRESULT STDMETHODCALLTYPE didFinishLoadingFromDataSource(IWebView*, unsigned long identifier, IWebDataSource*);
+    virtual HRESULT STDMETHODCALLTYPE didFailLoadingWithError(IWebView*, unsigned long identifier, IWebError*, IWebDataSource*);
+    virtual HRESULT STDMETHODCALLTYPE plugInFailedWithError(IWebView*, IWebError*, IWebDataSource*);
+
+private:
+    WinLauncher* m_client;
+    int m_refCount;
+};
+
+#endif // ResourceLoadDelegate
index 8056234..1f79d63 100644 (file)
@@ -51,10 +51,11 @@ static const int maxHistorySize = 10;
 
 typedef _com_ptr_t<_com_IIID<IWebMutableURLRequest, &__uuidof(IWebMutableURLRequest)>> IWebMutableURLRequestPtr;
 
-WinLauncher::WinLauncher(HWND mainWnd, HWND urlBarWnd, bool useLayeredWebView)
+WinLauncher::WinLauncher(HWND mainWnd, HWND urlBarWnd, bool useLayeredWebView, bool pageLoadTesting)
     : m_hMainWnd(mainWnd)
     , m_hURLBarWnd(urlBarWnd)
     , m_useLayeredWebView(useLayeredWebView)
+    , m_pageLoadTestClient(std::make_unique<PageLoadTestClient>(this, pageLoadTesting))
 {
 }
 
@@ -122,6 +123,11 @@ HRESULT WinLauncher::setFrameLoadDelegate(IWebFrameLoadDelegate* frameLoadDelega
     return m_webView->setFrameLoadDelegate(frameLoadDelegate);
 }
 
+HRESULT WinLauncher::setFrameLoadDelegatePrivate(IWebFrameLoadDelegatePrivate* frameLoadDelegatePrivate)
+{
+    return m_webViewPrivate->setFrameLoadDelegatePrivate(frameLoadDelegatePrivate);
+}
+
 HRESULT WinLauncher::setUIDelegate(IWebUIDelegate* uiDelegate)
 {
     m_uiDelegate = uiDelegate;
@@ -134,6 +140,13 @@ HRESULT WinLauncher::setAccessibilityDelegate(IAccessibilityDelegate* accessibil
     return m_webView->setAccessibilityDelegate(accessibilityDelegate);
 }
 
+
+HRESULT WinLauncher::setResourceLoadDelegate(IWebResourceLoadDelegate* resourceLoadDelegate)
+{
+    m_resourceLoadDelegate = resourceLoadDelegate;
+    return m_webView->setResourceLoadDelegate(resourceLoadDelegate);
+}
+
 IWebFramePtr WinLauncher::mainFrame()
 {
     IWebFramePtr framePtr;
@@ -348,6 +361,9 @@ HRESULT WinLauncher::loadURL(const BSTR& passedURL)
     if (FAILED(hr))
         return hr;
 
+    if (!passedURL)
+        return frame->loadHTMLString(_bstr_t(defaultHTML).GetBSTR(), 0);
+
     IWebMutableURLRequestPtr request;
     hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
     if (FAILED(hr))
@@ -366,3 +382,8 @@ HRESULT WinLauncher::loadURL(const BSTR& passedURL)
 
     return hr;
 }
+
+void WinLauncher::exitProgram()
+{
+    ::PostMessage(m_hMainWnd, static_cast<UINT>(WM_COMMAND), MAKELPARAM(IDM_EXIT, 0), 0);
+}
index a0ba9c1..37d2960 100644 (file)
@@ -23,7 +23,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
+#include "PageLoadTestClient.h"
 #include <WebKit/WebKit.h>
+#include <memory>
 #include <vector>
 
 typedef _com_ptr_t<_com_IIID<IWebFrame, &__uuidof(IWebFrame)>> IWebFramePtr;
@@ -39,10 +41,11 @@ typedef _com_ptr_t<_com_IIID<IAccessibilityDelegate, &__uuidof(IAccessibilityDel
 typedef _com_ptr_t<_com_IIID<IWebInspector, &__uuidof(IWebInspector)>> IWebInspectorPtr;
 typedef _com_ptr_t<_com_IIID<IWebCoreStatistics, &__uuidof(IWebCoreStatistics)>> IWebCoreStatisticsPtr;
 typedef _com_ptr_t<_com_IIID<IWebCache, &__uuidof(IWebCache)>> IWebCachePtr;
+typedef _com_ptr_t<_com_IIID<IWebResourceLoadDelegate, &__uuidof(IWebResourceLoadDelegate)>> IWebResourceLoadDelegatePtr;
 
 class WinLauncher {
 public:
-    WinLauncher(HWND mainWnd, HWND urlBarWnd, bool useLayeredWebView = false);
+    WinLauncher(HWND mainWnd, HWND urlBarWnd, bool useLayeredWebView = false, bool pageLoadTesting = false);
 
     HRESULT init();
     HRESULT prepareViews(HWND mainWnd, const RECT& clientRect, const BSTR& requestedURL, HWND& viewWnd);
@@ -53,12 +56,15 @@ public:
     void launchInspector();
     void navigateForwardOrBackward(HWND hWnd, UINT menuID);
     void navigateToHistory(HWND hWnd, UINT menuID);
+    void exitProgram();
     bool seedInitialDefaultPreferences();
     bool setToDefaultPreferences();
 
     HRESULT setFrameLoadDelegate(IWebFrameLoadDelegate*);
+    HRESULT setFrameLoadDelegatePrivate(IWebFrameLoadDelegatePrivate*);
     HRESULT setUIDelegate(IWebUIDelegate*);
     HRESULT setAccessibilityDelegate(IAccessibilityDelegate*);
+    HRESULT setResourceLoadDelegate(IWebResourceLoadDelegate*);
 
     IWebPreferencesPtr standardPreferences() { return m_standardPreferences;  }
     IWebPreferencesPrivatePtr privatePreferences() { return m_prefsPrivate; }
@@ -72,9 +78,13 @@ public:
     bool goBack();
     bool goForward();
 
+    PageLoadTestClient& pageLoadTestClient() { return *m_pageLoadTestClient; }
+
 private:
     std::vector<IWebHistoryItemPtr> m_historyItems;
 
+    std::unique_ptr<PageLoadTestClient> m_pageLoadTestClient;
+
     IWebViewPtr m_webView;
     IWebViewPrivatePtr m_webViewPrivate;
 
@@ -86,6 +96,7 @@ private:
     IWebFrameLoadDelegatePtr m_frameLoadDelegate;
     IWebUIDelegatePtr m_uiDelegate;
     IAccessibilityDelegatePtr m_accessibilityDelegate;
+    IWebResourceLoadDelegatePtr m_resourceLoadDelegate;
 
     IWebCoreStatisticsPtr m_statistics;
     IWebCachePtr m_webCache;
index 9528eee..5d7fbaa 100644 (file)
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">true</ExcludedFromBuild>
     </ClCompile>
     <ClCompile Include="..\DOMDefaultImpl.cpp" />
+    <ClCompile Include="..\PageLoadTestClient.cpp" />
     <ClCompile Include="..\PrintWebUIDelegate.cpp" />
+    <ClCompile Include="..\ResourceLoadDelegate.cpp" />
     <ClCompile Include="..\stdafx.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
   <ItemGroup>
     <ClInclude Include="..\AccessibilityDelegate.h" />
     <ClInclude Include="..\DOMDefaultImpl.h" />
+    <ClInclude Include="..\PageLoadTestClient.h" />
     <ClInclude Include="..\PrintWebUIDelegate.h" />
+    <ClInclude Include="..\ResourceLoadDelegate.h" />
     <ClInclude Include="..\stdafx.h" />
     <ClInclude Include="..\WinLauncher.h" />
     <ClInclude Include="..\WinLauncherReplace.h" />
index 3c4822d..8a172f5 100644 (file)
     <ClCompile Include="..\Common.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\ResourceLoadDelegate.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\PageLoadTestClient.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\DOMDefaultImpl.h">
     <ClInclude Include="..\WinLauncherWebHost.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\ResourceLoadDelegate.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\PageLoadTestClient.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="WinLauncherLib.rc">
index a13dcd0..74f0706 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2008, 2013 Apple Inc.  All rights reserved.
+ * Copyright (C) 2006, 2008, 2013-2014 Apple Inc.  All rights reserved.
  * Copyright (C) 2009, 2011 Brent Fulgham.  All rights reserved.
  * Copyright (C) 2009, 2010, 2011 Appcelerator, Inc. All rights reserved.
  * Copyright (C) 2013 Alex Christensen. All rights reserved.
@@ -30,6 +30,7 @@
 #include "WinLauncherWebHost.h"
 
 #include "DOMDefaultImpl.h"
+#include "PageLoadTestClient.h"
 #include "WinLauncher.h"
 #include <WebKit/WebKit.h>
 
@@ -82,11 +83,21 @@ HRESULT WinLauncherWebHost::updateAddressBar(IWebView& webView)
     if (FAILED(hr))
         return 0;
 
-    ::SendMessage(m_hURLBarWnd, static_cast<UINT>(WM_SETTEXT), 0, reinterpret_cast<LPARAM>(frameURL.GetBSTR()));
+    if (frameURL.length()) {
+        m_client->pageLoadTestClient().setPageURL(frameURL);
+        m_client->pageLoadTestClient().didCommitLoad();
+    }
+
+    loadURL(frameURL);
 
     return 0;
 }
 
+void WinLauncherWebHost::loadURL(_bstr_t& url)
+{
+    ::SendMessage(m_hURLBarWnd, static_cast<UINT>(WM_SETTEXT), 0, reinterpret_cast<LPARAM>(url.GetBSTR()));
+}
+
 HRESULT WinLauncherWebHost::didFailProvisionalLoadWithError(IWebView*, IWebError *error, IWebFrame*)
 {
     _bstr_t errorDescription;
@@ -134,6 +145,15 @@ typedef _com_ptr_t<_com_IIID<IDOMEventTarget, &__uuidof(IDOMEventTarget)>> IDOME
 
 HRESULT WinLauncherWebHost::didFinishLoadForFrame(IWebView* webView, IWebFrame* frame)
 {
+    if (!frame || !webView)
+        return E_POINTER;
+
+    BOOL mainFrame;
+    if (SUCCEEDED(frame->isMainFrame(&mainFrame))) {
+        if (mainFrame)
+            m_client->pageLoadTestClient().didFinishLoad();
+    }
+
     IDOMDocumentPtr doc;
     frame->DOMDocument(&doc.GetInterfacePtr());
 
@@ -158,3 +178,54 @@ HRESULT WinLauncherWebHost::didFinishLoadForFrame(IWebView* webView, IWebFrame*
 
     return hr;
 }
+
+HRESULT WinLauncherWebHost::didStartProvisionalLoadForFrame(IWebView*, IWebFrame* frame)
+{
+    if (!frame)
+        return E_FAIL;
+
+    m_client->pageLoadTestClient().didStartProvisionalLoad(*frame);
+    return S_OK;
+}
+
+HRESULT WinLauncherWebHost::didFailLoadWithError(IWebView*, IWebError*, IWebFrame*)
+{
+    m_client->pageLoadTestClient().didFailLoad();
+    return S_OK;
+}
+
+HRESULT WinLauncherWebHost::didHandleOnloadEventsForFrame(IWebView* sender, IWebFrame* frame)
+{
+    IWebDataSourcePtr dataSource;
+    HRESULT hr = frame->dataSource(&dataSource.GetInterfacePtr());
+    if (FAILED(hr) || !dataSource)
+        hr = frame->provisionalDataSource(&dataSource.GetInterfacePtr());
+    if (FAILED(hr) || !dataSource)
+        return 0;
+
+    IWebMutableURLRequestPtr request;
+    hr = dataSource->request(&request.GetInterfacePtr());
+    if (FAILED(hr) || !request)
+        return 0;
+
+    _bstr_t frameURL;
+    hr = request->mainDocumentURL(frameURL.GetAddress());
+    if (FAILED(hr))
+        return 0;
+
+    if (frameURL.length())
+        m_client->pageLoadTestClient().didHandleOnLoadEvents();
+
+    return S_OK;
+}
+
+HRESULT WinLauncherWebHost::didFirstLayoutInFrame(IWebView*, IWebFrame* frame)
+{
+    BOOL mainFrame;
+    if (SUCCEEDED(frame->isMainFrame(&mainFrame))) {
+        if (mainFrame)
+            m_client->pageLoadTestClient().didFirstLayoutForMainFrame();
+    }
+
+    return S_OK;
+}
index 16e39cf..37592b3 100644 (file)
@@ -30,7 +30,7 @@
 
 class WinLauncher;
 
-class WinLauncherWebHost : public IWebFrameLoadDelegate {
+class WinLauncherWebHost : public IWebFrameLoadDelegate, public IWebFrameLoadDelegatePrivate {
 public:
     WinLauncherWebHost(WinLauncher* client, HWND urlBar)
         : m_refCount(1), m_client(client), m_hURLBarWnd(urlBar) { }
@@ -41,7 +41,7 @@ public:
     virtual ULONG STDMETHODCALLTYPE Release();
 
     // IWebFrameLoadDelegate
-    virtual HRESULT STDMETHODCALLTYPE didStartProvisionalLoadForFrame(IWebView*, IWebFrame*) { return S_OK; }
+    virtual HRESULT STDMETHODCALLTYPE didStartProvisionalLoadForFrame(IWebView*, IWebFrame*);
     virtual HRESULT STDMETHODCALLTYPE didReceiveServerRedirectForProvisionalLoadForFrame(IWebView*, IWebFrame*) { return S_OK; }
     virtual HRESULT STDMETHODCALLTYPE didFailProvisionalLoadWithError(IWebView*, IWebError*, IWebFrame*);
     virtual HRESULT STDMETHODCALLTYPE didCommitLoadForFrame(IWebView* webView, IWebFrame*)
@@ -56,7 +56,7 @@ public:
     virtual HRESULT STDMETHODCALLTYPE didChangeIcons(IWebView*, IWebFrame*) { return S_OK; }
     virtual HRESULT STDMETHODCALLTYPE didReceiveIcon(IWebView*, HBITMAP, IWebFrame*) { return S_OK; }
     virtual HRESULT STDMETHODCALLTYPE didFinishLoadForFrame(IWebView*, IWebFrame*);   
-    virtual HRESULT STDMETHODCALLTYPE didFailLoadWithError(IWebView*, IWebError*, IWebFrame*) { return S_OK; }
+    virtual HRESULT STDMETHODCALLTYPE didFailLoadWithError(IWebView*, IWebError*, IWebFrame*);
     virtual HRESULT STDMETHODCALLTYPE didChangeLocationWithinPageForFrame(IWebView*, IWebFrame*) { return S_OK; }
     virtual HRESULT STDMETHODCALLTYPE willPerformClientRedirectToURL(IWebView*, BSTR url, double delaySeconds, DATE fireDate, IWebFrame*) { return S_OK; }
     virtual HRESULT STDMETHODCALLTYPE didCancelClientRedirectForFrame(IWebView*, IWebFrame*) { return S_OK; }
@@ -64,6 +64,14 @@ public:
     virtual /* [local] */ HRESULT STDMETHODCALLTYPE windowScriptObjectAvailable(IWebView*, JSContextRef, JSObjectRef)  { return S_OK; }
     virtual /* [local] */ HRESULT STDMETHODCALLTYPE didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*) { return S_OK; }
 
+    // IWebFrameLoadDelegatePrivate
+    virtual HRESULT STDMETHODCALLTYPE didFinishDocumentLoadForFrame(IWebView* sender, IWebFrame*) { return S_OK; }
+    virtual HRESULT STDMETHODCALLTYPE didFirstLayoutInFrame(IWebView* sender, IWebFrame*);
+    virtual HRESULT STDMETHODCALLTYPE didHandleOnloadEventsForFrame(IWebView*, IWebFrame*);
+    virtual HRESULT STDMETHODCALLTYPE didFirstVisuallyNonEmptyLayoutInFrame(IWebView* sender, IWebFrame*)  { return S_OK; }
+
+    void loadURL(_bstr_t&);
+
 protected:
     HRESULT updateAddressBar(IWebView&);
 
index 6c7922c..4b56c51 100644 (file)
@@ -53,18 +53,10 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int nCmdShow)
 
     bool usesLayeredWebView = false;
     bool useFullDesktop = false;
-
+    bool pageLoadTesting = false;
     _bstr_t requestedURL;
-    int argc = 0;
-    WCHAR** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
-    for (int i = 1; i < argc; ++i) {
-        if (!wcsicmp(argv[i], L"--transparent"))
-            usesLayeredWebView = true;
-        else if (!wcsicmp(argv[i], L"--desktop"))
-            useFullDesktop = true;
-        else if (!requestedURL)
-            requestedURL = argv[i];
-    }
+
+    parseCommandLine(usesLayeredWebView, useFullDesktop, pageLoadTesting, requestedURL);
 
     // Initialize global strings
     LoadString(hInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
@@ -107,7 +99,9 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int nCmdShow)
 
     RECT clientRect = { s_windowPosition.x, s_windowPosition.y, s_windowPosition.x + s_windowSize.cx, s_windowPosition.y + s_windowSize.cy };
 
-    gWinLauncher = new WinLauncher(hMainWnd, hURLBarWnd, usesLayeredWebView);
+    WinLauncherWebHost* webHost = nullptr;
+
+    gWinLauncher = new WinLauncher(hMainWnd, hURLBarWnd, usesLayeredWebView, pageLoadTesting);
     if (!gWinLauncher)
         goto exit;
 
@@ -124,7 +118,13 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int nCmdShow)
     if (!setCacheFolder())
         goto exit;
 
-    hr = gWinLauncher->setFrameLoadDelegate(new WinLauncherWebHost(gWinLauncher, hURLBarWnd));
+    webHost = new WinLauncherWebHost(gWinLauncher, hURLBarWnd);
+
+    hr = gWinLauncher->setFrameLoadDelegate(webHost);
+    if (FAILED(hr))
+        goto exit;
+
+    hr = gWinLauncher->setFrameLoadDelegatePrivate(webHost);
     if (FAILED(hr))
         goto exit;
 
@@ -136,6 +136,10 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int nCmdShow)
     if (FAILED (hr))
         goto exit;
 
+    hr = gWinLauncher->setResourceLoadDelegate(new ResourceLoadDelegate(gWinLauncher));
+    if (FAILED(hr))
+        goto exit;
+
     hr = gWinLauncher->prepareViews(hMainWnd, clientRect, requestedURL.GetBSTR(), gViewWindow);
     if (FAILED(hr) || !gViewWindow)
         goto exit;
index 0280946..de1e6b3 100644 (file)
@@ -70,6 +70,7 @@
 #include <windows.h>
 #include <wininet.h>
 #include <wtf/ExportMacros.h>
+#include <wtf/Platform.h>
 
 #if 0
 // Visual Studio Leak Detection