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); } }