blob: 77e8fd1ea2eb087b3f827a4ee1046b1b7f52322d [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11 * Copyright (C) 2012 Google Inc. All rights reserved.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB. If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
27 */
28
29#include "config.h"
30#include "core/dom/VisitedLinkState.h"
31
32#include "HTMLNames.h"
33#include "core/dom/NodeTraversal.h"
34#include "core/html/HTMLAnchorElement.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010035#include "core/page/Page.h"
Torne (Richard Coles)5267f702013-06-11 10:57:24 +010036#include "public/platform/Platform.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010037
38namespace WebCore {
39
40using namespace HTMLNames;
41
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010042inline static const AtomicString& linkAttribute(Element* element)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010044 ASSERT(element->isLink());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045 if (element->isHTMLElement())
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010046 return element->fastGetAttribute(HTMLNames::hrefAttr);
47 ASSERT(element->isSVGElement());
48 return element->getAttribute(XLinkNames::hrefAttr);
49}
50
51inline static LinkHash linkHashForElement(Document* document, Element* element)
52{
Ben Murdoche69819b2013-07-17 14:56:49 +010053 if (isHTMLAnchorElement(element))
54 return toHTMLAnchorElement(element)->visitedLinkHash();
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010055 return visitedLinkHash(document->baseURL(), linkAttribute(element));
56}
57
58inline static LinkHash linkHashForElementWithAttribute(Document* document, Element* element, const AtomicString& attribute)
59{
60 ASSERT(linkAttribute(element) == attribute);
Ben Murdoche69819b2013-07-17 14:56:49 +010061 if (isHTMLAnchorElement(element))
62 return toHTMLAnchorElement(element)->visitedLinkHash();
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010063 return visitedLinkHash(document->baseURL(), attribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010064}
65
66PassOwnPtr<VisitedLinkState> VisitedLinkState::create(Document* document)
67{
68 return adoptPtr(new VisitedLinkState(document));
69}
70
71VisitedLinkState::VisitedLinkState(Document* document)
72 : m_document(document)
73{
74}
75
76void VisitedLinkState::invalidateStyleForAllLinks()
77{
78 if (m_linksCheckedForVisitedState.isEmpty())
79 return;
80 for (Element* element = ElementTraversal::firstWithin(m_document); element; element = ElementTraversal::next(element)) {
81 if (element->isLink())
82 element->setNeedsStyleRecalc();
83 }
84}
85
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010086void VisitedLinkState::invalidateStyleForLink(LinkHash linkHash)
87{
88 if (!m_linksCheckedForVisitedState.contains(linkHash))
89 return;
90 for (Element* element = ElementTraversal::firstWithin(m_document); element; element = ElementTraversal::next(element)) {
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010091 if (element->isLink() && linkHashForElement(m_document, element) == linkHash)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010092 element->setNeedsStyleRecalc();
93 }
94}
95
96EInsideLink VisitedLinkState::determineLinkStateSlowCase(Element* element)
97{
98 ASSERT(element->isLink());
99
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100100 const AtomicString& attribute = linkAttribute(element);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100101
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100102 if (attribute.isNull())
103 return NotInsideLink; // This can happen for <img usemap>
104
105 // An empty attribute refers to the document itself which is always
106 // visited. It is useful to check this explicitly so that visited
107 // links can be tested in platform independent manner, without
108 // explicit support in the test harness.
109 if (attribute.isEmpty())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100110 return InsideVisitedLink;
111
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100112 // We null check the Frame here to avoid canonicalizing and hashing
113 // URLs in documents that aren't attached to Frames (like documents
114 // from XMLHttpRequest).
115 if (!m_document->frame())
116 return InsideUnvisitedLink;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100117
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100118 LinkHash hash = linkHashForElementWithAttribute(m_document, element, attribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100119 if (!hash)
120 return InsideUnvisitedLink;
121
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100122 m_linksCheckedForVisitedState.add(hash);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100123 return WebKit::Platform::current()->isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100124}
125
126}