VisitedLinkState.cpp [plain text]
#include "config.h"
#include "VisitedLinkState.h"
#include "ElementIterator.h"
#include "Frame.h"
#include "HTMLAnchorElement.h"
#include "Page.h"
#include "SVGAElement.h"
#include "SVGNames.h"
#include "VisitedLinkStore.h"
#include "XLinkNames.h"
namespace WebCore {
using namespace HTMLNames;
inline static const AtomString* linkAttribute(const Element& element)
{
if (!element.isLink())
return nullptr;
if (element.isHTMLElement())
return &element.attributeWithoutSynchronization(HTMLNames::hrefAttr);
if (element.isSVGElement())
return &element.getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr);
return nullptr;
}
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.invalidateStyleForSubtree();
}
}
inline static Optional<SharedStringHash> linkHashForElement(const Element& element)
{
if (is<HTMLAnchorElement>(element))
return downcast<HTMLAnchorElement>(element).visitedLinkHash();
if (is<SVGAElement>(element))
return downcast<SVGAElement>(element).visitedLinkHash();
return WTF::nullopt;
}
void VisitedLinkState::invalidateStyleForLink(SharedStringHash linkHash)
{
if (!m_linksCheckedForVisitedState.contains(linkHash))
return;
for (auto& element : descendantsOfType<Element>(m_document)) {
if (element.isLink() && linkHashForElement(element) == linkHash)
element.invalidateStyleForSubtree();
}
}
InsideLink VisitedLinkState::determineLinkStateSlowCase(const Element& element)
{
ASSERT(element.isLink());
const AtomString* attribute = linkAttribute(element);
if (!attribute || attribute->isNull())
return InsideLink::NotInside;
auto hashIfFound = linkHashForElement(element);
if (!hashIfFound)
return attribute->isEmpty() ? InsideLink::InsideVisited : InsideLink::InsideUnvisited;
auto hash = *hashIfFound;
if (!hash)
return InsideLink::InsideVisited;
Frame* frame = element.document().frame();
if (!frame)
return InsideLink::InsideUnvisited;
Page* page = frame->page();
if (!page)
return InsideLink::InsideUnvisited;
m_linksCheckedForVisitedState.add(hash);
if (!page->visitedLinkStore().isLinkVisited(*page, hash, element.document().baseURL(), *attribute))
return InsideLink::InsideUnvisited;
return InsideLink::InsideVisited;
}
}