VisitedLinkState.cpp [plain text]
#include "config.h"
#include "VisitedLinkState.h"
#include "ElementIterator.h"
#include "Frame.h"
#include "HTMLAnchorElement.h"
#include "Page.h"
#include "PageGroup.h"
#include "VisitedLinkStore.h"
#include "XLinkNames.h"
namespace WebCore {
using namespace HTMLNames;
inline static const AtomicString* linkAttribute(Element& element)
{
if (!element.isLink())
return 0;
if (element.isHTMLElement())
return &element.fastGetAttribute(HTMLNames::hrefAttr);
if (element.isSVGElement())
return &element.getAttribute(XLinkNames::hrefAttr);
return 0;
}
VisitedLinkState::VisitedLinkState(Document& document)
: m_document(document)
{
}
void VisitedLinkState::invalidateStyleForAllLinks()
{
if (m_linksCheckedForVisitedState.isEmpty())
return;
for (auto& element : descendantsOfType<Element>(m_document)) {
if (element.isLink())
element.setNeedsStyleRecalc();
}
}
inline static LinkHash linkHashForElement(Document& document, Element& element)
{
if (isHTMLAnchorElement(element))
return toHTMLAnchorElement(element).visitedLinkHash();
if (const AtomicString* attribute = linkAttribute(element))
return WebCore::visitedLinkHash(document.baseURL(), *attribute);
return 0;
}
void VisitedLinkState::invalidateStyleForLink(LinkHash linkHash)
{
if (!m_linksCheckedForVisitedState.contains(linkHash))
return;
for (auto& element : descendantsOfType<Element>(m_document)) {
if (linkHashForElement(m_document, element) == linkHash)
element.setNeedsStyleRecalc();
}
}
EInsideLink VisitedLinkState::determineLinkStateSlowCase(Element& element)
{
ASSERT(element.isLink());
const AtomicString* attribute = linkAttribute(element);
if (!attribute || attribute->isNull())
return NotInsideLink;
if (attribute->isEmpty())
return InsideVisitedLink;
LinkHash hash;
if (isHTMLAnchorElement(element))
hash = toHTMLAnchorElement(element).visitedLinkHash();
else
hash = WebCore::visitedLinkHash(element.document().baseURL(), *attribute);
if (!hash)
return InsideUnvisitedLink;
Frame* frame = element.document().frame();
if (!frame)
return InsideUnvisitedLink;
Page* page = frame->page();
if (!page)
return InsideUnvisitedLink;
m_linksCheckedForVisitedState.add(hash);
if (!page->visitedLinkStore().isLinkVisited(*page, hash, element.document().baseURL(), *attribute))
return InsideUnvisitedLink;
return InsideVisitedLink;
}
}