1/* 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 "VisitedLinkState.h" 31 32#include "Frame.h" 33#include "HTMLAnchorElement.h" 34#include "HTMLNames.h" 35#include "NodeTraversal.h" 36#include "Page.h" 37#include "PageGroup.h" 38#include "PlatformStrategies.h" 39#include "VisitedLinkStrategy.h" 40 41namespace WebCore { 42 43using namespace HTMLNames; 44 45inline static const AtomicString* linkAttribute(Element* element) 46{ 47 if (!element->isLink()) 48 return 0; 49 if (element->isHTMLElement()) 50 return &element->fastGetAttribute(HTMLNames::hrefAttr); 51 if (element->isSVGElement()) 52 return &element->getAttribute(XLinkNames::hrefAttr); 53 return 0; 54} 55 56PassOwnPtr<VisitedLinkState> VisitedLinkState::create(Document* document) 57{ 58 return adoptPtr(new VisitedLinkState(document)); 59} 60 61VisitedLinkState::VisitedLinkState(Document* document) 62 : m_document(document) 63{ 64} 65 66void VisitedLinkState::invalidateStyleForAllLinks() 67{ 68 if (m_linksCheckedForVisitedState.isEmpty()) 69 return; 70 for (Element* element = ElementTraversal::firstWithin(m_document); element; element = ElementTraversal::next(element)) { 71 if (element->isLink()) 72 element->setNeedsStyleRecalc(); 73 } 74} 75 76inline static LinkHash linkHashForElement(Document* document, Element* element) 77{ 78 if (element->hasTagName(aTag)) 79 return static_cast<HTMLAnchorElement*>(element)->visitedLinkHash(); 80 if (const AtomicString* attribute = linkAttribute(element)) 81 return WebCore::visitedLinkHash(document->baseURL(), *attribute); 82 return 0; 83} 84 85void VisitedLinkState::invalidateStyleForLink(LinkHash linkHash) 86{ 87 if (!m_linksCheckedForVisitedState.contains(linkHash)) 88 return; 89 for (Element* element = ElementTraversal::firstWithin(m_document); element; element = ElementTraversal::next(element)) { 90 if (linkHashForElement(m_document, element) == linkHash) 91 element->setNeedsStyleRecalc(); 92 } 93} 94 95EInsideLink VisitedLinkState::determineLinkStateSlowCase(Element* element) 96{ 97 ASSERT(element->isLink()); 98 99 const AtomicString* attribute = linkAttribute(element); 100 if (!attribute || attribute->isNull()) 101 return NotInsideLink; 102 103 // An empty href refers to the document itself which is always visited. It is useful to check this explicitly so 104 // that visited links can be tested in platform independent manner, without explicit support in the test harness. 105 if (attribute->isEmpty()) 106 return InsideVisitedLink; 107 108 LinkHash hash; 109 if (element->hasTagName(aTag)) 110 hash = static_cast<HTMLAnchorElement*>(element)->visitedLinkHash(); 111 else 112 hash = WebCore::visitedLinkHash(element->document()->baseURL(), *attribute); 113 114 if (!hash) 115 return InsideUnvisitedLink; 116 117 Frame* frame = element->document()->frame(); 118 if (!frame) 119 return InsideUnvisitedLink; 120 121 Page* page = frame->page(); 122 if (!page) 123 return InsideUnvisitedLink; 124 125 m_linksCheckedForVisitedState.add(hash); 126 127 return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash, element->document()->baseURL(), *attribute) ? InsideVisitedLink : InsideUnvisitedLink; 128} 129 130 131} 132