| 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 |