Upstream version 10.39.225.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 }
55
56 unsigned long long PerformanceTiming::navigationStart() const
57 {
58     DocumentLoadTiming* timing = documentLoadTiming();
59     if (!timing)
60         return 0;
61
62     return monotonicTimeToIntegerMilliseconds(timing->navigationStart());
63 }
64
65 unsigned long long PerformanceTiming::unloadEventStart() const
66 {
67     DocumentLoadTiming* timing = documentLoadTiming();
68     if (!timing)
69         return 0;
70
71     if (timing->hasCrossOriginRedirect() || !timing->hasSameOriginAsPreviousDocument())
72         return 0;
73
74     return monotonicTimeToIntegerMilliseconds(timing->unloadEventStart());
75 }
76
77 unsigned long long PerformanceTiming::unloadEventEnd() const
78 {
79     DocumentLoadTiming* timing = documentLoadTiming();
80     if (!timing)
81         return 0;
82
83     if (timing->hasCrossOriginRedirect() || !timing->hasSameOriginAsPreviousDocument())
84         return 0;
85
86     return monotonicTimeToIntegerMilliseconds(timing->unloadEventEnd());
87 }
88
89 unsigned long long PerformanceTiming::redirectStart() const
90 {
91     DocumentLoadTiming* timing = documentLoadTiming();
92     if (!timing)
93         return 0;
94
95     if (timing->hasCrossOriginRedirect())
96         return 0;
97
98     return monotonicTimeToIntegerMilliseconds(timing->redirectStart());
99 }
100
101 unsigned long long PerformanceTiming::redirectEnd() const
102 {
103     DocumentLoadTiming* timing = documentLoadTiming();
104     if (!timing)
105         return 0;
106
107     if (timing->hasCrossOriginRedirect())
108         return 0;
109
110     return monotonicTimeToIntegerMilliseconds(timing->redirectEnd());
111 }
112
113 unsigned long long PerformanceTiming::fetchStart() const
114 {
115     DocumentLoadTiming* timing = documentLoadTiming();
116     if (!timing)
117         return 0;
118
119     return monotonicTimeToIntegerMilliseconds(timing->fetchStart());
120 }
121
122 unsigned long long PerformanceTiming::domainLookupStart() const
123 {
124     ResourceLoadTiming* timing = resourceLoadTiming();
125     if (!timing)
126         return fetchStart();
127
128     // This will be zero when a DNS request is not performed.
129     // Rather than exposing a special value that indicates no DNS, we "backfill" with fetchStart.
130     double dnsStart = timing->dnsStart;
131     if (dnsStart == 0.0)
132         return fetchStart();
133
134     return monotonicTimeToIntegerMilliseconds(dnsStart);
135 }
136
137 unsigned long long PerformanceTiming::domainLookupEnd() const
138 {
139     ResourceLoadTiming* timing = resourceLoadTiming();
140     if (!timing)
141         return domainLookupStart();
142
143     // This will be zero when a DNS request is not performed.
144     // Rather than exposing a special value that indicates no DNS, we "backfill" with domainLookupStart.
145     double dnsEnd = timing->dnsEnd;
146     if (dnsEnd == 0.0)
147         return domainLookupStart();
148
149     return monotonicTimeToIntegerMilliseconds(dnsEnd);
150 }
151
152 unsigned long long PerformanceTiming::connectStart() const
153 {
154     DocumentLoader* loader = documentLoader();
155     if (!loader)
156         return domainLookupEnd();
157
158     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
159     if (!timing)
160         return domainLookupEnd();
161
162     // connectStart will be zero when a network request is not made.
163     // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd.
164     double connectStart = timing->connectStart;
165     if (connectStart == 0.0 || loader->response().connectionReused())
166         return domainLookupEnd();
167
168     // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's
169     // connect phase should not. So if there is DNS time, trim it from the start.
170     if (timing->dnsEnd > 0.0 && timing->dnsEnd > connectStart)
171         connectStart = timing->dnsEnd;
172
173     return monotonicTimeToIntegerMilliseconds(connectStart);
174 }
175
176 unsigned long long PerformanceTiming::connectEnd() const
177 {
178     DocumentLoader* loader = documentLoader();
179     if (!loader)
180         return connectStart();
181
182     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
183     if (!timing)
184         return connectStart();
185
186     // connectEnd will be zero when a network request is not made.
187     // Rather than exposing a special value that indicates no new connection, we "backfill" with connectStart.
188     double connectEnd = timing->connectEnd;
189     if (connectEnd == 0.0 || loader->response().connectionReused())
190         return connectStart();
191
192     return monotonicTimeToIntegerMilliseconds(connectEnd);
193 }
194
195 unsigned long long PerformanceTiming::secureConnectionStart() const
196 {
197     DocumentLoader* loader = documentLoader();
198     if (!loader)
199         return 0;
200
201     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
202     if (!timing)
203         return 0;
204
205     double sslStart = timing->sslStart;
206     if (sslStart == 0.0)
207         return 0;
208
209     return monotonicTimeToIntegerMilliseconds(sslStart);
210 }
211
212 unsigned long long PerformanceTiming::requestStart() const
213 {
214     ResourceLoadTiming* timing = resourceLoadTiming();
215
216     if (!timing || timing->sendStart == 0.0)
217         return connectEnd();
218
219     return monotonicTimeToIntegerMilliseconds(timing->sendStart);
220 }
221
222 unsigned long long PerformanceTiming::responseStart() const
223 {
224     ResourceLoadTiming* timing = resourceLoadTiming();
225     if (!timing || timing->receiveHeadersEnd == 0.0)
226         return requestStart();
227
228     // FIXME: Response start needs to be the time of the first received byte.
229     // However, the ResourceLoadTiming API currently only supports the time
230     // the last header byte was received. For many responses with reasonable
231     // sized cookies, the HTTP headers fit into a single packet so this time
232     // is basically equivalent. But for some responses, particularly those with
233     // headers larger than a single packet, this time will be too late.
234     return monotonicTimeToIntegerMilliseconds(timing->receiveHeadersEnd);
235 }
236
237 unsigned long long PerformanceTiming::responseEnd() const
238 {
239     DocumentLoadTiming* timing = documentLoadTiming();
240     if (!timing)
241         return 0;
242
243     return monotonicTimeToIntegerMilliseconds(timing->responseEnd());
244 }
245
246 unsigned long long PerformanceTiming::domLoading() const
247 {
248     const DocumentTiming* timing = documentTiming();
249     if (!timing)
250         return fetchStart();
251
252     return monotonicTimeToIntegerMilliseconds(timing->domLoading);
253 }
254
255 unsigned long long PerformanceTiming::domInteractive() const
256 {
257     const DocumentTiming* timing = documentTiming();
258     if (!timing)
259         return 0;
260
261     return monotonicTimeToIntegerMilliseconds(timing->domInteractive);
262 }
263
264 unsigned long long PerformanceTiming::domContentLoadedEventStart() const
265 {
266     const DocumentTiming* timing = documentTiming();
267     if (!timing)
268         return 0;
269
270     return monotonicTimeToIntegerMilliseconds(timing->domContentLoadedEventStart);
271 }
272
273 unsigned long long PerformanceTiming::domContentLoadedEventEnd() const
274 {
275     const DocumentTiming* timing = documentTiming();
276     if (!timing)
277         return 0;
278
279     return monotonicTimeToIntegerMilliseconds(timing->domContentLoadedEventEnd);
280 }
281
282 unsigned long long PerformanceTiming::domComplete() const
283 {
284     const DocumentTiming* timing = documentTiming();
285     if (!timing)
286         return 0;
287
288     return monotonicTimeToIntegerMilliseconds(timing->domComplete);
289 }
290
291 unsigned long long PerformanceTiming::loadEventStart() const
292 {
293     DocumentLoadTiming* timing = documentLoadTiming();
294     if (!timing)
295         return 0;
296
297     return monotonicTimeToIntegerMilliseconds(timing->loadEventStart());
298 }
299
300 unsigned long long PerformanceTiming::loadEventEnd() const
301 {
302     DocumentLoadTiming* timing = documentLoadTiming();
303     if (!timing)
304         return 0;
305
306     return monotonicTimeToIntegerMilliseconds(timing->loadEventEnd());
307 }
308
309 DocumentLoader* PerformanceTiming::documentLoader() const
310 {
311     if (!m_frame)
312         return 0;
313
314     return m_frame->loader().documentLoader();
315 }
316
317 const DocumentTiming* PerformanceTiming::documentTiming() const
318 {
319     if (!m_frame)
320         return 0;
321
322     Document* document = m_frame->document();
323     if (!document)
324         return 0;
325
326     return &document->timing();
327 }
328
329 DocumentLoadTiming* PerformanceTiming::documentLoadTiming() const
330 {
331     DocumentLoader* loader = documentLoader();
332     if (!loader)
333         return 0;
334
335     return loader->timing();
336 }
337
338 ResourceLoadTiming* PerformanceTiming::resourceLoadTiming() const
339 {
340     DocumentLoader* loader = documentLoader();
341     if (!loader)
342         return 0;
343
344     return loader->response().resourceLoadTiming();
345 }
346
347 unsigned long long PerformanceTiming::monotonicTimeToIntegerMilliseconds(double monotonicSeconds) const
348 {
349     ASSERT(monotonicSeconds >= 0);
350     const DocumentLoadTiming* timing = documentLoadTiming();
351     if (!timing)
352         return 0;
353
354     return toIntegerMilliseconds(timing->monotonicTimeToPseudoWallTime(monotonicSeconds));
355 }
356
357 void PerformanceTiming::trace(Visitor* visitor)
358 {
359     DOMWindowProperty::trace(visitor);
360 }
361
362 } // namespace blink