OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 * (C) 2000 Simon Hausmann <hausmann@kde.org> | 4 * (C) 2000 Simon Hausmann <hausmann@kde.org> |
5 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv
ed. | 5 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv
ed. |
6 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) | 6 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 #include "core/page/Chrome.h" | 43 #include "core/page/Chrome.h" |
44 #include "core/page/ChromeClient.h" | 44 #include "core/page/ChromeClient.h" |
45 #include "core/rendering/RenderImage.h" | 45 #include "core/rendering/RenderImage.h" |
46 #include "platform/PlatformMouseEvent.h" | 46 #include "platform/PlatformMouseEvent.h" |
47 #include "platform/network/DNS.h" | 47 #include "platform/network/DNS.h" |
48 #include "platform/network/ResourceRequest.h" | 48 #include "platform/network/ResourceRequest.h" |
49 #include "platform/weborigin/KnownPorts.h" | 49 #include "platform/weborigin/KnownPorts.h" |
50 #include "platform/weborigin/SecurityOrigin.h" | 50 #include "platform/weborigin/SecurityOrigin.h" |
51 #include "platform/weborigin/SecurityPolicy.h" | 51 #include "platform/weborigin/SecurityPolicy.h" |
52 #include "public/platform/Platform.h" | 52 #include "public/platform/Platform.h" |
53 #include "public/platform/WebPrescientNetworking.h" | |
54 #include "public/platform/WebURL.h" | 53 #include "public/platform/WebURL.h" |
55 #include "wtf/text/StringBuilder.h" | 54 #include "wtf/text/StringBuilder.h" |
56 | 55 |
57 namespace WebCore { | 56 namespace WebCore { |
58 | 57 |
59 namespace { | |
60 | |
61 void preconnectToURL(const KURL& url, blink::WebPreconnectMotivation motivation) | |
62 { | |
63 blink::WebPrescientNetworking* prescientNetworking = blink::Platform::curren
t()->prescientNetworking(); | |
64 if (!prescientNetworking) | |
65 return; | |
66 | |
67 prescientNetworking->preconnect(url, motivation); | |
68 } | |
69 | |
70 } | |
71 | |
72 class HTMLAnchorElement::PrefetchEventHandler FINAL : public NoBaseWillBeGarbage
Collected<HTMLAnchorElement::PrefetchEventHandler> { | |
73 public: | |
74 static PassOwnPtrWillBeRawPtr<PrefetchEventHandler> create(HTMLAnchorElement
* anchorElement) | |
75 { | |
76 return adoptPtrWillBeNoop(new HTMLAnchorElement::PrefetchEventHandler(an
chorElement)); | |
77 } | |
78 | |
79 void reset(); | |
80 | |
81 void handleEvent(Event* e); | |
82 void didChangeHREF() { m_hadHREFChanged = true; } | |
83 bool hasIssuedPreconnect() const { return m_hasIssuedPreconnect; } | |
84 | |
85 void trace(Visitor* visitor) { visitor->trace(m_anchorElement); } | |
86 | |
87 private: | |
88 explicit PrefetchEventHandler(HTMLAnchorElement*); | |
89 | |
90 void handleMouseOver(Event* event); | |
91 void handleMouseOut(Event* event); | |
92 void handleLeftMouseDown(Event* event); | |
93 void handleGestureTapUnconfirmed(Event*); | |
94 void handleGestureShowPress(Event*); | |
95 void handleClick(Event* event); | |
96 | |
97 bool shouldPrefetch(const KURL&); | |
98 void prefetch(blink::WebPreconnectMotivation); | |
99 | |
100 RawPtrWillBeMember<HTMLAnchorElement> m_anchorElement; | |
101 double m_mouseOverTimestamp; | |
102 double m_mouseDownTimestamp; | |
103 double m_tapDownTimestamp; | |
104 bool m_hadHREFChanged; | |
105 bool m_hadTapUnconfirmed; | |
106 bool m_hasIssuedPreconnect; | |
107 }; | |
108 | |
109 using namespace HTMLNames; | 58 using namespace HTMLNames; |
110 | 59 |
111 HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tagName, Document& doc
ument) | 60 HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tagName, Document& doc
ument) |
112 : HTMLElement(tagName, document) | 61 : HTMLElement(tagName, document) |
113 , m_linkRelations(0) | 62 , m_linkRelations(0) |
114 , m_cachedVisitedLinkHash(0) | 63 , m_cachedVisitedLinkHash(0) |
115 { | 64 { |
116 ScriptWrappable::init(this); | 65 ScriptWrappable::init(this); |
117 } | 66 } |
118 | 67 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 | 135 |
187 void HTMLAnchorElement::defaultEventHandler(Event* event) | 136 void HTMLAnchorElement::defaultEventHandler(Event* event) |
188 { | 137 { |
189 if (isLink()) { | 138 if (isLink()) { |
190 if (focused() && isEnterKeyKeydownEvent(event) && isLiveLink()) { | 139 if (focused() && isEnterKeyKeydownEvent(event) && isLiveLink()) { |
191 event->setDefaultHandled(); | 140 event->setDefaultHandled(); |
192 dispatchSimulatedClick(event); | 141 dispatchSimulatedClick(event); |
193 return; | 142 return; |
194 } | 143 } |
195 | 144 |
196 prefetchEventHandler()->handleEvent(event); | |
197 | |
198 if (isLinkClick(event) && isLiveLink()) { | 145 if (isLinkClick(event) && isLiveLink()) { |
199 handleClick(event); | 146 handleClick(event); |
200 prefetchEventHandler()->reset(); | |
201 return; | 147 return; |
202 } | 148 } |
203 } | 149 } |
204 | 150 |
205 HTMLElement::defaultEventHandler(event); | 151 HTMLElement::defaultEventHandler(event); |
206 } | 152 } |
207 | 153 |
208 void HTMLAnchorElement::setActive(bool down) | 154 void HTMLAnchorElement::setActive(bool down) |
209 { | 155 { |
210 if (rendererIsEditable()) | 156 if (rendererIsEditable()) |
(...skipping 14 matching lines...) Expand all Loading... |
225 // events here. | 171 // events here. |
226 document().setNeedsFocusedElementCheck(); | 172 document().setNeedsFocusedElementCheck(); |
227 } | 173 } |
228 } | 174 } |
229 if (isLink()) { | 175 if (isLink()) { |
230 String parsedURL = stripLeadingAndTrailingHTMLSpaces(value); | 176 String parsedURL = stripLeadingAndTrailingHTMLSpaces(value); |
231 if (document().isDNSPrefetchEnabled()) { | 177 if (document().isDNSPrefetchEnabled()) { |
232 if (protocolIs(parsedURL, "http") || protocolIs(parsedURL, "http
s") || parsedURL.startsWith("//")) | 178 if (protocolIs(parsedURL, "http") || protocolIs(parsedURL, "http
s") || parsedURL.startsWith("//")) |
233 prefetchDNS(document().completeURL(parsedURL).host()); | 179 prefetchDNS(document().completeURL(parsedURL).host()); |
234 } | 180 } |
235 | |
236 if (wasLink) | |
237 prefetchEventHandler()->didChangeHREF(); | |
238 } | 181 } |
239 invalidateCachedVisitedLinkHash(); | 182 invalidateCachedVisitedLinkHash(); |
240 } else if (name == nameAttr || name == titleAttr) { | 183 } else if (name == nameAttr || name == titleAttr) { |
241 // Do nothing. | 184 // Do nothing. |
242 } else if (name == relAttr) | 185 } else if (name == relAttr) |
243 setRel(value); | 186 setRel(value); |
244 else | 187 else |
245 HTMLElement::parseAttribute(name, value); | 188 HTMLElement::parseAttribute(name, value); |
246 } | 189 } |
247 | 190 |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 StringBuilder url; | 310 StringBuilder url; |
368 url.append(stripLeadingAndTrailingHTMLSpaces(fastGetAttribute(hrefAttr))); | 311 url.append(stripLeadingAndTrailingHTMLSpaces(fastGetAttribute(hrefAttr))); |
369 appendServerMapMousePosition(url, event); | 312 appendServerMapMousePosition(url, event); |
370 KURL completedURL = document().completeURL(url.toString()); | 313 KURL completedURL = document().completeURL(url.toString()); |
371 | 314 |
372 // Schedule the ping before the frame load. Prerender in Chrome may kill the
renderer as soon as the navigation is | 315 // Schedule the ping before the frame load. Prerender in Chrome may kill the
renderer as soon as the navigation is |
373 // sent out. | 316 // sent out. |
374 sendPings(completedURL); | 317 sendPings(completedURL); |
375 | 318 |
376 ResourceRequest request(completedURL); | 319 ResourceRequest request(completedURL); |
377 if (prefetchEventHandler()->hasIssuedPreconnect()) | |
378 frame->loader().client()->dispatchWillRequestAfterPreconnect(request); | |
379 if (hasAttribute(downloadAttr)) { | 320 if (hasAttribute(downloadAttr)) { |
380 if (!hasRel(RelationNoReferrer)) { | 321 if (!hasRel(RelationNoReferrer)) { |
381 String referrer = SecurityPolicy::generateReferrerHeader(document().
referrerPolicy(), completedURL, document().outgoingReferrer()); | 322 String referrer = SecurityPolicy::generateReferrerHeader(document().
referrerPolicy(), completedURL, document().outgoingReferrer()); |
382 if (!referrer.isEmpty()) | 323 if (!referrer.isEmpty()) |
383 request.setHTTPReferrer(Referrer(referrer, document().referrerPo
licy())); | 324 request.setHTTPReferrer(Referrer(referrer, document().referrerPo
licy())); |
384 } | 325 } |
385 | 326 |
386 bool isSameOrigin = completedURL.protocolIsData() || document().security
Origin()->canRequest(completedURL); | 327 bool isSameOrigin = completedURL.protocolIsData() || document().security
Origin()->canRequest(completedURL); |
387 const AtomicString& suggestedName = (isSameOrigin ? fastGetAttribute(dow
nloadAttr) : nullAtom); | 328 const AtomicString& suggestedName = (isSameOrigin ? fastGetAttribute(dow
nloadAttr) : nullAtom); |
388 | 329 |
(...skipping 15 matching lines...) Expand all Loading... |
404 bool isLinkClick(Event* event) | 345 bool isLinkClick(Event* event) |
405 { | 346 { |
406 return event->type() == EventTypeNames::click && (!event->isMouseEvent() ||
toMouseEvent(event)->button() != RightButton); | 347 return event->type() == EventTypeNames::click && (!event->isMouseEvent() ||
toMouseEvent(event)->button() != RightButton); |
407 } | 348 } |
408 | 349 |
409 bool HTMLAnchorElement::willRespondToMouseClickEvents() | 350 bool HTMLAnchorElement::willRespondToMouseClickEvents() |
410 { | 351 { |
411 return isLink() || HTMLElement::willRespondToMouseClickEvents(); | 352 return isLink() || HTMLElement::willRespondToMouseClickEvents(); |
412 } | 353 } |
413 | 354 |
414 HTMLAnchorElement::PrefetchEventHandler* HTMLAnchorElement::prefetchEventHandler
() | |
415 { | |
416 if (!m_prefetchEventHandler) | |
417 m_prefetchEventHandler = PrefetchEventHandler::create(this); | |
418 | |
419 return m_prefetchEventHandler.get(); | |
420 } | |
421 | |
422 HTMLAnchorElement::PrefetchEventHandler::PrefetchEventHandler(HTMLAnchorElement*
anchorElement) | |
423 : m_anchorElement(anchorElement) | |
424 { | |
425 ASSERT(m_anchorElement); | |
426 | |
427 reset(); | |
428 } | |
429 | |
430 void HTMLAnchorElement::PrefetchEventHandler::reset() | |
431 { | |
432 m_hadHREFChanged = false; | |
433 m_mouseOverTimestamp = 0; | |
434 m_mouseDownTimestamp = 0; | |
435 m_hadTapUnconfirmed = false; | |
436 m_tapDownTimestamp = 0; | |
437 m_hasIssuedPreconnect = false; | |
438 } | |
439 | |
440 void HTMLAnchorElement::PrefetchEventHandler::handleEvent(Event* event) | |
441 { | |
442 if (!shouldPrefetch(m_anchorElement->href())) | |
443 return; | |
444 | |
445 if (event->type() == EventTypeNames::mouseover) | |
446 handleMouseOver(event); | |
447 else if (event->type() == EventTypeNames::mouseout) | |
448 handleMouseOut(event); | |
449 else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent()
&& toMouseEvent(event)->button() == LeftButton) | |
450 handleLeftMouseDown(event); | |
451 else if (event->type() == EventTypeNames::gestureshowpress) | |
452 handleGestureShowPress(event); | |
453 else if (event->type() == EventTypeNames::gesturetapunconfirmed) | |
454 handleGestureTapUnconfirmed(event); | |
455 else if (isLinkClick(event)) | |
456 handleClick(event); | |
457 } | |
458 | |
459 void HTMLAnchorElement::PrefetchEventHandler::handleMouseOver(Event* event) | |
460 { | |
461 if (m_mouseOverTimestamp == 0.0) { | |
462 m_mouseOverTimestamp = event->timeStamp(); | |
463 | |
464 blink::Platform::current()->histogramEnumeration("MouseEventPrefetch.Mou
seOvers", 0, 2); | |
465 | |
466 prefetch(blink::WebPreconnectMotivationLinkMouseOver); | |
467 } | |
468 } | |
469 | |
470 void HTMLAnchorElement::PrefetchEventHandler::handleMouseOut(Event* event) | |
471 { | |
472 if (m_mouseOverTimestamp > 0.0) { | |
473 double mouseOverDuration = convertDOMTimeStampToSeconds(event->timeStamp
() - m_mouseOverTimestamp); | |
474 blink::Platform::current()->histogramCustomCounts("MouseEventPrefetch.Mo
useOverDuration_NoClick", mouseOverDuration * 1000, 0, 10000, 100); | |
475 | |
476 m_mouseOverTimestamp = 0.0; | |
477 } | |
478 } | |
479 | |
480 void HTMLAnchorElement::PrefetchEventHandler::handleLeftMouseDown(Event* event) | |
481 { | |
482 m_mouseDownTimestamp = event->timeStamp(); | |
483 | |
484 blink::Platform::current()->histogramEnumeration("MouseEventPrefetch.MouseDo
wns", 0, 2); | |
485 | |
486 prefetch(blink::WebPreconnectMotivationLinkMouseDown); | |
487 } | |
488 | |
489 void HTMLAnchorElement::PrefetchEventHandler::handleGestureTapUnconfirmed(Event*
event) | |
490 { | |
491 m_hadTapUnconfirmed = true; | |
492 | |
493 blink::Platform::current()->histogramEnumeration("MouseEventPrefetch.TapUnco
nfirmeds", 0, 2); | |
494 | |
495 prefetch(blink::WebPreconnectMotivationLinkTapUnconfirmed); | |
496 } | |
497 | |
498 void HTMLAnchorElement::PrefetchEventHandler::handleGestureShowPress(Event* even
t) | |
499 { | |
500 m_tapDownTimestamp = event->timeStamp(); | |
501 | |
502 blink::Platform::current()->histogramEnumeration("MouseEventPrefetch.TapDown
s", 0, 2); | |
503 | |
504 prefetch(blink::WebPreconnectMotivationLinkTapDown); | |
505 } | |
506 | |
507 void HTMLAnchorElement::PrefetchEventHandler::handleClick(Event* event) | |
508 { | |
509 bool capturedMouseOver = (m_mouseOverTimestamp > 0.0); | |
510 if (capturedMouseOver) { | |
511 double mouseOverDuration = convertDOMTimeStampToSeconds(event->timeStamp
() - m_mouseOverTimestamp); | |
512 | |
513 blink::Platform::current()->histogramCustomCounts("MouseEventPrefetch.Mo
useOverDuration_Click", mouseOverDuration * 1000, 0, 10000, 100); | |
514 } | |
515 | |
516 bool capturedMouseDown = (m_mouseDownTimestamp > 0.0); | |
517 blink::Platform::current()->histogramEnumeration("MouseEventPrefetch.MouseDo
wnFollowedByClick", capturedMouseDown, 2); | |
518 | |
519 if (capturedMouseDown) { | |
520 double mouseDownDuration = convertDOMTimeStampToSeconds(event->timeStamp
() - m_mouseDownTimestamp); | |
521 | |
522 blink::Platform::current()->histogramCustomCounts("MouseEventPrefetch.Mo
useDownDuration_Click", mouseDownDuration * 1000, 0, 10000, 100); | |
523 } | |
524 | |
525 bool capturedTapDown = (m_tapDownTimestamp > 0.0); | |
526 if (capturedTapDown) { | |
527 double tapDownDuration = convertDOMTimeStampToSeconds(event->timeStamp()
- m_tapDownTimestamp); | |
528 | |
529 blink::Platform::current()->histogramCustomCounts("MouseEventPrefetch.Ta
pDownDuration_Click", tapDownDuration * 1000, 0, 10000, 100); | |
530 } | |
531 | |
532 int flags = (m_hadTapUnconfirmed ? 2 : 0) | (capturedTapDown ? 1 : 0); | |
533 blink::Platform::current()->histogramEnumeration("MouseEventPrefetch.PreTapE
ventsFollowedByClick", flags, 4); | |
534 } | |
535 | |
536 bool HTMLAnchorElement::PrefetchEventHandler::shouldPrefetch(const KURL& url) | |
537 { | |
538 if (m_hadHREFChanged) | |
539 return false; | |
540 | |
541 if (m_anchorElement->hasEventListeners(EventTypeNames::click)) | |
542 return false; | |
543 | |
544 if (!url.protocolIsInHTTPFamily()) | |
545 return false; | |
546 | |
547 Document& document = m_anchorElement->document(); | |
548 | |
549 if (!document.securityOrigin()->canDisplay(url)) | |
550 return false; | |
551 | |
552 if (url.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(document.
url(), url)) | |
553 return false; | |
554 | |
555 LocalFrame* frame = document.frame(); | |
556 if (!frame) | |
557 return false; | |
558 | |
559 // Links which create new window/tab are avoided because they may require us
er approval interaction. | |
560 if (!m_anchorElement->target().isEmpty()) | |
561 return false; | |
562 | |
563 return true; | |
564 } | |
565 | |
566 void HTMLAnchorElement::PrefetchEventHandler::prefetch(blink::WebPreconnectMotiv
ation motivation) | |
567 { | |
568 const KURL& url = m_anchorElement->href(); | |
569 | |
570 if (!shouldPrefetch(url)) | |
571 return; | |
572 | |
573 // The precision of current MouseOver trigger is too low to actually trigger
preconnects. | |
574 if (motivation == blink::WebPreconnectMotivationLinkMouseOver) | |
575 return; | |
576 | |
577 preconnectToURL(url, motivation); | |
578 m_hasIssuedPreconnect = true; | |
579 } | |
580 | |
581 bool HTMLAnchorElement::isInteractiveContent() const | 355 bool HTMLAnchorElement::isInteractiveContent() const |
582 { | 356 { |
583 return isLink(); | 357 return isLink(); |
584 } | 358 } |
585 | 359 |
586 void HTMLAnchorElement::trace(Visitor* visitor) | |
587 { | |
588 visitor->trace(m_prefetchEventHandler); | |
589 HTMLElement::trace(visitor); | |
590 } | 360 } |
591 | |
592 } | |
OLD | NEW |