EInsideLink VisitedLinkState::determineLinkStateSlowCase(const Element& element)
{
    DCHECK(element.isLink());
    DCHECK(document().isActive());
    DCHECK(document() == element.document());

    const AtomicString& attribute = linkAttribute(element);

    if (attribute.isNull())
        return NotInsideLink; // This can happen for <img usemap>

    // An empty attribute refers to the document itself which is always
    // visited. It is useful to check this explicitly so that visited
    // links can be tested in platform independent manner, without
    // explicit support in the test harness.
    if (attribute.isEmpty())
        return InsideVisitedLink;

    if (LinkHash hash = linkHashForElement(element, attribute)) {
        m_linksCheckedForVisitedState.add(hash);
        if (Platform::current()->isLinkVisited(hash))
            return InsideVisitedLink;
    }

    return InsideUnvisitedLink;
}
void VisitedLinkState::invalidateStyleForLink(LinkHash linkHash)
{
    if (!m_linksCheckedForVisitedState.contains(linkHash))
        return;
    for (Node* node = document().firstChild(); node; node = NodeTraversal::next(*node)) {
        if (node->isLink() && linkHashForElement(toElement(*node)) == linkHash)
            node->setNeedsStyleRecalc(SubtreeStyleChange);
    }
}
static void invalidateStyleForLinkRecursively(Node& rootNode, LinkHash linkHash)
{
    for (Node& node : NodeTraversal::startsAt(rootNode)) {
        if (node.isLink() && linkHashForElement(toElement(node)) == linkHash) {
            toElement(node).pseudoStateChanged(CSSSelector::PseudoLink);
            toElement(node).pseudoStateChanged(CSSSelector::PseudoVisited);
            toElement(node).pseudoStateChanged(CSSSelector::PseudoAnyLink);
        }
        if (isShadowHost(&node))
            for (ShadowRoot* root = node.youngestShadowRoot(); root; root = root->olderShadowRoot())
                invalidateStyleForLinkRecursively(*root, linkHash);
    }
}