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