summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--chrome/browser/net/load_timing_observer.cc1
-rw-r--r--chrome/common/extensions/extension_localization_peer.cc2
-rw-r--r--chrome/common/extensions/extension_localization_peer.h7
-rw-r--r--chrome/common/extensions/extension_localization_peer_unittest.cc27
-rw-r--r--chrome/renderer/security_filter_peer.cc11
-rw-r--r--chrome/renderer/security_filter_peer.h21
-rw-r--r--content/browser/renderer_host/async_resource_handler.cc7
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host.cc4
-rw-r--r--content/common/inter_process_time_ticks_converter.cc58
-rw-r--r--content/common/inter_process_time_ticks_converter.h144
-rw-r--r--content/common/inter_process_time_ticks_converter_unittest.cc206
-rw-r--r--content/common/resource_dispatcher.cc96
-rw-r--r--content/common/resource_dispatcher.h20
-rw-r--r--content/common/resource_dispatcher_unittest.cc4
-rw-r--r--content/common/resource_messages.h2
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/content_tests.gypi1
-rw-r--r--content/public/common/resource_response.h4
-rw-r--r--content/public/common/webkit_param_traits.cc4
-rw-r--r--content/test/render_view_fake_resources_test.cc2
-rw-r--r--net/url_request/url_request.cc3
-rw-r--r--net/url_request/url_request.h10
-rw-r--r--webkit/glue/resource_loader_bridge.h14
-rw-r--r--webkit/glue/weburlloader_impl.cc14
-rw-r--r--webkit/tools/layout_tests/test_expectations.txt5
-rw-r--r--webkit/tools/test_shell/simple_resource_loader_bridge.cc8
27 files changed, 602 insertions, 77 deletions
diff --git a/DEPS b/DEPS
index e6e202b..9e0d5fc 100644
--- a/DEPS
+++ b/DEPS
@@ -5,7 +5,7 @@ vars = {
"sourceforge_url": "http://%(repo)s.svn.sourceforge.net/svnroot/%(repo)s",
"webkit_trunk": "http://svn.webkit.org/repository/webkit/trunk",
"nacl_trunk": "http://src.chromium.org/native_client/trunk",
- "webkit_revision": "102911",
+ "webkit_revision": "102988",
"chromium_git": "http://git.chromium.org/git",
"swig_revision": "69281",
"nacl_revision": "7388",
diff --git a/chrome/browser/net/load_timing_observer.cc b/chrome/browser/net/load_timing_observer.cc
index f0d33e2..b3bd189 100644
--- a/chrome/browser/net/load_timing_observer.cc
+++ b/chrome/browser/net/load_timing_observer.cc
@@ -153,6 +153,7 @@ void LoadTimingObserver::OnAddURLRequestEntry(
URLRequestRecord& record = url_request_to_record_[source.id];
record.base_ticks = time;
record.timing = ResourceLoadTimingInfo();
+ record.timing.base_ticks = time;
record.timing.base_time = TimeTicksToTime(time);
}
return;
diff --git a/chrome/common/extensions/extension_localization_peer.cc b/chrome/common/extensions/extension_localization_peer.cc
index dfb4f1d..fa00999 100644
--- a/chrome/common/extensions/extension_localization_peer.cc
+++ b/chrome/common/extensions/extension_localization_peer.cc
@@ -68,7 +68,7 @@ void ExtensionLocalizationPeer::OnReceivedData(const char* data,
void ExtensionLocalizationPeer::OnCompletedRequest(
const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time) {
+ const base::TimeTicks& completion_time) {
// Make sure we delete ourselves at the end of this call.
scoped_ptr<ExtensionLocalizationPeer> this_deleter(this);
diff --git a/chrome/common/extensions/extension_localization_peer.h b/chrome/common/extensions/extension_localization_peer.h
index 1f88775..346d06e 100644
--- a/chrome/common/extensions/extension_localization_peer.h
+++ b/chrome/common/extensions/extension_localization_peer.h
@@ -42,9 +42,10 @@ class ExtensionLocalizationPeer
virtual void OnReceivedData(const char* data,
int data_length,
int encoded_data_length) OVERRIDE;
- virtual void OnCompletedRequest(const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) OVERRIDE;
+ virtual void OnCompletedRequest(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& completion_time) OVERRIDE;
private:
friend class ExtensionLocalizationPeerTest;
diff --git a/chrome/common/extensions/extension_localization_peer_unittest.cc b/chrome/common/extensions/extension_localization_peer_unittest.cc
index df847ce..06bd74e 100644
--- a/chrome/common/extensions/extension_localization_peer_unittest.cc
+++ b/chrome/common/extensions/extension_localization_peer_unittest.cc
@@ -72,7 +72,7 @@ class MockResourceLoaderBridgePeer
MOCK_METHOD3(OnCompletedRequest, void(
const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time));
+ const base::TimeTicks& completion_time));
private:
DISALLOW_COPY_AND_ASSIGN(MockResourceLoaderBridgePeer);
@@ -142,11 +142,11 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestBadURLRequestStatus) {
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
EXPECT_CALL(*original_peer_, OnCompletedRequest(
- IsURLRequestEqual(net::URLRequestStatus::CANCELED), "", base::Time()));
+ IsURLRequestEqual(net::URLRequestStatus::CANCELED), "", base::TimeTicks()));
net::URLRequestStatus status;
status.set_status(net::URLRequestStatus::FAILED);
- filter_peer->OnCompletedRequest(status, "", base::Time());
+ filter_peer->OnCompletedRequest(status, "", base::TimeTicks());
}
TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) {
@@ -158,11 +158,12 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) {
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
EXPECT_CALL(*original_peer_, OnCompletedRequest(
- IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time()));
+ IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "",
+ base::TimeTicks()));
net::URLRequestStatus status;
status.set_status(net::URLRequestStatus::SUCCESS);
- filter_peer->OnCompletedRequest(status, "", base::Time());
+ filter_peer->OnCompletedRequest(status, "", base::TimeTicks());
}
TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) {
@@ -180,18 +181,18 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) {
EXPECT_CALL(*original_peer_, OnReceivedResponse(_)).Times(2);
EXPECT_CALL(*original_peer_, OnCompletedRequest(
IsURLRequestEqual(
- net::URLRequestStatus::SUCCESS), "", base::Time())).Times(2);
+ net::URLRequestStatus::SUCCESS), "", base::TimeTicks())).Times(2);
net::URLRequestStatus status;
status.set_status(net::URLRequestStatus::SUCCESS);
- filter_peer->OnCompletedRequest(status, "", base::Time());
+ filter_peer->OnCompletedRequest(status, "", base::TimeTicks());
// Test if Send gets called again (it shouldn't be) when first call returned
// an empty dictionary.
filter_peer =
CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_1));
SetData(filter_peer, "some text");
- filter_peer->OnCompletedRequest(status, "", base::Time());
+ filter_peer->OnCompletedRequest(status, "", base::TimeTicks());
}
TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) {
@@ -217,11 +218,12 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) {
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
EXPECT_CALL(*original_peer_, OnCompletedRequest(
- IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time()));
+ IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "",
+ base::TimeTicks()));
net::URLRequestStatus status;
status.set_status(net::URLRequestStatus::SUCCESS);
- filter_peer->OnCompletedRequest(status, "", base::Time());
+ filter_peer->OnCompletedRequest(status, "", base::TimeTicks());
}
TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) {
@@ -247,9 +249,10 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) {
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
EXPECT_CALL(*original_peer_, OnCompletedRequest(
- IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time()));
+ IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "",
+ base::TimeTicks()));
net::URLRequestStatus status;
status.set_status(net::URLRequestStatus::SUCCESS);
- filter_peer->OnCompletedRequest(status, "", base::Time());
+ filter_peer->OnCompletedRequest(status, "", base::TimeTicks());
}
diff --git a/chrome/renderer/security_filter_peer.cc b/chrome/renderer/security_filter_peer.cc
index 7d98684..994543c 100644
--- a/chrome/renderer/security_filter_peer.cc
+++ b/chrome/renderer/security_filter_peer.cc
@@ -87,9 +87,10 @@ void SecurityFilterPeer::OnReceivedData(const char* data,
NOTREACHED();
}
-void SecurityFilterPeer::OnCompletedRequest(const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) {
+void SecurityFilterPeer::OnCompletedRequest(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& completion_time) {
NOTREACHED();
}
@@ -149,7 +150,7 @@ void BufferedPeer::OnReceivedData(const char* data,
void BufferedPeer::OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time) {
+ const base::TimeTicks& completion_time) {
// Make sure we delete ourselves at the end of this call.
scoped_ptr<BufferedPeer> this_deleter(this);
@@ -201,7 +202,7 @@ void ReplaceContentPeer::OnReceivedData(const char* data,
void ReplaceContentPeer::OnCompletedRequest(
const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time) {
+ const base::TimeTicks& completion_time) {
webkit_glue::ResourceResponseInfo info;
ProcessResponseInfo(info, &info, mime_type_);
info.security_info = security_info;
diff --git a/chrome/renderer/security_filter_peer.h b/chrome/renderer/security_filter_peer.h
index c54705d..df499bd 100644
--- a/chrome/renderer/security_filter_peer.h
+++ b/chrome/renderer/security_filter_peer.h
@@ -41,9 +41,10 @@ class SecurityFilterPeer : public webkit_glue::ResourceLoaderBridge::Peer {
virtual void OnReceivedData(const char* data,
int data_length,
int encoded_data_length) OVERRIDE;
- virtual void OnCompletedRequest(const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) OVERRIDE;
+ virtual void OnCompletedRequest(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& completion_time) OVERRIDE;
protected:
SecurityFilterPeer(webkit_glue::ResourceLoaderBridge* resource_loader_bridge,
@@ -71,9 +72,10 @@ class BufferedPeer : public SecurityFilterPeer {
virtual void OnReceivedData(const char* data,
int data_length,
int encoded_data_length) OVERRIDE;
- virtual void OnCompletedRequest(const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) OVERRIDE;
+ virtual void OnCompletedRequest(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& completion_time) OVERRIDE;
protected:
// Invoked when the entire request has been processed before the data is sent
@@ -113,9 +115,10 @@ class ReplaceContentPeer : public SecurityFilterPeer {
virtual void OnReceivedData(const char* data,
int data_length,
int encoded_data_length) OVERRIDE;
- virtual void OnCompletedRequest(const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) OVERRIDE;
+ virtual void OnCompletedRequest(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& completion_time) OVERRIDE;
private:
webkit_glue::ResourceResponseInfo response_info_;
diff --git a/content/browser/renderer_host/async_resource_handler.cc b/content/browser/renderer_host/async_resource_handler.cc
index 9f7577f..d4b5a15 100644
--- a/content/browser/renderer_host/async_resource_handler.cc
+++ b/content/browser/renderer_host/async_resource_handler.cc
@@ -26,7 +26,6 @@
#include "net/base/net_log.h"
#include "webkit/glue/resource_loader_bridge.h"
-using base::Time;
using base::TimeTicks;
namespace {
@@ -110,6 +109,8 @@ bool AsyncResourceHandler::OnRequestRedirected(
rdh_->delegate()->OnRequestRedirected(request, response, filter_);
DevToolsNetLogObserver::PopulateResponseInfo(request, response);
+ response->request_start = request->creation_time();
+ response->response_start = TimeTicks::Now();
return filter_->Send(new ResourceMsg_ReceivedRedirect(
routing_id_, request_id, new_url, *response));
}
@@ -143,6 +144,8 @@ bool AsyncResourceHandler::OnResponseStarted(
request_url))));
}
+ response->request_start = request->creation_time();
+ response->response_start = TimeTicks::Now();
filter_->Send(new ResourceMsg_ReceivedResponse(
routing_id_, request_id, *response));
@@ -241,7 +244,7 @@ bool AsyncResourceHandler::OnResponseCompleted(
int request_id,
const net::URLRequestStatus& status,
const std::string& security_info) {
- Time completion_time = Time::Now();
+ TimeTicks completion_time = TimeTicks::Now();
filter_->Send(new ResourceMsg_RequestComplete(routing_id_,
request_id,
status,
diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc
index 542b606..5bb26e3 100644
--- a/content/browser/renderer_host/resource_dispatcher_host.cc
+++ b/content/browser/renderer_host/resource_dispatcher_host.cc
@@ -137,8 +137,8 @@ void AbortRequestBeforeItStarts(ResourceMessageFilter* filter,
route_id,
request_id,
status,
- std::string(), // No security info needed, connection was not
- base::Time())); // established.
+ std::string(), // No security info needed, connection not established.
+ base::TimeTicks()));
}
}
diff --git a/content/common/inter_process_time_ticks_converter.cc b/content/common/inter_process_time_ticks_converter.cc
new file mode 100644
index 0000000..09c14f0
--- /dev/null
+++ b/content/common/inter_process_time_ticks_converter.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/inter_process_time_ticks_converter.h"
+
+#include "base/logging.h"
+
+namespace content {
+
+InterProcessTimeTicksConverter::InterProcessTimeTicksConverter(
+ const LocalTimeTicks& local_lower_bound,
+ const LocalTimeTicks& local_upper_bound,
+ const RemoteTimeTicks& remote_lower_bound,
+ const RemoteTimeTicks& remote_upper_bound)
+ : remote_lower_bound_(remote_lower_bound.value_),
+ remote_upper_bound_(remote_upper_bound.value_) {
+ int64 target_range = local_upper_bound.value_ - local_lower_bound.value_;
+ int64 source_range = remote_upper_bound.value_ - remote_lower_bound.value_;
+ if (source_range <= target_range) {
+ // We fit! Just shift the midpoints to match.
+ numerator_ = 1;
+ denominator_ = 1;
+ offset_ = ((local_upper_bound.value_ + local_lower_bound.value_) -
+ (remote_upper_bound.value_ + remote_lower_bound.value_)) / 2;
+ return;
+ }
+ // Set up scaling factors, and then deduce shift.
+ numerator_ = target_range;
+ denominator_ = source_range;
+ // Find out what we need to shift by to make this really work.
+ offset_ = local_lower_bound.value_ - Convert(remote_lower_bound.value_);
+ DCHECK_GE(local_upper_bound.value_, Convert(remote_upper_bound.value_));
+}
+
+LocalTimeTicks InterProcessTimeTicksConverter::ToLocalTimeTicks(
+ const RemoteTimeTicks& remote_ms) {
+ DCHECK_LE(remote_lower_bound_, remote_ms.value_);
+ DCHECK_GE(remote_upper_bound_, remote_ms.value_);
+ RemoteTimeDelta remote_delta = remote_ms - remote_lower_bound_;
+ return LocalTimeTicks(remote_lower_bound_ + offset_ +
+ ToLocalTimeDelta(remote_delta).value_);
+}
+
+LocalTimeDelta InterProcessTimeTicksConverter::ToLocalTimeDelta(
+ const RemoteTimeDelta& remote_delta) {
+ DCHECK_GE(remote_upper_bound_, remote_lower_bound_ + remote_delta.value_);
+ return LocalTimeDelta(Convert(remote_delta.value_));
+}
+
+int64 InterProcessTimeTicksConverter::Convert(int64 value) {
+ if (value <= 0) {
+ return value;
+ }
+ return numerator_ * value / denominator_;
+}
+
+} // namespace content
diff --git a/content/common/inter_process_time_ticks_converter.h b/content/common/inter_process_time_ticks_converter.h
new file mode 100644
index 0000000..0377764
--- /dev/null
+++ b/content/common/inter_process_time_ticks_converter.h
@@ -0,0 +1,144 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_
+#define CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_
+
+#include "base/time.h"
+
+namespace content {
+
+class LocalTimeDelta;
+class LocalTimeTicks;
+class RemoteTimeDelta;
+class RemoteTimeTicks;
+
+// On Windows, TimeTicks are not consistent between processes. Often, the values
+// on one process have a static offset relative to another. Occasionally, these
+// offsets shift while running.
+//
+// To combat this, any TimeTicks values sent from the remote process to the
+// local process must be tweaked in order to appear monotonic.
+//
+// In order to properly tweak ticks, we need 4 reference points:
+//
+// - |local_lower_bound|: A known point, recorded on the local process, that
+// occurs before any remote values that will be
+// converted.
+// - |remote_lower_bound|: The equivalent point on the remote process. This
+// should be recorded immediately after
+// |local_lower_bound|.
+// - |local_upper_bound|: A known point, recorded on the local process, that
+// occurs after any remote values that will be
+// converted.
+// - |remote_upper_bound|: The equivalent point on the remote process. This
+// should be recorded immediately before
+// |local_upper_bound|.
+//
+// Once these bounds are determined, values within the remote process's range
+// can be converted to the local process's range. The values are converted as
+// follows:
+//
+// 1. If the remote's range exceeds the local's range, it is scaled to fit.
+// Any values converted will have the same scale factor applied.
+//
+// 2. The remote's range is shifted so that it is centered within the
+// local's range. Any values converted will be shifted the same amount.
+class InterProcessTimeTicksConverter {
+ public:
+ InterProcessTimeTicksConverter(const LocalTimeTicks& local_lower_bound,
+ const LocalTimeTicks& local_upper_bound,
+ const RemoteTimeTicks& remote_lower_bound,
+ const RemoteTimeTicks& remote_upper_bound);
+
+ // Returns the value within the local's bounds that correlates to
+ // |remote_ms|.
+ LocalTimeTicks ToLocalTimeTicks(const RemoteTimeTicks& remote_ms);
+
+ // Returns the equivalent delta after applying remote-to-local scaling to
+ // |remote_delta|.
+ LocalTimeDelta ToLocalTimeDelta(const RemoteTimeDelta& remote_delta);
+
+ private:
+ int64 Convert(int64 value);
+
+ int64 offset_;
+ int64 numerator_;
+ int64 denominator_;
+
+ int64 remote_lower_bound_;
+ int64 remote_upper_bound_;
+};
+
+class LocalTimeDelta {
+ public:
+ int ToInt32() const { return value_; }
+
+ private:
+ friend class InterProcessTimeTicksConverter;
+ friend class LocalTimeTicks;
+
+ LocalTimeDelta(int value) : value_(value) {}
+
+ int value_;
+};
+
+class LocalTimeTicks {
+ public:
+ static LocalTimeTicks FromTimeTicks(const base::TimeTicks& value) {
+ return LocalTimeTicks(value.ToInternalValue());
+ }
+
+ base::TimeTicks ToTimeTicks() {
+ return base::TimeTicks::FromInternalValue(value_);
+ }
+
+ LocalTimeTicks operator+(const LocalTimeDelta& delta) {
+ return LocalTimeTicks(value_ + delta.value_);
+ }
+
+ private:
+ friend class InterProcessTimeTicksConverter;
+
+ LocalTimeTicks(int64 value) : value_(value) {}
+
+ int64 value_;
+};
+
+class RemoteTimeDelta {
+ public:
+ static RemoteTimeDelta FromRawDelta(int delta) {
+ return RemoteTimeDelta(delta);
+ }
+
+ private:
+ friend class InterProcessTimeTicksConverter;
+ friend class RemoteTimeTicks;
+
+ RemoteTimeDelta(int value) : value_(value) {}
+
+ int value_;
+};
+
+class RemoteTimeTicks {
+ public:
+ static RemoteTimeTicks FromTimeTicks(const base::TimeTicks& ticks) {
+ return RemoteTimeTicks(ticks.ToInternalValue());
+ }
+
+ RemoteTimeDelta operator-(const RemoteTimeTicks& rhs) const {
+ return RemoteTimeDelta(value_ - rhs.value_);
+ }
+
+ private:
+ friend class InterProcessTimeTicksConverter;
+
+ RemoteTimeTicks(int64 value) : value_(value) {}
+
+ int64 value_;
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_
diff --git a/content/common/inter_process_time_ticks_converter_unittest.cc b/content/common/inter_process_time_ticks_converter_unittest.cc
new file mode 100644
index 0000000..1d1f301
--- /dev/null
+++ b/content/common/inter_process_time_ticks_converter_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time.h"
+#include "content/common/inter_process_time_ticks_converter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::TimeTicks;
+
+namespace content {
+
+namespace {
+
+struct TestParams {
+ int64 local_lower_bound;
+ int64 remote_lower_bound;
+ int64 remote_upper_bound;
+ int64 local_upper_bound;
+ int64 test_time;
+ int64 test_delta;
+};
+
+struct TestResults {
+ int64 result_time;
+ int32 result_delta;
+};
+
+TestResults RunTest(const TestParams& params) {
+ TimeTicks local_lower_bound = TimeTicks::FromInternalValue(
+ params.local_lower_bound);
+ TimeTicks local_upper_bound = TimeTicks::FromInternalValue(
+ params.local_upper_bound);
+ TimeTicks remote_lower_bound = TimeTicks::FromInternalValue(
+ params.remote_lower_bound);
+ TimeTicks remote_upper_bound = TimeTicks::FromInternalValue(
+ params.remote_upper_bound);
+ TimeTicks test_time = TimeTicks::FromInternalValue(params.test_time);
+
+ InterProcessTimeTicksConverter converter(
+ LocalTimeTicks::FromTimeTicks(local_lower_bound),
+ LocalTimeTicks::FromTimeTicks(local_upper_bound),
+ RemoteTimeTicks::FromTimeTicks(remote_lower_bound),
+ RemoteTimeTicks::FromTimeTicks(remote_upper_bound));
+
+ TestResults results;
+ results.result_time = converter.ToLocalTimeTicks(
+ RemoteTimeTicks::FromTimeTicks(
+ test_time)).ToTimeTicks().ToInternalValue();
+ results.result_delta = converter.ToLocalTimeDelta(
+ RemoteTimeDelta::FromRawDelta(params.test_delta)).ToInt32();
+ return results;
+}
+
+TEST(InterProcessTimeTicksConverterTest, NoSkew) {
+ // All times are monotonic and centered, so no adjustment should occur.
+ TestParams p;
+ p.local_lower_bound = 0;
+ p.remote_lower_bound = 1;
+ p.remote_upper_bound = 4;
+ p.local_upper_bound = 5;
+ p.test_time = 2;
+ p.test_delta = 1;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(2, results.result_time);
+ EXPECT_EQ(1, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, OffsetMidpoints) {
+ // All times are monotonic, but not centered. Adjust the |remote_*| times so
+ // they are centered within the |local_*| times.
+ TestParams p;
+ p.local_lower_bound = 0;
+ p.remote_lower_bound = 2;
+ p.remote_upper_bound = 5;
+ p.local_upper_bound = 5;
+ p.test_time = 3;
+ p.test_delta = 1;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(2, results.result_time);
+ EXPECT_EQ(1, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, DoubleEndedSkew) {
+ // |remote_lower_bound| occurs before |local_lower_bound| and
+ // |remote_upper_bound| occurs after |local_upper_bound|. We must adjust both
+ // bounds and scale down the delta. |test_time| is on the midpoint, so it
+ // doesn't change. The ratio of local time to network time is 1:2, so we scale
+ // |test_delta| to half.
+ TestParams p;
+ p.local_lower_bound = 2;
+ p.remote_lower_bound = 0;
+ p.remote_upper_bound = 8;
+ p.local_upper_bound = 6;
+ p.test_time = 4;
+ p.test_delta = 2;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(4, results.result_time);
+ EXPECT_EQ(1, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, FrontEndSkew) {
+ // |remote_upper_bound| is coherent, but |remote_lower_bound| is not. So we
+ // adjust the lower bound and move |test_time| out. The scale factor is 2:3,
+ // but since we use integers, the numbers truncate from 3.33 to 3 and 1.33
+ // to 1.
+ TestParams p;
+ p.local_lower_bound = 2;
+ p.remote_lower_bound = 0;
+ p.remote_upper_bound = 6;
+ p.local_upper_bound = 6;
+ p.test_time = 2;
+ p.test_delta = 2;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(3, results.result_time);
+ EXPECT_EQ(1, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, BackEndSkew) {
+ // Like the previous test, but |remote_lower_bound| is coherent and
+ // |remote_upper_bound| is skewed.
+ TestParams p;
+ p.local_lower_bound = 0;
+ p.remote_lower_bound = 0;
+ p.remote_upper_bound = 6;
+ p.local_upper_bound = 4;
+ p.test_time = 2;
+ p.test_delta = 2;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(1, results.result_time);
+ EXPECT_EQ(1, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, Instantaneous) {
+ // The bounds are all okay, but the |remote_lower_bound| and
+ // |remote_upper_bound| have the same value. No adjustments should be made and
+ // no divide-by-zero errors should occur.
+ TestParams p;
+ p.local_lower_bound = 0;
+ p.remote_lower_bound = 1;
+ p.remote_upper_bound = 1;
+ p.local_upper_bound = 2;
+ p.test_time = 1;
+ p.test_delta = 0;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(1, results.result_time);
+ EXPECT_EQ(0, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, OffsetInstantaneous) {
+ // The bounds are all okay, but the |remote_lower_bound| and
+ // |remote_upper_bound| have the same value and are offset from the midpoint
+ // of |local_lower_bound| and |local_upper_bound|. An offset should be applied
+ // to make the midpoints line up.
+ TestParams p;
+ p.local_lower_bound = 0;
+ p.remote_lower_bound = 2;
+ p.remote_upper_bound = 2;
+ p.local_upper_bound = 2;
+ p.test_time = 2;
+ p.test_delta = 0;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(1, results.result_time);
+ EXPECT_EQ(0, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, DisjointInstantaneous) {
+ // |local_lower_bound| and |local_upper_bound| are the same. No matter what
+ // the other values are, they must fit within [local_lower_bound,
+ // local_upper_bound]. So, all of the values should be adjusted so they are
+ // exactly that value.
+ TestParams p;
+ p.local_lower_bound = 1;
+ p.remote_lower_bound = 2;
+ p.remote_upper_bound = 2;
+ p.local_upper_bound = 1;
+ p.test_time = 2;
+ p.test_delta = 0;
+ TestResults results = RunTest(p);
+ EXPECT_EQ(1, results.result_time);
+ EXPECT_EQ(0, results.result_delta);
+}
+
+TEST(InterProcessTimeTicksConverterTest, RoundingNearEdges) {
+ // Verify that rounding never causes a value to appear outside the given
+ // |local_*| range.
+ const int kMaxRange = 100;
+ for (int i = 0; i < kMaxRange; ++i) {
+ for (int j = 0; j < kMaxRange; ++j) {
+ TestParams p;
+ p.local_lower_bound = 0;
+ p.remote_lower_bound = 0;
+ p.remote_upper_bound = j;
+ p.local_upper_bound = i;
+ p.test_time = 0;
+ p.test_delta = j;
+ TestResults results = RunTest(p);
+ EXPECT_LE(0, results.result_time);
+ EXPECT_GE(i, results.result_delta);
+ }
+ }
+}
+
+} // anonymous namespace
+
+} // namespace content
diff --git a/content/common/resource_dispatcher.cc b/content/common/resource_dispatcher.cc
index 6094fc2..38bc014 100644
--- a/content/common/resource_dispatcher.cc
+++ b/content/common/resource_dispatcher.cc
@@ -13,6 +13,7 @@
#include "base/message_loop.h"
#include "base/shared_memory.h"
#include "base/string_util.h"
+#include "content/common/inter_process_time_ticks_converter.h"
#include "content/common/request_extra_data.h"
#include "content/common/resource_messages.h"
#include "content/public/common/resource_dispatcher_delegate.h"
@@ -23,6 +24,12 @@
#include "net/http/http_response_headers.h"
#include "webkit/glue/resource_type.h"
+using content::InterProcessTimeTicksConverter;
+using content::LocalTimeDelta;
+using content::LocalTimeTicks;
+using content::RemoteTimeDelta;
+using content::RemoteTimeTicks;
+
// Each resource request is assigned an ID scoped to this process.
static int MakeRequestID() {
// NOTE: The resource_dispatcher_host also needs probably unique
@@ -348,6 +355,7 @@ void ResourceDispatcher::OnReceivedResponse(
PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
if (!request_info)
return;
+ request_info->response_start = base::TimeTicks::Now();
if (delegate_) {
webkit_glue::ResourceLoaderBridge::Peer* new_peer =
@@ -357,7 +365,9 @@ void ResourceDispatcher::OnReceivedResponse(
request_info->peer = new_peer;
}
- request_info->peer->OnReceivedResponse(response_head);
+ webkit_glue::ResourceResponseInfo renderer_response_info;
+ ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
+ request_info->peer->OnReceivedResponse(renderer_response_info);
}
void ResourceDispatcher::OnReceivedCachedMetadata(
@@ -411,17 +421,20 @@ void ResourceDispatcher::OnReceivedRedirect(
const IPC::Message& message,
int request_id,
const GURL& new_url,
- const webkit_glue::ResourceResponseInfo& info) {
+ const content::ResourceResponseHead& response_head) {
PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
if (!request_info)
return;
+ request_info->response_start = base::TimeTicks::Now();
int32 routing_id = message.routing_id();
bool has_new_first_party_for_cookies = false;
GURL new_first_party_for_cookies;
- if (request_info->peer->OnReceivedRedirect(new_url, info,
- &has_new_first_party_for_cookies,
- &new_first_party_for_cookies)) {
+ webkit_glue::ResourceResponseInfo renderer_response_info;
+ ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
+ if (request_info->peer->OnReceivedRedirect(new_url, renderer_response_info,
+ &has_new_first_party_for_cookies,
+ &new_first_party_for_cookies)) {
// Double-check if the request is still around. The call above could
// potentially remove it.
request_info = GetPendingRequestInfo(request_id);
@@ -447,13 +460,15 @@ void ResourceDispatcher::FollowPendingRedirect(
message_sender()->Send(msg);
}
-void ResourceDispatcher::OnRequestComplete(int request_id,
- const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) {
+void ResourceDispatcher::OnRequestComplete(
+ int request_id,
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& browser_completion_time) {
PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
if (!request_info)
return;
+ request_info->completion_time = base::TimeTicks::Now();
webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer;
@@ -465,10 +480,12 @@ void ResourceDispatcher::OnRequestComplete(int request_id,
request_info->peer = new_peer;
}
+ base::TimeTicks renderer_completion_time = ToRendererCompletionTime(
+ *request_info, browser_completion_time);
// The request ID will be removed from our pending list in the destructor.
// Normally, dispatching this message causes the reference-counted request to
// die immediately.
- peer->OnCompletedRequest(status, security_info, completion_time);
+ peer->OnCompletedRequest(status, security_info, renderer_completion_time);
}
int ResourceDispatcher::AddPendingRequest(
@@ -579,6 +596,65 @@ webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge(
return new webkit_glue::IPCResourceLoaderBridge(this, request_info);
}
+void ResourceDispatcher::ToResourceResponseInfo(
+ const PendingRequestInfo& request_info,
+ const content::ResourceResponseHead& browser_info,
+ webkit_glue::ResourceResponseInfo* renderer_info) const {
+ *renderer_info = browser_info;
+ if (request_info.request_start.is_null() ||
+ request_info.response_start.is_null() ||
+ browser_info.request_start.is_null() ||
+ browser_info.response_start.is_null()) {
+ return;
+ }
+ content::InterProcessTimeTicksConverter converter(
+ LocalTimeTicks::FromTimeTicks(request_info.request_start),
+ LocalTimeTicks::FromTimeTicks(request_info.response_start),
+ RemoteTimeTicks::FromTimeTicks(browser_info.request_start),
+ RemoteTimeTicks::FromTimeTicks(browser_info.response_start));
+
+ LocalTimeTicks renderer_base_ticks = converter.ToLocalTimeTicks(
+ RemoteTimeTicks::FromTimeTicks(browser_info.load_timing.base_ticks));
+ renderer_info->load_timing.base_ticks = renderer_base_ticks.ToTimeTicks();
+
+#define CONVERT(field) \
+ LocalTimeDelta renderer_##field = converter.ToLocalTimeDelta( \
+ RemoteTimeDelta::FromRawDelta(browser_info.load_timing.field)); \
+ renderer_info->load_timing.field = renderer_##field.ToInt32()
+
+ CONVERT(proxy_start);
+ CONVERT(dns_start);
+ CONVERT(dns_end);
+ CONVERT(connect_start);
+ CONVERT(connect_end);
+ CONVERT(ssl_start);
+ CONVERT(ssl_end);
+ CONVERT(send_start);
+ CONVERT(send_end);
+ CONVERT(receive_headers_start);
+ CONVERT(receive_headers_end);
+
+#undef CONVERT
+}
+
+base::TimeTicks ResourceDispatcher::ToRendererCompletionTime(
+ const PendingRequestInfo& request_info,
+ const base::TimeTicks& browser_completion_time) const {
+ if (request_info.completion_time.is_null()) {
+ return browser_completion_time;
+ }
+
+ // TODO(simonjam): The optimal lower bound should be the most recent value of
+ // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that?
+ // Until then, |response_start| is used as it is the most recent value
+ // returned for this request.
+ int64 result = std::max(browser_completion_time.ToInternalValue(),
+ request_info.response_start.ToInternalValue());
+ result = std::min(result, request_info.completion_time.ToInternalValue());
+ return base::TimeTicks::FromInternalValue(result);
+}
+
+// static
bool ResourceDispatcher::IsResourceDispatcherMessage(
const IPC::Message& message) {
switch (message.type()) {
diff --git a/content/common/resource_dispatcher.h b/content/common/resource_dispatcher.h
index 1b8e3a3..7c5cdba 100644
--- a/content/common/resource_dispatcher.h
+++ b/content/common/resource_dispatcher.h
@@ -15,6 +15,7 @@
#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/shared_memory.h"
+#include "base/time.h"
#include "content/common/content_export.h"
#include "ipc/ipc_channel.h"
#include "webkit/glue/resource_loader_bridge.h"
@@ -79,7 +80,8 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Channel::Listener {
: peer(peer),
resource_type(resource_type),
is_deferred(false),
- url(request_url) {
+ url(request_url),
+ request_start(base::TimeTicks::Now()) {
}
~PendingRequestInfo() { }
webkit_glue::ResourceLoaderBridge::Peer* peer;
@@ -88,6 +90,9 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Channel::Listener {
bool is_deferred;
GURL url;
linked_ptr<IPC::Message> pending_redirect_message;
+ base::TimeTicks request_start;
+ base::TimeTicks response_start;
+ base::TimeTicks completion_time;
};
typedef base::hash_map<int, PendingRequestInfo> PendingRequestList;
@@ -110,7 +115,7 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Channel::Listener {
const IPC::Message& message,
int request_id,
const GURL& new_url,
- const webkit_glue::ResourceResponseInfo& info);
+ const content::ResourceResponseHead& response_head);
void OnReceivedData(
const IPC::Message& message,
int request_id,
@@ -125,7 +130,7 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Channel::Listener {
int request_id,
const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time);
+ const base::TimeTicks& completion_time);
// Dispatch the message to one of the message response handlers.
void DispatchMessage(const IPC::Message& message);
@@ -134,6 +139,15 @@ class CONTENT_EXPORT ResourceDispatcher : public IPC::Channel::Listener {
// again in the deferred state.
void FlushDeferredMessages(int request_id);
+ void ToResourceResponseInfo(
+ const PendingRequestInfo& request_info,
+ const content::ResourceResponseHead& browser_info,
+ webkit_glue::ResourceResponseInfo* renderer_info) const;
+
+ base::TimeTicks ToRendererCompletionTime(
+ const PendingRequestInfo& request_info,
+ const base::TimeTicks& browser_completion_time) const;
+
// Returns true if the message passed in is a resource related message.
static bool IsResourceDispatcherMessage(const IPC::Message& message);
diff --git a/content/common/resource_dispatcher_unittest.cc b/content/common/resource_dispatcher_unittest.cc
index d133bc1..2bc9ebb 100644
--- a/content/common/resource_dispatcher_unittest.cc
+++ b/content/common/resource_dispatcher_unittest.cc
@@ -67,7 +67,7 @@ class TestRequestCallback : public ResourceLoaderBridge::Peer {
virtual void OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time) {
+ const base::TimeTicks& completion_time) {
EXPECT_FALSE(complete_);
complete_ = true;
}
@@ -298,7 +298,7 @@ class DeferredResourceLoadingTest : public ResourceDispatcherTest,
virtual void OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time) {
+ const base::TimeTicks& completion_time) {
}
protected:
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index 95c73ae..1771461 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -169,7 +169,7 @@ IPC_MESSAGE_ROUTED4(ResourceMsg_RequestComplete,
int /* request_id */,
net::URLRequestStatus /* status */,
std::string /* security info */,
- base::Time /* completion_time */)
+ base::TimeTicks /* completion_time */)
// Resource messages sent from the renderer to the browser.
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 7b073dc..7e30d23 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -173,6 +173,8 @@
'common/indexed_db_messages.h',
'common/indexed_db_param_traits.cc',
'common/indexed_db_param_traits.h',
+ 'common/inter_process_time_ticks_converter.cc',
+ 'common/inter_process_time_ticks_converter.h',
'common/intents_messages.h',
'common/java_bridge_messages.h',
'common/mac/attributed_string_coder.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 673a089..e8e36c0 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -244,6 +244,7 @@
'common/gpu/gpu_feature_flags_unittest.cc',
'common/gpu/gpu_info_unittest.cc',
'common/hi_res_timer_manager_unittest.cc',
+ 'common/inter_process_time_ticks_converter_unittest.cc',
'common/net/url_fetcher_impl_unittest.cc',
'common/page_zoom_unittest.cc',
'common/resource_dispatcher_unittest.cc',
diff --git a/content/public/common/resource_response.h b/content/public/common/resource_response.h
index 652ef34..9a8e3a8 100644
--- a/content/public/common/resource_response.h
+++ b/content/public/common/resource_response.h
@@ -23,6 +23,10 @@ namespace content {
struct ResourceResponseHead : webkit_glue::ResourceResponseInfo {
// The response status.
net::URLRequestStatus status;
+ // TimeTicks::Now() when the browser received the request from the renderer.
+ base::TimeTicks request_start;
+ // TimeTicks::Now() when the browser sent the response to the renderer.
+ base::TimeTicks response_start;
};
// Parameters for a synchronous resource response.
diff --git a/content/public/common/webkit_param_traits.cc b/content/public/common/webkit_param_traits.cc
index 555bd77..5d4e059 100644
--- a/content/public/common/webkit_param_traits.cc
+++ b/content/public/common/webkit_param_traits.cc
@@ -40,6 +40,7 @@ void ParamTraits<webkit_glue::ResourceLoadTimingInfo>::Write(
WriteParam(m, p.base_time.is_null());
if (p.base_time.is_null())
return;
+ WriteParam(m, p.base_ticks);
WriteParam(m, p.base_time);
WriteParam(m, p.proxy_start);
WriteParam(m, p.proxy_end);
@@ -64,6 +65,7 @@ bool ParamTraits<webkit_glue::ResourceLoadTimingInfo>::Read(
return true;
return
+ ReadParam(m, iter, &r->base_ticks) &&
ReadParam(m, iter, &r->base_time) &&
ReadParam(m, iter, &r->proxy_start) &&
ReadParam(m, iter, &r->proxy_end) &&
@@ -82,6 +84,8 @@ bool ParamTraits<webkit_glue::ResourceLoadTimingInfo>::Read(
void ParamTraits<webkit_glue::ResourceLoadTimingInfo>::Log(const param_type& p,
std::string* l) {
l->append("(");
+ LogParam(p.base_ticks, l);
+ l->append(", ");
LogParam(p.base_time, l);
l->append(", ");
LogParam(p.proxy_start, l);
diff --git a/content/test/render_view_fake_resources_test.cc b/content/test/render_view_fake_resources_test.cc
index d8769c1..87d67a5 100644
--- a/content/test/render_view_fake_resources_test.cc
+++ b/content/test/render_view_fake_resources_test.cc
@@ -175,7 +175,7 @@ void RenderViewFakeResourcesTest::OnRequestResource(
request_id,
net::URLRequestStatus(),
std::string(),
- base::Time())));
+ base::TimeTicks())));
}
void RenderViewFakeResourcesTest::OnRenderViewReady() {
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index af405d7..0408757 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -152,7 +152,8 @@ URLRequest::URLRequest(const GURL& url, Delegate* delegate)
ALLOW_THIS_IN_INITIALIZER_LIST(before_request_callback_(
base::Bind(&URLRequest::BeforeRequestComplete,
base::Unretained(this)))),
- has_notified_completion_(false) {
+ has_notified_completion_(false),
+ creation_time_(base::TimeTicks::Now()) {
SIMPLE_STATS_COUNTER("URLRequestCount");
// Sanity check out environment.
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 3deb198..5e3ca80 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -15,6 +15,7 @@
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/string16.h"
+#include "base/time.h"
#include "base/threading/non_thread_safe.h"
#include "googleurl/src/gurl.h"
#include "net/base/auth.h"
@@ -48,10 +49,6 @@ class AppCacheRequestHandlerTest;
class AppCacheURLRequestJobTest;
}
-namespace base {
-class Time;
-} // namespace base
-
// Temporary layering violation to allow existing users of a deprecated
// interface.
namespace fileapi {
@@ -456,6 +453,9 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// the response status line. Restrictions on GetResponseHeaders apply.
void GetAllResponseHeaders(std::string* headers);
+ // The time when |this| was constructed.
+ base::TimeTicks creation_time() const { return creation_time_; }
+
// The time at which the returned response was requested. For cached
// responses, this is the last time the cache entry was validated.
const base::Time& request_time() const {
@@ -814,6 +814,8 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe) {
AuthCredentials auth_credentials_;
scoped_refptr<AuthChallengeInfo> auth_info_;
+ base::TimeTicks creation_time_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequest);
};
diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h
index 8976463..c86b998 100644
--- a/webkit/glue/resource_loader_bridge.h
+++ b/webkit/glue/resource_loader_bridge.h
@@ -53,8 +53,11 @@ struct ResourceLoadTimingInfo {
WEBKIT_GLUE_EXPORT ResourceLoadTimingInfo();
WEBKIT_GLUE_EXPORT ~ResourceLoadTimingInfo();
- // All the values in this struct are given as offsets in milliseconds wrt
- // this base time.
+ // All the values in this struct are given as offsets in ticks wrt
+ // this base tick count.
+ base::TimeTicks base_ticks;
+
+ // The value of Time::Now() when base_ticks was set.
base::Time base_time;
// The time that proxy processing started. For requests with no proxy phase,
@@ -329,9 +332,10 @@ class ResourceLoaderBridge {
// Called when the response is complete. This method signals completion of
// the resource load.ff
- virtual void OnCompletedRequest(const net::URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) = 0;
+ virtual void OnCompletedRequest(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ const base::TimeTicks& completion_time) = 0;
};
// use WebKitPlatformSupportImpl::CreateResourceLoader() for construction, but
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index 7df6ace..8315b61 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -36,7 +36,7 @@
#include "webkit/glue/weburlrequest_extradata_impl.h"
using base::Time;
-using base::TimeDelta;
+using base::TimeTicks;
using WebKit::WebData;
using WebKit::WebHTTPBody;
using WebKit::WebHTTPHeaderVisitor;
@@ -124,6 +124,7 @@ bool GetInfoFromDataURL(const GURL& url,
// Assure same time for all time fields of data: URLs.
Time now = Time::Now();
info->load_timing.base_time = now;
+ info->load_timing.base_ticks = TimeTicks::Now();
info->request_time = now;
info->response_time = now;
info->headers = NULL;
@@ -173,7 +174,7 @@ void PopulateURLResponse(
if (!timing_info.base_time.is_null()) {
WebURLLoadTiming timing;
timing.initialize();
- timing.setRequestTime(timing_info.base_time.ToDoubleT());
+ timing.setRequestTime((timing_info.base_ticks - TimeTicks()).InSecondsF());
timing.setProxyStart(timing_info.proxy_start);
timing.setProxyEnd(timing_info.proxy_end);
timing.setDNSStart(timing_info.dns_start);
@@ -284,7 +285,7 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
virtual void OnReceivedCachedMetadata(const char* data, int len);
virtual void OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time);
+ const base::TimeTicks& completion_time);
private:
friend class base::RefCounted<Context>;
@@ -610,7 +611,7 @@ void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
void WebURLLoaderImpl::Context::OnCompletedRequest(
const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& completion_time) {
+ const base::TimeTicks& completion_time) {
if (ftp_listing_delegate_.get()) {
ftp_listing_delegate_->OnCompletedRequest();
ftp_listing_delegate_.reset(NULL);
@@ -642,7 +643,8 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
error.unreachableURL = request_.url();
client_->didFail(loader_, error);
} else {
- client_->didFinishLoading(loader_, completion_time.ToDoubleT());
+ client_->didFinishLoading(
+ loader_, (completion_time - TimeTicks()).InSecondsF());
}
}
@@ -686,7 +688,7 @@ void WebURLLoaderImpl::Context::HandleDataURL() {
OnReceivedData(data.data(), data.size(), 0);
}
- OnCompletedRequest(status, info.security_info, base::Time::Now());
+ OnCompletedRequest(status, info.security_info, base::TimeTicks::Now());
}
// WebURLLoaderImpl -----------------------------------------------------------
diff --git a/webkit/tools/layout_tests/test_expectations.txt b/webkit/tools/layout_tests/test_expectations.txt
index 668f5a9b..707c890 100644
--- a/webkit/tools/layout_tests/test_expectations.txt
+++ b/webkit/tools/layout_tests/test_expectations.txt
@@ -6,8 +6,3 @@
// until the changes can be landed upstream.
// PLEASE DO NOT LEAVE ENTRIES IN THIS FILE FOR MORE THAN 24 HRS.
-
-BUGCR107668: fast/speech/input-appearance-numberandspeech.html = IMAGE
-BUGCR107668: fast/speech/input-appearance-searchandspeech.html = IMAGE
-BUGCR107668: fast/speech/input-appearance-speechbutton.html = IMAGE
-BUGCR107668: fast/speech/speech-bidi-rendering.html = IMAGE
diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
index 6ce3e9c..958d662 100644
--- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
+++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
@@ -288,7 +288,7 @@ class RequestProxy : public net::URLRequest::Delegate,
void NotifyCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& complete_time) {
+ const base::TimeTicks& complete_time) {
if (peer_) {
peer_->OnCompletedRequest(status, security_info, complete_time);
DropPeer(); // ensure no further notifications
@@ -423,7 +423,7 @@ class RequestProxy : public net::URLRequest::Delegate,
virtual void OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& complete_time) {
+ const base::TimeTicks& complete_time) {
if (download_to_file_)
file_stream_.Close();
owner_loop_->PostTask(
@@ -519,7 +519,7 @@ class RequestProxy : public net::URLRequest::Delegate,
// |failed_file_request_status_|. Otherwise use request_'s status.
OnCompletedRequest(failed_file_request_status_.get() ?
*failed_file_request_status_ : request_->status(),
- std::string(), base::Time());
+ std::string(), base::TimeTicks());
request_.reset(); // destroy on the io thread
}
@@ -729,7 +729,7 @@ class SyncRequestProxy : public RequestProxy {
virtual void OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
- const base::Time& complete_time) {
+ const base::TimeTicks& complete_time) {
if (download_to_file_)
file_stream_.Close();
result_->status = status;