Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / timing / PerformanceTiming.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "core/timing/PerformanceTiming.h"
33
34 #include "core/dom/Document.h"
35 #include "core/dom/DocumentTiming.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/loader/DocumentLoadTiming.h"
38 #include "core/loader/DocumentLoader.h"
39 #include "core/loader/FrameLoader.h"
40 #include "platform/network/ResourceLoadTiming.h"
41 #include "platform/network/ResourceResponse.h"
42
43 namespace blink {
44
45 static unsigned long long toIntegerMilliseconds(double seconds)
46 {
47     ASSERT(seconds >= 0);
48     return static_cast<unsigned long long>(seconds * 1000.0);
49 }
50
51 PerformanceTiming::PerformanceTiming(LocalFrame* frame)
52     : DOMWindowProperty(frame)
53 {
54     ScriptWrappable::init(this);
55 }
56
57 unsigned long long PerformanceTiming::navigationStart() const
58 {
59     DocumentLoadTiming* timing = documentLoadTiming();
60     if (!timing)
61         return 0;
62
63     return monotonicTimeToIntegerMilliseconds(timing->navigationStart());
64 }
65
66 unsigned long long PerformanceTiming::unloadEventStart() const
67 {
68     DocumentLoadTiming* timing = documentLoadTiming();
69     if (!timing)
70         return 0;
71
72     if (timing->hasCrossOriginRedirect() || !timing->hasSameOriginAsPreviousDocument())
73         return 0;
74
75     return monotonicTimeToIntegerMilliseconds(timing->unloadEventStart());
76 }
77
78 unsigned long long PerformanceTiming::unloadEventEnd() const
79 {
80     DocumentLoadTiming* timing = documentLoadTiming();
81     if (!timing)
82         return 0;
83
84     if (timing->hasCrossOriginRedirect() || !timing->hasSameOriginAsPreviousDocument())
85         return 0;
86
87     return monotonicTimeToIntegerMilliseconds(timing->unloadEventEnd());
88 }
89
90 unsigned long long PerformanceTiming::redirectStart() const
91 {
92     DocumentLoadTiming* timing = documentLoadTiming();
93     if (!timing)
94         return 0;
95
96     if (timing->hasCrossOriginRedirect())
97         return 0;
98
99     return monotonicTimeToIntegerMilliseconds(timing->redirectStart());
100 }
101
102 unsigned long long PerformanceTiming::redirectEnd() const
103 {
104     DocumentLoadTiming* timing = documentLoadTiming();
105     if (!timing)
106         return 0;
107
108     if (timing->hasCrossOriginRedirect())
109         return 0;
110
111     return monotonicTimeToIntegerMilliseconds(timing->redirectEnd());
112 }
113
114 unsigned long long PerformanceTiming::fetchStart() const
115 {
116     DocumentLoadTiming* timing = documentLoadTiming();
117     if (!timing)
118         return 0;
119
120     return monotonicTimeToIntegerMilliseconds(timing->fetchStart());
121 }
122
123 unsigned long long PerformanceTiming::domainLookupStart() const
124 {
125     ResourceLoadTiming* timing = resourceLoadTiming();
126     if (!timing)
127         return fetchStart();
128
129     // This will be zero when a DNS request is not performed.
130     // Rather than exposing a special value that indicates no DNS, we "backfill" with fetchStart.
131     double dnsStart = timing->dnsStart;
132     if (dnsStart == 0.0)
133         return fetchStart();
134
135     return monotonicTimeToIntegerMilliseconds(dnsStart);
136 }
137
138 unsigned long long PerformanceTiming::domainLookupEnd() const
139 {
140     ResourceLoadTiming* timing = resourceLoadTiming();
141     if (!timing)
142         return domainLookupStart();
143
144     // This will be zero when a DNS request is not performed.
145     // Rather than exposing a special value that indicates no DNS, we "backfill" with domainLookupStart.
146     double dnsEnd = timing->dnsEnd;
147     if (dnsEnd == 0.0)
148         return domainLookupStart();
149
150     return monotonicTimeToIntegerMilliseconds(dnsEnd);
151 }
152
153 unsigned long long PerformanceTiming::connectStart() const
154 {
155     DocumentLoader* loader = documentLoader();
156     if (!loader)
157         return domainLookupEnd();
158
159     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
160     if (!timing)
161         return domainLookupEnd();
162
163     // connectStart will be zero when a network request is not made.
164     // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd.
165     double connectStart = timing->connectStart;
166     if (connectStart == 0.0 || loader->response().connectionReused())
167         return domainLookupEnd();
168
169     // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's
170     // connect phase should not. So if there is DNS time, trim it from the start.
171     if (timing->dnsEnd > 0.0 && timing->dnsEnd > connectStart)
172         connectStart = timing->dnsEnd;
173
174     return monotonicTimeToIntegerMilliseconds(connectStart);
175 }
176
177 unsigned long long PerformanceTiming::connectEnd() const
178 {
179     DocumentLoader* loader = documentLoader();
180     if (!loader)
181         return connectStart();
182
183     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
184     if (!timing)
185         return connectStart();
186
187     // connectEnd will be zero when a network request is not made.
188     // Rather than exposing a special value that indicates no new connection, we "backfill" with connectStart.
189     double connectEnd = timing->connectEnd;
190     if (connectEnd == 0.0 || loader->response().connectionReused())
191         return connectStart();
192
193     return monotonicTimeToIntegerMilliseconds(connectEnd);
194 }
195
196 unsigned long long PerformanceTiming::secureConnectionStart() const
197 {
198     DocumentLoader* loader = documentLoader();
199     if (!loader)
200         return 0;
201
202     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
203     if (!timing)
204         return 0;
205
206     double sslStart = timing->sslStart;
207     if (sslStart == 0.0)
208         return 0;
209
210     return monotonicTimeToIntegerMilliseconds(sslStart);
211 }
212
213 unsigned long long PerformanceTiming::requestStart() const
214 {
215     ResourceLoadTiming* timing = resourceLoadTiming();
216
217     if (!timing || timing->sendStart == 0.0)
218         return connectEnd();
219
220     return monotonicTimeToIntegerMilliseconds(timing->sendStart);
221 }
222
223 unsigned long long PerformanceTiming::responseStart() const
224 {
225     ResourceLoadTiming* timing = resourceLoadTiming();
226     if (!timing || timing->receiveHeadersEnd == 0.0)
227         return requestStart();
228
229     // FIXME: Response start needs to be the time of the first received byte.
230     // However, the ResourceLoadTiming API currently only supports the time
231     // the last header byte was received. For many responses with reasonable
232     // sized cookies, the HTTP headers fit into a single packet so this time
233     // is basically equivalent. But for some responses, particularly those with
234     // headers larger than a single packet, this time will be too late.
235     return monotonicTimeToIntegerMilliseconds(timing->receiveHeadersEnd);
236 }
237
238 unsigned long long PerformanceTiming::responseEnd() const
239 {
240     DocumentLoadTiming* timing = documentLoadTiming();
241     if (!timing)
242         return 0;
243
244     return monotonicTimeToIntegerMilliseconds(timing->responseEnd());
245 }
246
247 unsigned long long PerformanceTiming::domLoading() const
248 {
249     const DocumentTiming* timing = documentTiming();
250     if (!timing)
251         return fetchStart();
252
253     return monotonicTimeToIntegerMilliseconds(timing->domLoading);
254 }
255
256 unsigned long long PerformanceTiming::domInteractive() const
257 {
258     const DocumentTiming* timing = documentTiming();
259     if (!timing)
260         return 0;
261
262     return monotonicTimeToIntegerMilliseconds(timing->domInteractive);
263 }
264
265 unsigned long long PerformanceTiming::domContentLoadedEventStart() const
266 {
267     const DocumentTiming* timing = documentTiming();
268     if (!timing)
269         return 0;
270
271     return monotonicTimeToIntegerMilliseconds(timing->domContentLoadedEventStart);
272 }
273
274 unsigned long long PerformanceTiming::domContentLoadedEventEnd() const
275 {
276     const DocumentTiming* timing = documentTiming();
277     if (!timing)
278         return 0;
279
280     return monotonicTimeToIntegerMilliseconds(timing->domContentLoadedEventEnd);
281 }
282
283 unsigned long long PerformanceTiming::domComplete() const
284 {
285     const DocumentTiming* timing = documentTiming();
286     if (!timing)
287         return 0;
288
289     return monotonicTimeToIntegerMilliseconds(timing->domComplete);
290 }
291
292 unsigned long long PerformanceTiming::loadEventStart() const
293 {
294     DocumentLoadTiming* timing = documentLoadTiming();
295     if (!timing)
296         return 0;
297
298     return monotonicTimeToIntegerMilliseconds(timing->loadEventStart());
299 }
300
301 unsigned long long PerformanceTiming::loadEventEnd() const
302 {
303     DocumentLoadTiming* timing = documentLoadTiming();
304     if (!timing)
305         return 0;
306
307     return monotonicTimeToIntegerMilliseconds(timing->loadEventEnd());
308 }
309
310 DocumentLoader* PerformanceTiming::documentLoader() const
311 {
312     if (!m_frame)
313         return 0;
314
315     return m_frame->loader().documentLoader();
316 }
317
318 const DocumentTiming* PerformanceTiming::documentTiming() const
319 {
320     if (!m_frame)
321         return 0;
322
323     Document* document = m_frame->document();
324     if (!document)
325         return 0;
326
327     return &document->timing();
328 }
329
330 DocumentLoadTiming* PerformanceTiming::documentLoadTiming() const
331 {
332     DocumentLoader* loader = documentLoader();
333     if (!loader)
334         return 0;
335
336     return loader->timing();
337 }
338
339 ResourceLoadTiming* PerformanceTiming::resourceLoadTiming() const
340 {
341     DocumentLoader* loader = documentLoader();
342     if (!loader)
343         return 0;
344
345     return loader->response().resourceLoadTiming();
346 }
347
348 unsigned long long PerformanceTiming::monotonicTimeToIntegerMilliseconds(double monotonicSeconds) const
349 {
350     ASSERT(monotonicSeconds >= 0);
351     const DocumentLoadTiming* timing = documentLoadTiming();
352     if (!timing)
353         return 0;
354
355     return toIntegerMilliseconds(timing->monotonicTimeToPseudoWallTime(monotonicSeconds));
356 }
357
358 } // namespace blink