t.node.acceptPreOrder(new Visitor() {
public boolean visit(AncestorChain<?> ancestors) {
ParseTreeNode node = ancestors.node;
if (node instanceof CssTree.Pseudo) {
boolean remove = false;
CssTree child = ((CssTree.Pseudo) node).children().get(0);
if (child instanceof CssTree.IdentLiteral) {
Name pseudoName = Name.css(
((CssTree.IdentLiteral) child).getValue());
if (!ALLOWED_PSEUDO_CLASSES.contains(pseudoName)) {
// Allow the visited pseudo selector but not with any styles
// that can be fetched via getComputedStyle in DOMita's
// COMPUTED_STYLE_WHITELIST.
if (!(LINK_PSEUDO_CLASSES.contains(pseudoName)
&& strippedPropertiesBannedInLinkClasses(
ancestors.parent.parent.cast(CssTree.Selector.class)
))) {
mq.addMessage(PluginMessageType.UNSAFE_CSS_PSEUDO_SELECTOR,
invalidNodeMessageLevel, node.getFilePosition(),
node);
remove = true;
}
}
} else {
StringBuilder rendered = new StringBuilder();
TokenConsumer tc = new CssPrettyPrinter(rendered);
node.render(new RenderContext(tc));
tc.noMoreTokens();
mq.addMessage(PluginMessageType.UNSAFE_CSS_PSEUDO_SELECTOR,
invalidNodeMessageLevel, node.getFilePosition(),
MessagePart.Factory.valueOf(rendered.toString()));
remove = true;
}
if (remove) {
// Delete the containing selector, since otherwise we'd broaden
// the rule.
selectorFor(ancestors).getAttributes().set(
CssValidator.INVALID, Boolean.TRUE);
}
}
return true;
}
}, t.parent);
// 3) Remove any properties and attributes that didn't validate
t.node.acceptPreOrder(new Visitor() {
public boolean visit(AncestorChain<?> ancestors) {
ParseTreeNode node = ancestors.node;
if (node instanceof CssTree.Property) {
if (node.getAttributes().is(CssValidator.INVALID)) {
declarationFor(ancestors).getAttributes().set(
CssValidator.INVALID, Boolean.TRUE);
}
} else if (node instanceof CssTree.Attrib) {
if (node.getAttributes().is(CssValidator.INVALID)) {
simpleSelectorFor(ancestors).getAttributes().set(
CssValidator.INVALID, Boolean.TRUE);
}
} else if (node instanceof CssTree.Term
&& (CssPropertyPartType.URI == propertyPartType(node))) {
boolean remove = false;
Message removeMsg = null;
CssTree term = (CssTree.Term) node;
CssTree.CssLiteral content =
(CssTree.CssLiteral) term.children().get(0);
if (content instanceof CssTree.Substitution) {
return true; // Handled by later pass.
}