diff --git a/bundles/org.eclipse.e4.ui.css.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.css.core/META-INF/MANIFEST.MF index 76e17ec59af..27dfb2acb81 100644 --- a/bundles/org.eclipse.e4.ui.css.core/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.ui.css.core/META-INF/MANIFEST.MF @@ -31,6 +31,7 @@ Export-Package: org.eclipse.e4.ui.css.core;x-internal:=true, org.eclipse.e4.ui.css.core.impl.dom.parsers;x-internal:=true, org.eclipse.e4.ui.css.core.impl.dom.properties;x-friends:="org.eclipse.e4.ui.css.swt", org.eclipse.e4.ui.css.core.impl.engine;x-friends:="org.eclipse.e4.ui.css.swt,org.eclipse.e4.ui.workbench.swt", + org.eclipse.e4.ui.css.core.impl.engine.selector;x-friends:="org.eclipse.e4.ui.tests.css.core", org.eclipse.e4.ui.css.core.impl.sac;x-internal:=true, org.eclipse.e4.ui.css.core.resources;x-friends:="org.eclipse.e4.ui.css.swt,org.eclipse.e4.ui.workbench.renderers.swt", org.eclipse.e4.ui.css.core.sac;x-internal:=true, diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedCSSRule.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedCSSRule.java index ae6bd4c11f5..1d50bb853ed 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedCSSRule.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedCSSRule.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2013 Angelo Zerr and others. + * Copyright (c) 2008, 2026 Angelo Zerr and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,8 +13,7 @@ *******************************************************************************/ package org.eclipse.e4.ui.css.core.dom; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; import org.w3c.dom.css.CSSRule; /** @@ -28,7 +27,7 @@ public interface ExtendedCSSRule extends CSSRule { public CSSPropertyList getCSSPropertyList(); /** - * Return the list of {@link Selector} of this {@link CSSRule}. + * Return the list of selectors of this {@link CSSRule}. */ - public SelectorList getSelectorList(); + public Selectors.SelectorList getSelectorList(); } diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedDocumentCSS.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedDocumentCSS.java index f23d30d74cf..d3d7bc717d1 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedDocumentCSS.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/dom/ExtendedDocumentCSS.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2018 Angelo Zerr and others. + * Copyright (c) 2008, 2026 Angelo Zerr and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -15,9 +15,6 @@ package org.eclipse.e4.ui.css.core.dom; import java.util.EventListener; -import java.util.List; -import org.w3c.css.sac.Condition; -import org.w3c.css.sac.Selector; import org.w3c.dom.css.DocumentCSS; import org.w3c.dom.stylesheets.StyleSheet; @@ -26,21 +23,10 @@ */ public interface ExtendedDocumentCSS extends DocumentCSS { - public static final Integer SAC_ID_CONDITION = Integer.valueOf(Condition.SAC_ID_CONDITION); - public static final Integer SAC_CLASS_CONDITION = Integer.valueOf(Condition.SAC_CLASS_CONDITION); - public static final Integer SAC_PSEUDO_CLASS_CONDITION = Integer.valueOf(Condition.SAC_PSEUDO_CLASS_CONDITION); - public static final Integer OTHER_SAC_CONDITIONAL_SELECTOR = Integer.valueOf(Selector.SAC_CONDITIONAL_SELECTOR); - - public static final Integer OTHER_SAC_SELECTOR = Integer.valueOf(999); - public void addStyleSheet(StyleSheet styleSheet); public void removeAllStyleSheets(); - public List queryConditionSelector(int conditionType); - - public List querySelector(int selectorType, int conditionType); - /** * @since 0.12.200 */ diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/engine/CSSEngine.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/engine/CSSEngine.java index a6624b84852..f036cf16154 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/engine/CSSEngine.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/engine/CSSEngine.java @@ -20,11 +20,10 @@ import org.eclipse.e4.ui.css.core.dom.IElementProvider; import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler; import org.eclipse.e4.ui.css.core.dom.properties.converters.ICSSValueConverter; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; import org.eclipse.e4.ui.css.core.resources.IResourcesRegistry; import org.eclipse.e4.ui.css.core.util.resources.IResourcesLocatorManager; import org.w3c.css.sac.InputSource; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; import org.w3c.dom.Element; import org.w3c.dom.css.CSSStyleDeclaration; import org.w3c.dom.css.CSSStyleSheet; @@ -105,27 +104,27 @@ public interface CSSEngine { /** * Parse Selectors from String value. */ - SelectorList parseSelectors(String text); + Selectors.SelectorList parseSelectors(String text); /** * Parse Selectors from InputSource value. */ - SelectorList parseSelectors(InputSource source) throws IOException; + Selectors.SelectorList parseSelectors(InputSource source) throws IOException; /** * Parse Selectors from InputStream. */ - SelectorList parseSelectors(InputStream stream) throws IOException; + Selectors.SelectorList parseSelectors(InputStream stream) throws IOException; /** * Parse Selectors from String value. */ - SelectorList parseSelectors(Reader reader) throws IOException; + Selectors.SelectorList parseSelectors(Reader reader) throws IOException; /** * Check if the selector matches the object node. */ - boolean matches(Selector selector, Object node, String pseudo); + boolean matches(Selectors.Selector selector, Object node, String pseudo); /*--------------- Apply styles -----------------*/ diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/CSSStyleRuleImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/CSSStyleRuleImpl.java index 01e5822bd4a..23200bae6c2 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/CSSStyleRuleImpl.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/CSSStyleRuleImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 Angelo Zerr and others. + * Copyright (c) 2008, 2026 Angelo Zerr and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -17,8 +17,7 @@ import org.eclipse.e4.ui.css.core.dom.CSSPropertyList; import org.eclipse.e4.ui.css.core.dom.ExtendedCSSRule; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; import org.w3c.dom.DOMException; import org.w3c.dom.css.CSSRule; import org.w3c.dom.css.CSSStyleDeclaration; @@ -27,10 +26,10 @@ public class CSSStyleRuleImpl extends CSSRuleImpl implements CSSStyleRule, ExtendedCSSRule { - private final SelectorList selectors; + private final Selectors.SelectorList selectors; private CSSStyleDeclaration styleDeclaration; - public CSSStyleRuleImpl(CSSStyleSheet parentStyleSheet, CSSRule parentRule, SelectorList selectors) { + public CSSStyleRuleImpl(CSSStyleSheet parentStyleSheet, CSSRule parentRule, Selectors.SelectorList selectors) { super(parentStyleSheet, parentRule); this.selectors = selectors; } @@ -55,17 +54,7 @@ public String getCssText() { @Override public String getSelectorText() { - StringBuilder sb = new StringBuilder(); - for (int selID = 0; selID < getSelectorList().getLength(); selID++) { - Selector item = getSelectorList().item(selID); - sb.append(item.toString()); - sb.append(", "); - } - if (getSelectorList().getLength() > 0) { - sb.delete(sb.length() - 2, sb.length()); - } - - return sb.toString(); + return selectors.text(); } @Override @@ -83,7 +72,7 @@ public void setSelectorText(String selectorText) throws DOMException { // Additional methods @Override - public SelectorList getSelectorList() { + public Selectors.SelectorList getSelectorList() { return selectors; } diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/DocumentCSSImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/DocumentCSSImpl.java index f9fba83d961..b87b42b143c 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/DocumentCSSImpl.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/DocumentCSSImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2018 Angelo Zerr and others. + * Copyright (c) 2008, 2026 Angelo Zerr and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -18,19 +18,10 @@ package org.eclipse.e4.ui.css.core.impl.dom; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import org.eclipse.e4.ui.css.core.dom.ExtendedCSSRule; import org.eclipse.e4.ui.css.core.dom.ExtendedDocumentCSS; -import org.w3c.css.sac.ConditionalSelector; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; import org.w3c.dom.Element; -import org.w3c.dom.css.CSSRule; -import org.w3c.dom.css.CSSRuleList; import org.w3c.dom.css.CSSStyleDeclaration; -import org.w3c.dom.css.CSSStyleSheet; import org.w3c.dom.css.DocumentCSS; import org.w3c.dom.stylesheets.StyleSheet; import org.w3c.dom.stylesheets.StyleSheetList; @@ -42,11 +33,6 @@ public class DocumentCSSImpl implements ExtendedDocumentCSS { private final StyleSheetListImpl styleSheetList = new StyleSheetListImpl(); - /** - * key=selector type, value = CSSStyleDeclaration - */ - private Map> styleDeclarationMap; - private final List styleSheetChangeListeners = new ArrayList<>(1); @Override @@ -72,93 +58,6 @@ public void removeAllStyleSheets() { styleSheetChangeListeners.forEach(l -> l.styleSheetRemoved(styleSheet)); } styleSheetList.removeAllStyleSheets(); - this.styleDeclarationMap = null; - } - - @Override - public List queryConditionSelector(int conditionType) { - return querySelector(Selector.SAC_CONDITIONAL_SELECTOR, conditionType); - } - - @Override - public List querySelector(int selectorType, int conditionType) { - List list = getCSSStyleDeclarationList(selectorType, conditionType); - if (list != null) { - return list; - } - int l = styleSheetList.getLength(); - for (int i = 0; i < l; i++) { - CSSStyleSheet styleSheet = (CSSStyleSheet) styleSheetList.item(i); - CSSRuleList ruleList = styleSheet.getCssRules(); - list = querySelector(ruleList, selectorType, conditionType); - setCSSStyleDeclarationList(list, selectorType, conditionType); - } - return list; - } - - protected List querySelector(CSSRuleList ruleList, int selectorType, int selectorConditionType) { - List list = new ArrayList<>(); - if (selectorType == Selector.SAC_CONDITIONAL_SELECTOR) { - int length = ruleList.getLength(); - for (int i = 0; i < length; i++) { - CSSRule rule = ruleList.item(i); - if (rule.getType() == CSSRule.STYLE_RULE && rule instanceof ExtendedCSSRule r) { - SelectorList selectorList = r.getSelectorList(); - // Loop for SelectorList - int l = selectorList.getLength(); - for (int j = 0; j < l; j++) { - Selector selector = selectorList.item(j); - if (selector.getSelectorType() == selectorType) { - // It's conditional selector - ConditionalSelector conditionalSelector = (ConditionalSelector) selector; - short conditionType = conditionalSelector.getCondition().getConditionType(); - if (selectorConditionType == conditionType) { - // current selector match the current CSS - // Rule - // CSSStyleRule styleRule = (CSSStyleRule) - // rule; - list.add(selector); - } - } - } - } - } - } - return list; - } - - protected List getCSSStyleDeclarationList(int selectorType, int conditionType) { - Integer key = getKey(selectorType, conditionType); - return getStyleDeclarationMap().get(key); - } - - protected void setCSSStyleDeclarationList(List list, int selectorType, int conditionType) { - Integer key = getKey(selectorType, conditionType); - getStyleDeclarationMap().put(key, list); - } - - protected Integer getKey(int selectorType, int conditionType) { - if (selectorType == Selector.SAC_CONDITIONAL_SELECTOR) { - if (conditionType == SAC_CLASS_CONDITION.intValue()) { - return SAC_CLASS_CONDITION; - } - if (conditionType == SAC_ID_CONDITION.intValue()) { - return SAC_ID_CONDITION; - } - if (conditionType == SAC_PSEUDO_CLASS_CONDITION.intValue()) { - return SAC_PSEUDO_CLASS_CONDITION; - } - return OTHER_SAC_CONDITIONAL_SELECTOR; - } - - return OTHER_SAC_SELECTOR; - } - - protected Map> getStyleDeclarationMap() { - if (styleDeclarationMap == null) { - styleDeclarationMap = new HashMap<>(); - } - return styleDeclarationMap; } @Override diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/ViewCSSImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/ViewCSSImpl.java index c628ce9cf41..aa1a5c8a92c 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/ViewCSSImpl.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/dom/ViewCSSImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2018 Angelo Zerr and others. + * Copyright (c) 2008, 2026 Angelo Zerr and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -21,11 +21,9 @@ import java.util.List; import org.eclipse.e4.ui.css.core.dom.ExtendedCSSRule; import org.eclipse.e4.ui.css.core.dom.ExtendedDocumentCSS; -import org.eclipse.e4.ui.css.core.impl.sac.ExtendedSelector; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; +import org.eclipse.e4.ui.css.core.impl.engine.selector.SelectorMatcher; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.w3c.dom.css.CSSRule; import org.w3c.dom.css.CSSRuleList; import org.w3c.dom.css.CSSStyleDeclaration; @@ -112,47 +110,42 @@ private List getCombinedRules() { } private CSSStyleDeclaration getComputedStyle(List ruleList, Element elt, String pseudoElt) { - Node parent = elt.getParentNode(); - - Node[] hierarchy = null; - if (parent != null) { - List hierarchyList = new ArrayList<>(); - for (Node n = parent; n != null; n = n.getParentNode()) { - hierarchyList.add(n); - } - hierarchy = hierarchyList.toArray(new Node[hierarchyList.size()]); - } - List styleDeclarations = null; StyleWrapper firstStyleDeclaration = null; int position = 0; + + int depth = 0; + for (org.w3c.dom.Node n = elt; n instanceof Element; n = n.getParentNode()) { + depth++; + } + Element[] hierarchy = new Element[depth]; + int idx = 0; + for (org.w3c.dom.Node n = elt; n instanceof Element; n = n.getParentNode()) { + hierarchy[idx++] = (Element) n; + } + for (CSSRule rule : ruleList) { if (rule.getType() != CSSRule.STYLE_RULE || (!(rule instanceof ExtendedCSSRule)) ) { continue; // we only handle the CSSRule.STYLE_RULE and ExtendedCSSRule case } CSSStyleRule styleRule = (CSSStyleRule) rule; ExtendedCSSRule r = (ExtendedCSSRule) rule; - SelectorList selectorList = r.getSelectorList(); - // Loop for SelectorList - int l = selectorList.getLength(); - for (int j = 0; j < l; j++) { - Selector selector = selectorList.item(j); - if (selector instanceof ExtendedSelector extendedSelector) { - if (extendedSelector.match(elt, hierarchy, 0, pseudoElt)) { - CSSStyleDeclaration style = styleRule.getStyle(); - int specificity = extendedSelector.getSpecificity(); - StyleWrapper wrapper = new StyleWrapper(style, specificity, position++); - if (firstStyleDeclaration == null) { - firstStyleDeclaration = wrapper; - } else { - // There is several Style Declarations which - // match the current element - if (styleDeclarations == null) { - styleDeclarations = new ArrayList<>(); - styleDeclarations.add(firstStyleDeclaration); - } - styleDeclarations.add(wrapper); + Selectors.SelectorList selectorList = r.getSelectorList(); + for (Selectors.Selector selector : selectorList.alternatives()) { + if (SelectorMatcher.matches(selector, elt, pseudoElt, hierarchy, 0)) { + CSSStyleDeclaration style = styleRule.getStyle(); + int specificity = selector.specificity(); + StyleWrapper wrapper = new StyleWrapper(style, specificity, position++); + if (firstStyleDeclaration == null) { + firstStyleDeclaration = wrapper; + } else { + // There is several Style Declarations which + // match the current element + if (styleDeclarations == null) { + styleDeclarations = new ArrayList<>(); + styleDeclarations.add(firstStyleDeclaration); } + styleDeclarations.add(wrapper); } } } diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/CSSEngineImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/CSSEngineImpl.java index 2fb2d1829de..66e7ede4f84 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/CSSEngineImpl.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/CSSEngineImpl.java @@ -62,23 +62,17 @@ import org.eclipse.e4.ui.css.core.impl.dom.CSSStyleSheetImpl; import org.eclipse.e4.ui.css.core.impl.dom.DocumentCSSImpl; import org.eclipse.e4.ui.css.core.impl.dom.ViewCSSImpl; -import org.eclipse.e4.ui.css.core.impl.sac.CSSConditionFactoryImpl; -import org.eclipse.e4.ui.css.core.impl.sac.CSSSelectorFactoryImpl; -import org.eclipse.e4.ui.css.core.impl.sac.ExtendedSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.SacTranslator; +import org.eclipse.e4.ui.css.core.impl.engine.selector.SelectorMatcher; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; import org.eclipse.e4.ui.css.core.resources.IResourcesRegistry; import org.eclipse.e4.ui.css.core.resources.ResourceRegistryKeyFactory; import org.eclipse.e4.ui.css.core.util.impl.resources.ResourcesLocatorManager; import org.eclipse.e4.ui.css.core.util.resources.IResourcesLocatorManager; import org.eclipse.e4.ui.css.core.utils.StringUtils; -import org.w3c.css.sac.AttributeCondition; -import org.w3c.css.sac.CombinatorCondition; -import org.w3c.css.sac.Condition; -import org.w3c.css.sac.ConditionFactory; -import org.w3c.css.sac.ConditionalSelector; -import org.w3c.css.sac.DescendantSelector; +import org.apache.batik.css.parser.DefaultConditionFactory; +import org.apache.batik.css.parser.DefaultSelectorFactory; import org.w3c.css.sac.InputSource; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -105,9 +99,6 @@ */ public abstract class CSSEngineImpl implements CSSEngine { - public static final ConditionFactory CONDITIONFACTORY_INSTANCE = new CSSConditionFactoryImpl( - null, "class", null, "id"); - /** * Archives are deliberately identified by exclamation mark in URLs */ @@ -324,7 +315,7 @@ public CSSStyleDeclaration parseStyleDeclaration(InputSource source) throws IOEx /*--------------- Parse CSS Selector -----------------*/ @Override - public SelectorList parseSelectors(String selector) { + public Selectors.SelectorList parseSelectors(String selector) { try { return parseSelectors(new StringReader(selector)); } catch (IOException e) { @@ -333,24 +324,24 @@ public SelectorList parseSelectors(String selector) { } @Override - public SelectorList parseSelectors(Reader reader) throws IOException { + public Selectors.SelectorList parseSelectors(Reader reader) throws IOException { InputSource source = new InputSource(); source.setCharacterStream(reader); return parseSelectors(source); } @Override - public SelectorList parseSelectors(InputStream stream) throws IOException { + public Selectors.SelectorList parseSelectors(InputStream stream) throws IOException { InputSource source = new InputSource(); source.setByteStream(stream); return parseSelectors(source); } @Override - public SelectorList parseSelectors(InputSource source) throws IOException { + public Selectors.SelectorList parseSelectors(InputSource source) throws IOException { checkInputSource(source); CSSParser parser = makeCSSParser(); - return parser.parseSelectors(source); + return SacTranslator.translate(parser.parseSelectors(source)); } /*--------------- Parse CSS Property Value-----------------*/ @@ -387,6 +378,28 @@ public CSSValue parsePropertyValue(InputSource source) throws IOException { /*--------------- Apply styles -----------------*/ + private final ThreadLocal> styledElements = new ThreadLocal<>(); + + public void startStylingSession() { + styledElements.set(new HashSet<>()); + } + + public void stopStylingSession() { + styledElements.remove(); + } + + public boolean isElementStyled(Object element) { + Set set = styledElements.get(); + return set != null && set.contains(element); + } + + public void markElementStyled(Object element) { + Set set = styledElements.get(); + if (set != null) { + set.add(element); + } + } + @Override public void applyStyles(Object element, boolean applyStylesToChildNodes) { applyStyles(element, applyStylesToChildNodes, computeDefaultStyle); @@ -399,6 +412,21 @@ public void applyStyles(Object element, boolean applyStylesToChildNodes, boolean return; } + if (isElementStyled(element)) { + if (applyStylesToChildNodes) { + NodeList nodes = elt instanceof ChildVisibilityAwareElement c + ? c.getVisibleChildNodes() + : elt.getChildNodes(); + if (nodes != null) { + processNodeList(nodes, this::applyStyles, applyStylesToChildNodes); + onStylesAppliedToChildNodes(elt, nodes); + } + } + return; + } + + markElementStyled(element); + /* * Compute new Style to apply. */ @@ -491,46 +519,57 @@ protected boolean isVisible(Element elt) { return true; } - private void applyConditionalPseudoStyle(ExtendedCSSRule parentRule, String pseudoInstance, Object element, CSSStyleDeclaration styleWithPseudoInstance) { - SelectorList selectorList = parentRule.getSelectorList(); - for (int j = 0; j < selectorList.getLength(); j++) { - Selector item = selectorList.item(j); - // search for conditional selectors - ConditionalSelector conditional = null; - if (item instanceof ConditionalSelector) { - conditional = (ConditionalSelector) item; - } else if (item instanceof DescendantSelector) { - if (((DescendantSelector) item).getSimpleSelector() instanceof ConditionalSelector) { - conditional = (ConditionalSelector) ((DescendantSelector) item).getSimpleSelector(); - } else if (((DescendantSelector) item).getAncestorSelector() instanceof ConditionalSelector) { - conditional = (ConditionalSelector) ((DescendantSelector) item).getAncestorSelector(); - } - } - if (conditional != null) { - Condition condition = conditional.getCondition(); - // we're only interested in attribute selector conditions - AttributeCondition attr = null; - if (condition instanceof AttributeCondition) { - attr = (AttributeCondition) condition; - } else if (condition instanceof CombinatorCondition) { - if (((CombinatorCondition) condition).getSecondCondition() instanceof AttributeCondition) { - attr = (AttributeCondition) ((CombinatorCondition) condition).getSecondCondition(); - } else if (((CombinatorCondition) condition).getFirstCondition() instanceof AttributeCondition) { - attr = (AttributeCondition) ((CombinatorCondition) condition).getFirstCondition(); - } - } - if (attr != null) { - String value = attr.getValue(); - if (value.equals(pseudoInstance)) { - // if we match the pseudo, apply the style - applyStyleDeclaration(element, styleWithPseudoInstance, pseudoInstance); - return; - } - } + private void applyConditionalPseudoStyle(ExtendedCSSRule parentRule, String pseudoInstance, Object element, + CSSStyleDeclaration styleWithPseudoInstance) { + Selectors.SelectorList selectorList = parentRule.getSelectorList(); + for (Selectors.Selector alternative : selectorList.alternatives()) { + if (matchesPseudoInstanceAttribute(alternative, pseudoInstance)) { + applyStyleDeclaration(element, styleWithPseudoInstance, pseudoInstance); + return; } } } + /** + * Returns {@code true} if {@code selector} carries a pseudo-class or + * attribute selector (anywhere in a compound or descendant combinator) + * whose target value equals {@code pseudoInstance}. Mirrors the legacy + * SAC walker, which handled both {@code :selected} (a pseudo-class) and + * {@code Shell[active='true']} (an attribute) through SAC's shared + * {@code AttributeCondition} interface. + */ + private static boolean matchesPseudoInstanceAttribute(Selectors.Selector selector, String pseudoInstance) { + if (selector instanceof Selectors.PseudoClass pc) { + return pseudoInstance.equals(pc.name()); + } + if (selector instanceof Selectors.AttributeSelector attr) { + return pseudoInstance.equals(attr.value()); + } + if (selector instanceof Selectors.AttributeIncludes attr) { + return pseudoInstance.equals(attr.value()); + } + if (selector instanceof Selectors.AttributeBeginHyphen attr) { + return pseudoInstance.equals(attr.value()); + } + if (selector instanceof Selectors.And and) { + return matchesPseudoInstanceAttribute(and.left(), pseudoInstance) + || matchesPseudoInstanceAttribute(and.right(), pseudoInstance); + } + if (selector instanceof Selectors.Descendant d) { + return matchesPseudoInstanceAttribute(d.descendant(), pseudoInstance) + || matchesPseudoInstanceAttribute(d.ancestor(), pseudoInstance); + } + if (selector instanceof Selectors.Child c) { + return matchesPseudoInstanceAttribute(c.child(), pseudoInstance) + || matchesPseudoInstanceAttribute(c.parent(), pseudoInstance); + } + if (selector instanceof Selectors.Adjacent a) { + return matchesPseudoInstanceAttribute(a.second(), pseudoInstance) + || matchesPseudoInstanceAttribute(a.first(), pseudoInstance); + } + return false; + } + protected String[] getStaticPseudoInstances(Element element) { if (element instanceof CSSStylableElement stylableElement) { return stylableElement.getStaticPseudoInstances(); @@ -933,18 +972,21 @@ protected Map getElementsContext() { } @Override - public boolean matches(Selector selector, Object element, String pseudoElt) { + public boolean matches(Selectors.Selector selector, Object element, String pseudoElt) { Element elt = getElement(element); if (elt == null) { return false; } - if (selector instanceof ExtendedSelector extendedSelector) { - return extendedSelector.match(elt, pseudoElt); - } else { - // TODO : selector is not batik ExtendedSelector, - // Manage this case... + int depth = 0; + for (Node n = elt; n instanceof Element; n = n.getParentNode()) { + depth++; } - return false; + Element[] hierarchy = new Element[depth]; + int idx = 0; + for (Node n = elt; n instanceof Element; n = n.getParentNode()) { + hierarchy[idx++] = (Element) n; + } + return SelectorMatcher.matches(selector, elt, pseudoElt, hierarchy, 0); } /*--------------- Error Handler -----------------*/ @@ -1118,14 +1160,16 @@ public String convert(Object value, Object toType, Object context) } /** - * Return instance of CSS Parser, configured with the Batik selector - * factory and the platform's class/id condition factory. + * Return instance of CSS Parser, configured with Batik's stock selector + * and condition factories. Selectors flow through {@link SacTranslator} + * before they reach engine code, so we no longer need our vendored copies + * of the SAC factory classes. */ public CSSParser makeCSSParser() { ICSSParserFactory factory = CSSParserFactory.newInstance(); CSSParser parser = factory.makeCSSParser(); - parser.setSelectorFactory(CSSSelectorFactoryImpl.INSTANCE); - parser.setConditionFactory(CONDITIONFACTORY_INSTANCE); + parser.setSelectorFactory(DefaultSelectorFactory.INSTANCE); + parser.setConditionFactory(DefaultConditionFactory.INSTANCE); return parser; } diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SacTranslator.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SacTranslator.java new file mode 100644 index 00000000000..5ee9a3d5dbf --- /dev/null +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SacTranslator.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2026 Lars Vogel and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lars Vogel - initial API and implementation + *******************************************************************************/ +package org.eclipse.e4.ui.css.core.impl.engine.selector; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Adjacent; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.And; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeBeginHyphen; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeIncludes; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Child; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.ClassSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Descendant; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.ElementType; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.IdSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.PseudoClass; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Selector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Universal; +import org.w3c.css.sac.AttributeCondition; +import org.w3c.css.sac.CombinatorCondition; +import org.w3c.css.sac.Condition; +import org.w3c.css.sac.ConditionalSelector; +import org.w3c.css.sac.DescendantSelector; +import org.w3c.css.sac.ElementSelector; +import org.w3c.css.sac.SelectorList; +import org.w3c.css.sac.SiblingSelector; +import org.w3c.css.sac.SimpleSelector; + +/** + * Converts a SAC selector tree (as produced by the Batik parser) into the + * engine's internal {@link Selectors} AST. + * + *

+ * The translator is the single boundary between the SAC parser output and the + * rest of the engine. Once a stylesheet has been parsed, only the internal + * AST flows through {@code CSSEngine.matches}, the rule list, and + * {@link SelectorMatcher}. SAC types do not cross this boundary. + *

+ * + *

+ * Specificity is preserved exactly: the internal records compute it the same + * way the legacy SAC wrappers did (100 per id, 10 per class / attribute / + * pseudo-class, 1 per element, 0 for {@code *}). Combinators sum operands. + *

+ */ +public final class SacTranslator { + + private SacTranslator() { + // statics only + } + + /** Translate an entire {@link SelectorList} into the internal form. */ + public static Selectors.SelectorList translate(SelectorList sacList) { + List alternatives = new ArrayList<>(sacList.getLength()); + for (int i = 0; i < sacList.getLength(); i++) { + alternatives.add(translate(sacList.item(i))); + } + return new Selectors.SelectorList(alternatives); + } + + /** Translate a single SAC {@link org.w3c.css.sac.Selector}. */ + public static Selector translate(org.w3c.css.sac.Selector sac) { + return switch (sac.getSelectorType()) { + case org.w3c.css.sac.Selector.SAC_ELEMENT_NODE_SELECTOR -> translateElement((ElementSelector) sac); + case org.w3c.css.sac.Selector.SAC_PSEUDO_ELEMENT_SELECTOR -> translatePseudoElement((ElementSelector) sac); + case org.w3c.css.sac.Selector.SAC_CONDITIONAL_SELECTOR -> translateConditional((ConditionalSelector) sac); + case org.w3c.css.sac.Selector.SAC_DESCENDANT_SELECTOR -> { + DescendantSelector d = (DescendantSelector) sac; + yield new Descendant(translate(d.getAncestorSelector()), translateSimple(d.getSimpleSelector())); + } + case org.w3c.css.sac.Selector.SAC_CHILD_SELECTOR -> { + DescendantSelector c = (DescendantSelector) sac; + yield new Child(translate(c.getAncestorSelector()), translateSimple(c.getSimpleSelector())); + } + case org.w3c.css.sac.Selector.SAC_DIRECT_ADJACENT_SELECTOR -> { + SiblingSelector s = (SiblingSelector) sac; + yield new Adjacent(translate(s.getSelector()), translateSimple(s.getSiblingSelector())); + } + default -> throw new IllegalArgumentException( + "Unsupported SAC selector type: " + sac.getSelectorType() + " (" + sac + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + }; + } + + private static Selector translateSimple(SimpleSelector simple) { + return translate(simple); + } + + private static Selector translateElement(ElementSelector sel) { + String name = sel.getLocalName(); + return name == null ? new Universal() : new ElementType(name); + } + + private static Selector translatePseudoElement(ElementSelector sel) { + // Pseudo-element form (::first-line). The engine has never matched + // these; treat as the element it appears on (if any) or universal. + // In practice the parser only emits this when a stylesheet uses :: , + // which the supported subset does not. + String name = sel.getLocalName(); + return name == null ? new Universal() : new PseudoClass(name); + } + + private static Selector translateConditional(ConditionalSelector sel) { + Selector left = translate(sel.getSimpleSelector()); + Selector right = translateCondition(sel.getCondition()); + if (left instanceof Universal) { + return right; + } + return new And(left, right); + } + + private static Selector translateCondition(Condition condition) { + return switch (condition.getConditionType()) { + case Condition.SAC_CLASS_CONDITION -> new ClassSelector(((AttributeCondition) condition).getValue()); + case Condition.SAC_ID_CONDITION -> new IdSelector(((AttributeCondition) condition).getValue()); + case Condition.SAC_PSEUDO_CLASS_CONDITION -> new PseudoClass(((AttributeCondition) condition).getValue()); + case Condition.SAC_LANG_CONDITION -> { + // Modeled as a presence-form attribute selector keyed on lang; + // nothing in the supported subset uses :lang(), but the parser + // can still emit it. + AttributeCondition lang = (AttributeCondition) condition; + yield new AttributeSelector("lang", lang.getValue()); //$NON-NLS-1$ + } + case Condition.SAC_ATTRIBUTE_CONDITION -> { + AttributeCondition attr = (AttributeCondition) condition; + // Batik's stock Parser always calls createAttributeCondition with + // specified=false, regardless of whether the source was [attr] or + // [attr='value']. Distinguish the two by whether a value was + // supplied: null means the presence form [attr]. + yield new AttributeSelector(attr.getLocalName(), attr.getValue()); + } + case Condition.SAC_ONE_OF_ATTRIBUTE_CONDITION -> { + AttributeCondition attr = (AttributeCondition) condition; + yield new AttributeIncludes(attr.getLocalName(), attr.getValue()); + } + case Condition.SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION -> { + AttributeCondition attr = (AttributeCondition) condition; + yield new AttributeBeginHyphen(attr.getLocalName(), attr.getValue()); + } + case Condition.SAC_AND_CONDITION -> { + CombinatorCondition combo = (CombinatorCondition) condition; + yield new And(translateCondition(combo.getFirstCondition()), + translateCondition(combo.getSecondCondition())); + } + default -> throw new IllegalArgumentException( + "Unsupported SAC condition type: " + condition.getConditionType() + " (" + condition + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + }; + } +} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SelectorMatcher.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SelectorMatcher.java new file mode 100644 index 00000000000..82e97624dd3 --- /dev/null +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SelectorMatcher.java @@ -0,0 +1,288 @@ +/******************************************************************************* + * Copyright (c) 2026 Lars Vogel and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lars Vogel - initial API and implementation + *******************************************************************************/ +package org.eclipse.e4.ui.css.core.impl.engine.selector; + +import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Adjacent; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.And; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeBeginHyphen; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeIncludes; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Child; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.ClassSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Descendant; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.ElementType; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.IdSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.PseudoClass; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Selector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.SelectorList; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Universal; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Matches a {@link Selector} against an {@link Element}. + * + *

+ * Every method is static; the matcher carries no state. Callers pass the + * element being tested plus an optional pseudo-element string (the same + * argument the SAC engine carried) so that pseudo-class matching can defer + * to the existing {@link CSSStylableElement#isPseudoInstanceOf} contract. + *

+ * + *

+ * Tag-name comparison is case sensitive, matching the existing SAC matcher + * (Phase 1 test {@code testTagNameCaseSensitivity} in {@code CSSEngineTest} + * locks this in). Pseudo-class semantics also follow the existing engine: + * the static-pseudo-instance carve-out from + * {@code CSSPseudoClassConditionImpl} is preserved so cascade behaviour + * does not shift. + *

+ */ +public final class SelectorMatcher { + + private SelectorMatcher() { + // statics only + } + + /** + * @return {@code true} if {@code selector} matches {@code element} for + * the given pseudo state. + */ + public static boolean matches(Selector selector, Element element, String pseudoElement) { + return matches(selector, element, pseudoElement, null, 0); + } + + /** + * @return {@code true} if {@code selector} matches {@code element} for + * the given pseudo state, using a pre-computed ancestor hierarchy array if available. + */ + public static boolean matches(Selector selector, Element element, String pseudoElement, Element[] hierarchy, int hierarchyIndex) { + if (element == null) { + return false; + } + if (selector instanceof Universal) { + return true; + } + if (selector instanceof ElementType type) { + return matchesElementType(type, element); + } + if (selector instanceof ClassSelector cls) { + return matchesClass(cls, element); + } + if (selector instanceof IdSelector id) { + return matchesId(id, element); + } + if (selector instanceof AttributeSelector attr) { + return matchesAttribute(attr, element); + } + if (selector instanceof AttributeIncludes inc) { + return matchesAttributeIncludes(inc, element); + } + if (selector instanceof AttributeBeginHyphen beg) { + return matchesAttributeBeginHyphen(beg, element); + } + if (selector instanceof PseudoClass pc) { + return matchesPseudoClass(pc, element, pseudoElement); + } + if (selector instanceof And and) { + return matches(and.left(), element, pseudoElement, hierarchy, hierarchyIndex) + && matches(and.right(), element, pseudoElement, hierarchy, hierarchyIndex); + } + if (selector instanceof Descendant d) { + return matchesDescendant(d, element, pseudoElement, hierarchy, hierarchyIndex); + } + if (selector instanceof Child c) { + return matchesChild(c, element, pseudoElement, hierarchy, hierarchyIndex); + } + if (selector instanceof Adjacent a) { + return matchesAdjacent(a, element, pseudoElement, hierarchy, hierarchyIndex); + } + if (selector instanceof SelectorList list) { + return matchesAny(list, element, pseudoElement, hierarchy, hierarchyIndex); + } + throw new IllegalStateException("Unknown selector kind: " + selector.getClass()); //$NON-NLS-1$ + } + + private static boolean matchesElementType(ElementType type, Element element) { + String localName = type.localName(); + if (localName == null) { + return true; + } + String elementName = element.getPrefix() == null ? element.getNodeName() : element.getLocalName(); + return localName.equals(elementName); + } + + private static boolean matchesClass(ClassSelector cls, Element element) { + if (!(element instanceof CSSStylableElement stylable)) { + return false; + } + String elementClass = stylable.getCSSClass(); + if (elementClass == null) { + return false; + } + // CSS class attribute can be a whitespace-separated list of classes. + // Walk the string manually to avoid the regex compile + array allocation + // String.split forces on every match evaluation. + return containsWord(elementClass, cls.className()); + } + + private static boolean matchesId(IdSelector id, Element element) { + if (!(element instanceof CSSStylableElement stylable)) { + return false; + } + return id.id().equals(stylable.getCSSId()); + } + + private static boolean matchesAttribute(AttributeSelector attr, Element element) { + String name = attr.name(); + if (!element.hasAttribute(name)) { + return false; + } + String required = attr.value(); + if (required == null) { + // presence form: [attr] + return true; + } + return required.equals(element.getAttribute(name)); + } + + private static boolean matchesAttributeIncludes(AttributeIncludes inc, Element element) { + String actual = element.getAttribute(inc.name()); + if (actual == null) { + return false; + } + return containsWord(actual, inc.value()); + } + + /** + * Returns {@code true} if {@code haystack} contains {@code word} as a + * whitespace-separated token. Equivalent to splitting on + * {@code \s+} and checking for an exact token match, but without the + * regex compile and array allocation each call. + */ + private static boolean containsWord(String haystack, String word) { + if (word == null || word.isEmpty()) { + return false; + } + int wordLength = word.length(); + int length = haystack.length(); + int i = 0; + while (i < length) { + while (i < length && Character.isWhitespace(haystack.charAt(i))) { + i++; + } + int start = i; + while (i < length && !Character.isWhitespace(haystack.charAt(i))) { + i++; + } + if (i - start == wordLength && haystack.regionMatches(start, word, 0, wordLength)) { + return true; + } + } + return false; + } + + private static boolean matchesAttributeBeginHyphen(AttributeBeginHyphen beg, Element element) { + String actual = element.getAttribute(beg.name()); + if (actual == null) { + return false; + } + String value = beg.value(); + return actual.equals(value) || actual.startsWith(value + "-"); + } + + private static boolean matchesPseudoClass(PseudoClass pseudo, Element element, String pseudoElement) { + String name = pseudo.name(); + // If the caller is iterating a static-pseudo cascade, only match the + // pseudo argument on the way down. + if (pseudoElement != null && !pseudoElement.equals(name)) { + return false; + } + if (!(element instanceof CSSStylableElement stylable)) { + return false; + } + if (!stylable.isPseudoInstanceOf(name)) { + return false; + } + if (pseudoElement == null) { + // Same carve-out as CSSPseudoClassConditionImpl: when no pseudo + // element argument is supplied, pseudos that the element + // publishes only as static instances do not match the regular + // cascade. They get applied separately via the default style + // declaration map. + return !stylable.isStaticPseudoInstance(name); + } + return true; + } + + private static boolean matchesDescendant(Descendant d, Element element, String pseudoElement, Element[] hierarchy, int hierarchyIndex) { + if (!matches(d.descendant(), element, pseudoElement, hierarchy, hierarchyIndex)) { + return false; + } + if (hierarchy != null) { + for (int i = hierarchyIndex + 1; i < hierarchy.length; i++) { + if (matches(d.ancestor(), hierarchy[i], null, hierarchy, i)) { + return true; + } + } + return false; + } else { + Node parent = element.getParentNode(); + while (parent instanceof Element parentElement) { + if (matches(d.ancestor(), parentElement, null, null, 0)) { + return true; + } + parent = parentElement.getParentNode(); + } + return false; + } + } + + private static boolean matchesChild(Child c, Element element, String pseudoElement, Element[] hierarchy, int hierarchyIndex) { + if (!matches(c.child(), element, pseudoElement, hierarchy, hierarchyIndex)) { + return false; + } + if (hierarchy != null) { + int parentIdx = hierarchyIndex + 1; + if (parentIdx < hierarchy.length) { + return matches(c.parent(), hierarchy[parentIdx], null, hierarchy, parentIdx); + } + return false; + } else { + Node parent = element.getParentNode(); + return parent instanceof Element parentElement && matches(c.parent(), parentElement, null, null, 0); + } + } + + private static boolean matchesAdjacent(Adjacent a, Element element, String pseudoElement, Element[] hierarchy, int hierarchyIndex) { + if (!matches(a.second(), element, pseudoElement, hierarchy, hierarchyIndex)) { + return false; + } + Node previous = element.getPreviousSibling(); + while (previous != null && !(previous instanceof Element)) { + previous = previous.getPreviousSibling(); + } + return previous instanceof Element previousElement && matches(a.first(), previousElement, null, null, 0); + } + + private static boolean matchesAny(SelectorList list, Element element, String pseudoElement, Element[] hierarchy, int hierarchyIndex) { + for (Selector alternative : list.alternatives()) { + if (matches(alternative, element, pseudoElement, hierarchy, hierarchyIndex)) { + return true; + } + } + return false; + } +} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/Selectors.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/Selectors.java new file mode 100644 index 00000000000..ebca60b165b --- /dev/null +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/Selectors.java @@ -0,0 +1,357 @@ +/******************************************************************************* + * Copyright (c) 2026 Lars Vogel and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lars Vogel - initial API and implementation + *******************************************************************************/ +package org.eclipse.e4.ui.css.core.impl.engine.selector; + +import java.util.List; + +/** + * Internal CSS selector AST. + * + *

+ * The engine historically exposed W3C SAC selectors + * ({@code org.w3c.css.sac.Selector} and friends) and matched against them + * through a hierarchy of vendored Batik wrapper classes under + * {@code impl/sac/*}. This package replaces both with a small set of records + * that the engine owns end to end. The W3C SAC types stay only as long as + * the parser still emits them; a translator turns the SAC selector tree + * produced by the Batik SAC parser into one of these records before it + * reaches the engine matcher. + *

+ * + *

+ * Specificity follows CSS 2.1: 100 per id, 10 per class / attribute / + * pseudo-class, 1 per element, 0 for the universal selector. Combinators + * sum the specificity of their operands; selector lists report the maximum + * specificity over their alternatives. + *

+ */ +public final class Selectors { + + private Selectors() { + // constants only + } + + /** A parsed CSS selector. Sealed; pattern-match in the matcher. */ + public sealed interface Selector + permits Universal, ElementType, ClassSelector, IdSelector, AttributeSelector, + AttributeIncludes, AttributeBeginHyphen, PseudoClass, And, Descendant, Child, Adjacent, SelectorList { + + /** CSS specificity contribution of this selector. */ + int specificity(); + + /** Best-effort textual reproduction of the selector. */ + String text(); + } + + /** {@code *} — matches any element. */ + public record Universal() implements Selector { + @Override + public int specificity() { + return 0; + } + + @Override + public String text() { + return "*"; //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code Button} — matches by local element name. */ + public record ElementType(String localName) implements Selector { + @Override + public int specificity() { + return 1; + } + + @Override + public String text() { + return localName; + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code .foo} — matches by CSS class. */ + public record ClassSelector(String className) implements Selector { + @Override + public int specificity() { + return 10; + } + + @Override + public String text() { + return "." + className; //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code #foo} — matches by CSS id. */ + public record IdSelector(String id) implements Selector { + @Override + public int specificity() { + return 100; + } + + @Override + public String text() { + return "#" + id; //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** + * {@code [attr]} or {@code [attr='value']}. {@code value} is {@code null} + * for the presence form and the empty string for {@code [attr='']}. + */ + public record AttributeSelector(String name, String value) implements Selector { + @Override + public int specificity() { + return 10; + } + + @Override + public String text() { + return value == null ? "[" + name + "]" : "[" + name + "='" + value + "']"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code [attr~='value']} — matches when {@code attr} contains {@code value} as a whitespace-separated word. */ + public record AttributeIncludes(String name, String value) implements Selector { + @Override + public int specificity() { + return 10; + } + + @Override + public String text() { + return "[" + name + "~='" + value + "']"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code [attr|='value']} — matches when {@code attr} equals {@code value} or starts with {@code value-}. */ + public record AttributeBeginHyphen(String name, String value) implements Selector { + @Override + public int specificity() { + return 10; + } + + @Override + public String text() { + return "[" + name + "|='" + value + "']"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Override + public String toString() { + return text(); + } + } + + /** + * {@code :name} — matches when the element answers true to + * {@code isPseudoInstanceOf(name)} on its CSS-stylable element wrapper. + */ + public record PseudoClass(String name) implements Selector { + @Override + public int specificity() { + return 10; + } + + @Override + public String text() { + return ":" + name; //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** + * Compound selector: every operand must match the same element. Built + * by the translator for forms like {@code Button.primary#go} or + * {@code [a][b]} where multiple simple selectors apply to one element. + */ + public record And(Selector left, Selector right) implements Selector { + @Override + public int specificity() { + return left.specificity() + right.specificity(); + } + + @Override + public String text() { + return left.text() + right.text(); + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code ancestor descendant} — descendant combinator. */ + public record Descendant(Selector ancestor, Selector descendant) implements Selector { + @Override + public int specificity() { + return ancestor.specificity() + descendant.specificity(); + } + + @Override + public String text() { + return ancestor.text() + " " + descendant.text(); //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code parent > child} — child combinator. */ + public record Child(Selector parent, Selector child) implements Selector { + @Override + public int specificity() { + return parent.specificity() + child.specificity(); + } + + @Override + public String text() { + return parent.text() + " > " + child.text(); //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** {@code first + second} — direct adjacent sibling combinator. */ + public record Adjacent(Selector first, Selector second) implements Selector { + @Override + public int specificity() { + return first.specificity() + second.specificity(); + } + + @Override + public String text() { + return first.text() + " + " + second.text(); //$NON-NLS-1$ + } + + @Override + public String toString() { + return text(); + } + } + + /** + * {@code a, b} — selector list. Specificity reports the maximum over the + * alternatives so cascade ordering can match a list against an element by + * iterating its alternatives. + * + *

+ * A regular final class rather than a record because the cascade reads + * {@link #specificity()} once per matched alternative and we want it + * precomputed; record components cannot host derived state. + *

+ */ + public static final class SelectorList implements Selector { + + private final List alternatives; + private final int specificity; + + public SelectorList(List alternatives) { + this.alternatives = List.copyOf(alternatives); + int max = 0; + for (Selector alternative : this.alternatives) { + int s = alternative.specificity(); + if (s > max) { + max = s; + } + } + this.specificity = max; + } + + public List alternatives() { + return alternatives; + } + + /** Number of alternatives in the list. SAC-style accessor for callers iterating the list. */ + public int getLength() { + return alternatives.size(); + } + + /** {@code i}-th alternative. SAC-style accessor for callers iterating the list. */ + public Selector item(int i) { + return alternatives.get(i); + } + + @Override + public int specificity() { + return specificity; + } + + @Override + public String text() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < alternatives.size(); i++) { + if (i > 0) { + sb.append(", "); //$NON-NLS-1$ + } + sb.append(alternatives.get(i).text()); + } + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + return o instanceof SelectorList other && alternatives.equals(other.alternatives); + } + + @Override + public int hashCode() { + return alternatives.hashCode(); + } + + @Override + public String toString() { + return text(); + } + } +} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractAttributeCondition.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractAttributeCondition.java deleted file mode 100644 index fabffbad828..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractAttributeCondition.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Objects; -import org.w3c.css.sac.AttributeCondition; - -/** - * This class provides an abstract implementation of the {@link - * org.w3c.css.sac.AttributeCondition} interface. - */ -public abstract class AbstractAttributeCondition implements AttributeCondition, - ExtendedCondition { - - /** - * The attribute value. - */ - protected String value; - - /** - * Creates a new AbstractAttributeCondition object. - */ - protected AbstractAttributeCondition(String value) { - this.value = value; - } - - /** - * Indicates whether some other object is "equal to" this one. - * - * @param obj - * the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - AbstractAttributeCondition c = (AbstractAttributeCondition) obj; - return c.value.equals(value); - } - - /** - * equal objects should have equal hashCodes. - * - * @return hashCode of this AbstractAttributeCondition - */ - @Override - public int hashCode() { - return Objects.hashCode(value); - } - - /** - * Returns the specificity of this condition. - */ - @Override - public int getSpecificity() { - return 1 << 8; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getValue()}. - */ - @Override - public String getValue() { - return value; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractCombinatorCondition.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractCombinatorCondition.java deleted file mode 100644 index 0de6c81b86c..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractCombinatorCondition.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.css.sac.CombinatorCondition; -import org.w3c.css.sac.Condition; - -/** - * This class provides an abstract implementation of the {@link - * org.w3c.css.sac.CombinatorCondition} interface. - */ -public abstract class AbstractCombinatorCondition implements - CombinatorCondition, ExtendedCondition { - - /** - * The first condition. - */ - protected Condition firstCondition; - - /** - * The second condition. - */ - protected Condition secondCondition; - - /** - * Creates a new CombinatorCondition object. - */ - protected AbstractCombinatorCondition(Condition c1, Condition c2) { - firstCondition = c1; - secondCondition = c2; - } - - /** - * Indicates whether some other object is "equal to" this one. - * - * @param obj - * the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - AbstractCombinatorCondition c = (AbstractCombinatorCondition) obj; - return (c.firstCondition.equals(firstCondition) && c.secondCondition - .equals(secondCondition)); - } - - /** - * Returns the specificity of this condition. - */ - @Override - public int getSpecificity() { - return ((ExtendedCondition) getFirstCondition()).getSpecificity() - + ((ExtendedCondition) getSecondCondition()).getSpecificity(); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.CombinatorCondition#getFirstCondition()}. - */ - @Override - public Condition getFirstCondition() { - return firstCondition; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.CombinatorCondition#getSecondCondition()}. - */ - @Override - public Condition getSecondCondition() { - return secondCondition; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractDescendantSelector.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractDescendantSelector.java deleted file mode 100644 index f183af1ccae..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractDescendantSelector.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.css.sac.DescendantSelector; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SimpleSelector; - -/** - * This class provides an abstract implementation of the {@link - * org.w3c.css.sac.DescendantSelector} interface. - */ -public abstract class AbstractDescendantSelector - implements DescendantSelector, - ExtendedSelector { - - /** - * The ancestor selector. - */ - protected Selector ancestorSelector; - - /** - * The simple selector. - */ - protected SimpleSelector simpleSelector; - - /** - * Creates a new DescendantSelector object. - */ - protected AbstractDescendantSelector(Selector ancestor, - SimpleSelector simple) { - ancestorSelector = ancestor; - simpleSelector = simple; - } - - /** - * Indicates whether some other object is "equal to" this one. - * @param obj the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - AbstractDescendantSelector s = (AbstractDescendantSelector)obj; - return s.simpleSelector.equals(simpleSelector); - } - - /** - * Returns the specificity of this selector. - */ - @Override - public int getSpecificity() { - return ((ExtendedSelector)ancestorSelector).getSpecificity() + - ((ExtendedSelector)simpleSelector).getSpecificity(); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.DescendantSelector#getAncestorSelector()}. - */ - @Override - public Selector getAncestorSelector() { - return ancestorSelector; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.DescendantSelector#getSimpleSelector()}. - */ - @Override - public SimpleSelector getSimpleSelector() { - return simpleSelector; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractElementSelector.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractElementSelector.java deleted file mode 100644 index 529b86a0fbb..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractElementSelector.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.ElementSelector; - -/** - * This class provides an abstract implementation of the ElementSelector - * interface. - */ -public abstract class AbstractElementSelector implements ElementSelector, ExtendedSelector { - - /** - * The namespace URI. - */ - protected String namespaceURI; - - /** - * The local name. - */ - protected String localName; - - /** - * Creates a new ElementSelector object. - */ - protected AbstractElementSelector(String uri, String name) { - namespaceURI = uri; - localName = name; - } - - /** - * Indicates whether some other object is "equal to" this one. - * @param obj the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - AbstractElementSelector s = (AbstractElementSelector)obj; - return (s.namespaceURI.equals(namespaceURI) && s.localName.equals(localName)); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ElementSelector#getNamespaceURI()}. - */ - @Override - public String getNamespaceURI() { - return namespaceURI; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ElementSelector#getLocalName()}. - */ - @Override - public String getLocalName() { - return localName; - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractSiblingSelector.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractSiblingSelector.java deleted file mode 100644 index bb061dd13e0..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/AbstractSiblingSelector.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SiblingSelector; -import org.w3c.css.sac.SimpleSelector; - -/** - * This class provides an abstract implementation of the {@link - * org.w3c.css.sac.SiblingSelector} interface. - */ -public abstract class AbstractSiblingSelector implements SiblingSelector, - ExtendedSelector { - - /** - * The node type. - */ - protected short nodeType; - - /** - * The selector. - */ - protected Selector selector; - - /** - * The simple selector. - */ - protected SimpleSelector simpleSelector; - - /** - * Creates a new SiblingSelector object. - */ - protected AbstractSiblingSelector(short type, Selector sel, - SimpleSelector simple) { - nodeType = type; - selector = sel; - simpleSelector = simple; - } - - /** - * Returns the node type. - */ - @Override - public short getNodeType() { - return nodeType; - } - - /** - * Indicates whether some other object is "equal to" this one. - * - * @param obj - * the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - AbstractSiblingSelector s = (AbstractSiblingSelector) obj; - return s.simpleSelector.equals(simpleSelector); - } - - /** - * Returns the specificity of this selector. - */ - @Override - public int getSpecificity() { - return ((ExtendedSelector) selector).getSpecificity() - + ((ExtendedSelector) simpleSelector).getSpecificity(); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SiblingSelector#getSelector()}. - */ - @Override - public Selector getSelector() { - return selector; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SiblingSelector#getSiblingSelector()}. - */ - @Override - public SimpleSelector getSiblingSelector() { - return simpleSelector; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSAndConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSAndConditionImpl.java deleted file mode 100644 index b9d528d05ad..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSAndConditionImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Condition; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.CombinatorCondition} interface. - */ -public class CSSAndConditionImpl extends AbstractCombinatorCondition { - /** - * Creates a new CombinatorCondition object. - */ - public CSSAndConditionImpl(Condition c1, Condition c2) { - super(c1, c2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_AND_CONDITION; - } - - /** - * Tests whether this condition matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - return ((ExtendedCondition)getFirstCondition()).match(e, pseudoE) && - ((ExtendedCondition)getSecondCondition()).match(e, pseudoE); - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - ((ExtendedCondition)getFirstCondition()).fillAttributeSet(attrSet); - ((ExtendedCondition)getSecondCondition()).fillAttributeSet(attrSet); - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - return String.valueOf( getFirstCondition() ) + getSecondCondition(); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSAttributeConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSAttributeConditionImpl.java deleted file mode 100644 index 3467d068938..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSAttributeConditionImpl.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.AttributeCondition} interface. - */ -public class CSSAttributeConditionImpl extends AbstractAttributeCondition { - /** - * The attribute's local name. - */ - protected String localName; - - /** - * The attribute's namespace URI. - */ - protected String namespaceURI; - - /** - * Whether this condition applies to specified attributes. - */ - protected boolean specified; - - /** - * Creates a new CSSAttributeCondition object. - */ - public CSSAttributeConditionImpl(String localName, String namespaceURI, - boolean specified, String value) { - super(value); - this.localName = localName; - this.namespaceURI = namespaceURI; - this.specified = specified; - } - - /** - * Indicates whether some other object is "equal to" this one. - * - * @param obj - * the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) { - return false; - } - CSSAttributeConditionImpl c = (CSSAttributeConditionImpl) obj; - return (c.namespaceURI.equals(namespaceURI) - && c.localName.equals(localName) && c.specified == specified); - } - - /** - * equal objects should have equal hashCodes. - * - * @return hashCode of this CSSAttributeCondition - */ - @Override - public int hashCode() { - return namespaceURI.hashCode() ^ localName.hashCode() - ^ Boolean.hashCode(specified); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_ATTRIBUTE_CONDITION; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getNamespaceURI()}. - */ - @Override - public String getNamespaceURI() { - return namespaceURI; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getLocalName()}. - */ - @Override - public String getLocalName() { - return localName; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getSpecified()}. - */ - @Override - public boolean getSpecified() { - return specified; - } - - /** - * Tests whether this condition matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - if (!e.hasAttribute(getLocalName())) { - return false; - } - String val = getValue(); - if (val == null) { - return true; - } - return e.getAttribute(getLocalName()).equals(val); - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - attrSet.add(localName); - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - if (value == null) { - return '[' + localName + ']'; - } - return '[' + localName + "=\"" + value + "\"]"; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSBeginHyphenAttributeConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSBeginHyphenAttributeConditionImpl.java deleted file mode 100644 index 12064bb8e47..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSBeginHyphenAttributeConditionImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.AttributeCondition} interface. - */ -public class CSSBeginHyphenAttributeConditionImpl extends - CSSAttributeConditionImpl { - - /** - * Creates a new CSSAttributeCondition object. - */ - public CSSBeginHyphenAttributeConditionImpl(String localName, - String namespaceURI, boolean specified, String value) { - super(localName, namespaceURI, specified, value); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION; - } - - /** - * Tests whether this condition matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - return e.getAttribute(getLocalName()).startsWith(getValue()); - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - return '[' + getLocalName() + "|=\"" + getValue() + "\"]"; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSChildSelectorImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSChildSelectorImpl.java deleted file mode 100644 index 450031025f2..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSChildSelectorImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SimpleSelector; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.DescendantSelector} interface. - */ -public class CSSChildSelectorImpl extends AbstractDescendantSelector { - - /** - * Creates a new CSSChildSelector object. - */ - public CSSChildSelectorImpl(Selector ancestor, SimpleSelector simple) { - super(ancestor, simple); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Selector#getSelectorType()}. - */ - @Override - public short getSelectorType() { - return SAC_CHILD_SELECTOR; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, Node[] hierarchy, int parentIndex, String pseudoE) { - if (hierarchy == null || parentIndex >= hierarchy.length) { - return false; - } - - Node n = hierarchy[parentIndex]; - if (n != null && n.getNodeType() == Node.ELEMENT_NODE) { - return ((ExtendedSelector) getAncestorSelector()).match((Element) n, hierarchy, parentIndex + 1, null) - && ((ExtendedSelector) getSimpleSelector()).match(e, hierarchy, parentIndex + 1, pseudoE); - } - return false; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - Node n = e.getParentNode(); - if (n != null && n.getNodeType() == Node.ELEMENT_NODE) { - return ((ExtendedSelector) getAncestorSelector()).match((Element) n, - null) - && ((ExtendedSelector) getSimpleSelector()).match(e, pseudoE); - } - return false; - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - ((ExtendedSelector)getAncestorSelector()).fillAttributeSet(attrSet); - ((ExtendedSelector)getSimpleSelector()).fillAttributeSet(attrSet); - } - - /** - * Returns a representation of the selector. - */ - @Override - public String toString() { - SimpleSelector s = getSimpleSelector(); - if (s.getSelectorType() == SAC_PSEUDO_ELEMENT_SELECTOR) { - return String.valueOf( getAncestorSelector() ) + s; - } - return getAncestorSelector() + " > " + s; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSClassConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSClassConditionImpl.java deleted file mode 100644 index 521c7743af1..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSClassConditionImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.AttributeCondition} interface. - */ -public class CSSClassConditionImpl extends CSSAttributeConditionImpl { - - /** - * Creates a new CSSAttributeCondition object. - */ - public CSSClassConditionImpl(String localName, String namespaceURI, - String value) { - super(localName, namespaceURI, true, value); - } - - @Override - public boolean match(Element e, String pseudoE) { - String attr = null; - if ((e instanceof CSSStylableElement)) { - attr = ((CSSStylableElement) e).getCSSClass(); - } else { - attr = e.getAttribute("class"); - } - if (attr == null || attr.length() < 1) { - return false; - } - String val = getValue(); - int attrLen = attr.length(); - int valLen = val.length(); - for (int i = attr.indexOf(val); i != -1; i = attr.indexOf(val, i - + valLen)) { - if ((i == 0 || Character.isSpaceChar(attr.charAt(i - 1))) - && (i + valLen == attrLen || Character.isSpaceChar(attr - .charAt(i + valLen)))) { - return true; - } - } - - return false; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSConditionFactoryImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSConditionFactoryImpl.java deleted file mode 100644 index 24676814228..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSConditionFactoryImpl.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.css.sac.AttributeCondition; -import org.w3c.css.sac.CSSException; -import org.w3c.css.sac.CombinatorCondition; -import org.w3c.css.sac.Condition; -import org.w3c.css.sac.ConditionFactory; -import org.w3c.css.sac.ContentCondition; -import org.w3c.css.sac.LangCondition; -import org.w3c.css.sac.NegativeCondition; -import org.w3c.css.sac.PositionalCondition; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.ConditionFactory} interface. - */ -public class CSSConditionFactoryImpl implements ConditionFactory { - - private static final String NOT_IMPLEMENTED_IN_CSS2 = "Not implemented in CSS2"; //$NON-NLS-1$ - - /** - * The class attribute namespace URI. - */ - protected String classNamespaceURI; - - /** - * The class attribute local name. - */ - protected String classLocalName; - - /** - * The id attribute namespace URI. - */ - protected String idNamespaceURI; - - /** - * The id attribute local name. - */ - protected String idLocalName; - - /** - * Creates a new condition factory. - */ - public CSSConditionFactoryImpl(String cns, String cln, String idns, - String idln) { - classNamespaceURI = cns; - classLocalName = cln; - idNamespaceURI = idns; - idLocalName = idln; - } - - /** - * SAC: Implements {@link - * ConditionFactory#createAndCondition(Condition,Condition)}. - */ - @Override - public CombinatorCondition createAndCondition(Condition first, - Condition second) throws CSSException { - return new CSSAndConditionImpl(first, second); - } - - /** - * SAC: Implements {@link - * ConditionFactory#createOrCondition(Condition,Condition)}. - */ - @Override - public CombinatorCondition createOrCondition(Condition first, - Condition second) throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createNegativeCondition(Condition)}. - */ - @Override - public NegativeCondition createNegativeCondition(Condition condition) - throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * ConditionFactory#createPositionalCondition(int,boolean,boolean)}. - */ - @Override - public PositionalCondition createPositionalCondition(int position, - boolean typeNode, boolean type) throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * ConditionFactory#createAttributeCondition(String,String,boolean,String)}. - */ - @Override - public AttributeCondition createAttributeCondition(String localName, - String namespaceURI, boolean specified, String value) - throws CSSException { - return new CSSAttributeConditionImpl(localName, namespaceURI, specified, - value); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createIdCondition(String)}. - */ - @Override - public AttributeCondition createIdCondition(String value) - throws CSSException { - return new CSSIdConditionImpl(idNamespaceURI, idLocalName, value); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createLangCondition(String)}. - */ - @Override - public LangCondition createLangCondition(String lang) throws CSSException { - return new CSSLangConditionImpl(lang); - } - - /** - * SAC: Implements {@link - * ConditionFactory#createOneOfAttributeCondition(String,String,boolean,String)}. - */ - @Override - public AttributeCondition createOneOfAttributeCondition(String localName, - String nsURI, boolean specified, String value) throws CSSException { - return new CSSOneOfAttributeConditionImpl(localName, nsURI, specified, - value); - } - - /** - * SAC: Implements {@link - * ConditionFactory#createBeginHyphenAttributeCondition(String,String,boolean,String)}. - */ - @Override - public AttributeCondition createBeginHyphenAttributeCondition( - String localName, String namespaceURI, boolean specified, - String value) throws CSSException { - return new CSSBeginHyphenAttributeConditionImpl(localName, - namespaceURI, specified, value); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createClassCondition(String,String)}. - */ - @Override - public AttributeCondition createClassCondition(String namespaceURI, - String value) throws CSSException { - return new CSSClassConditionImpl(classLocalName, classNamespaceURI, value); - } - - /** - * SAC: Implements {@link - * ConditionFactory#createPseudoClassCondition(String,String)}. - */ - @Override - public AttributeCondition createPseudoClassCondition(String namespaceURI, - String value) throws CSSException { - return new CSSPseudoClassConditionImpl(namespaceURI, value); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createOnlyChildCondition()}. - */ - @Override - public Condition createOnlyChildCondition() throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createOnlyTypeCondition()}. - */ - @Override - public Condition createOnlyTypeCondition() throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionFactory#createContentCondition(String)}. - */ - @Override - public ContentCondition createContentCondition(String data) - throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSConditionalSelectorImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSConditionalSelectorImpl.java deleted file mode 100644 index c4cc09ad9c1..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSConditionalSelectorImpl.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Condition; -import org.w3c.css.sac.ConditionalSelector; -import org.w3c.css.sac.SimpleSelector; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.ConditionalSelector} interface. - */ -public class CSSConditionalSelectorImpl implements ConditionalSelector, ExtendedSelector { - - /** - * The simple selector. - */ - protected SimpleSelector simpleSelector; - - /** - * The condition. - */ - protected Condition condition; - - /** - * Creates a new ConditionalSelector object. - */ - public CSSConditionalSelectorImpl(SimpleSelector s, Condition c) { - simpleSelector = s; - condition = c; - } - - /** - * Indicates whether some other object is "equal to" this one. - * @param obj the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - CSSConditionalSelectorImpl s = (CSSConditionalSelectorImpl)obj; - return (s.simpleSelector.equals(simpleSelector) && - s.condition.equals(condition)); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Selector#getSelectorType()}. - */ - @Override - public short getSelectorType() { - return SAC_CONDITIONAL_SELECTOR; - } - - @Override - public boolean match(Element e, Node[] hierarchy, int parentIndex, String pseudoE) { - return ((ExtendedSelector)getSimpleSelector()).match(e, hierarchy, parentIndex, pseudoE) && - ((ExtendedCondition)getCondition()).match(e, pseudoE); - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - return ((ExtendedSelector)getSimpleSelector()).match(e, pseudoE) && - ((ExtendedCondition)getCondition()).match(e, pseudoE); - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - ((ExtendedSelector)getSimpleSelector()).fillAttributeSet(attrSet); - ((ExtendedCondition)getCondition()).fillAttributeSet(attrSet); - } - - /** - * Returns the specificity of this selector. - */ - @Override - public int getSpecificity() { - return ((ExtendedSelector)getSimpleSelector()).getSpecificity() + - ((ExtendedCondition)getCondition()).getSpecificity(); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionalSelector#getSimpleSelector()}. - */ - @Override - public SimpleSelector getSimpleSelector() { - return simpleSelector; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.ConditionalSelector#getCondition()}. - */ - @Override - public Condition getCondition() { - return condition; - } - - /** - * Returns a representation of the selector. - */ - @Override - public String toString() { - return String.valueOf( simpleSelector ) + condition; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDescendantSelectorImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDescendantSelectorImpl.java deleted file mode 100644 index 44f3568dfc3..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDescendantSelectorImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SimpleSelector; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * This class provides an implementation for the - * {@link org.w3c.css.sac.DescendantSelector} interface. - */ -public class CSSDescendantSelectorImpl extends AbstractDescendantSelector { - - /** - * Creates a new CSSDescendantSelector object. - */ - public CSSDescendantSelectorImpl(Selector ancestor, SimpleSelector simple) { - super(ancestor, simple); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Selector#getSelectorType()}. - */ - @Override - public short getSelectorType() { - return SAC_DESCENDANT_SELECTOR; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, Node[] hierarchy, int parentIndex, String pseudoE) { - ExtendedSelector p = (ExtendedSelector) getAncestorSelector(); - if (!((ExtendedSelector) getSimpleSelector()).match(e, hierarchy, parentIndex, pseudoE)) { - return false; - } - - if (hierarchy == null) { - return false; - } - - Node n; - int length = hierarchy.length; - for (int i = parentIndex; i < length; i++) { - n = hierarchy[i]; - if (n != null && n.getNodeType() == Node.ELEMENT_NODE - && p.match((Element) n, hierarchy, i + 1, null)) { - return true; - } - } - return false; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - ExtendedSelector p = (ExtendedSelector) getAncestorSelector(); - if (!((ExtendedSelector) getSimpleSelector()).match(e, pseudoE)) { - return false; - } - for (Node n = e.getParentNode(); n != null; n = n.getParentNode()) { - if (n.getNodeType() == Node.ELEMENT_NODE && p.match((Element) n, null)) { - return true; - } - } - return false; - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - ((ExtendedSelector)getSimpleSelector()).fillAttributeSet(attrSet); - } - - /** - * Returns a representation of the selector. - */ - @Override - public String toString() { - return getAncestorSelector() + " " + getSimpleSelector(); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDirectAdjacentSelectorImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDirectAdjacentSelectorImpl.java deleted file mode 100644 index 73eea3eb684..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDirectAdjacentSelectorImpl.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SimpleSelector; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * This class provides an implementation for the - * {@link org.w3c.css.sac.DescendantSelector} interface. - */ -public class CSSDirectAdjacentSelectorImpl extends AbstractSiblingSelector { - - /** - * Creates a new CSSDirectAdjacentSelector object. - */ - public CSSDirectAdjacentSelectorImpl(short type, Selector parent, SimpleSelector simple) { - super(type, parent, simple); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Selector#getSelectorType()}. - */ - @Override - public short getSelectorType() { - return SAC_DIRECT_ADJACENT_SELECTOR; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, Node[] hiearchy, int parentIndex, String pseudoE) { - Node n = e; - if (!((ExtendedSelector) getSiblingSelector()).match(e, hiearchy, parentIndex, pseudoE)) { - return false; - } - - while ((n = n.getPreviousSibling()) != null && n.getNodeType() != Node.ELEMENT_NODE) { - } - - if (n == null) { - return false; - } - - return ((ExtendedSelector) getSelector()).match((Element) n, hiearchy, parentIndex, null); - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - Node n = e; - if (!((ExtendedSelector)getSiblingSelector()).match(e, pseudoE)) { - return false; - } - while ((n = n.getPreviousSibling()) != null && n.getNodeType() != Node.ELEMENT_NODE) { - } - - if (n == null) { - return false; - } - - return ((ExtendedSelector)getSelector()).match((Element)n, null); - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - ((ExtendedSelector)getSelector()).fillAttributeSet(attrSet); - ((ExtendedSelector)getSiblingSelector()).fillAttributeSet(attrSet); - } - - /** - * Returns a representation of the selector. - */ - @Override - public String toString() { - return getSelector() + " + " + getSiblingSelector(); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java index 150c95c4b7a..9456b6a94e2 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java @@ -25,6 +25,7 @@ import org.eclipse.e4.ui.css.core.impl.dom.CSSUnknownRuleImpl; import org.eclipse.e4.ui.css.core.impl.dom.CSSValueFactory; import org.eclipse.e4.ui.css.core.impl.dom.MediaListImpl; +import org.eclipse.e4.ui.css.core.impl.engine.selector.SacTranslator; import org.eclipse.e4.ui.css.core.sac.ExtendedDocumentHandler; import org.w3c.css.sac.CSSException; import org.w3c.css.sac.InputSource; @@ -165,9 +166,10 @@ public void endFontFace() throws CSSException { @Override public void startSelector(SelectorList selectors) throws CSSException { - // Create the style rule and add it to the rule list + // Translate the SAC selector list into the engine's internal AST at + // this boundary so nothing downstream needs to touch SAC types. CSSStyleRuleImpl rule = new CSSStyleRuleImpl(parentStyleSheet, null, - selectors); + SacTranslator.translate(selectors)); if (!getNodeStack().empty()) { ((CSSRuleListImpl) getNodeStack().peek()).add(rule); } diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSElementSelectorImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSElementSelectorImpl.java deleted file mode 100644 index f24e1aeea7f..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSElementSelectorImpl.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.dom.Element; - -/** - * This class implements the {@link org.w3c.css.sac.ElementSelector} interface. - */ -public class CSSElementSelectorImpl extends AbstractElementSelector { - - /** - * Creates a new ElementSelector object. - */ - public CSSElementSelectorImpl(String uri, String name) { - super(uri, name); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Selector#getSelectorType()}. - */ - @Override - public short getSelectorType() { - return SAC_ELEMENT_NODE_SELECTOR; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - String name = getLocalName(); - if (name == null) { - if (namespaceURI != null) { - return namespaceURI.equals(e.getNamespaceURI()); - } else { - return true; - } - } - String eName; - if (e.getPrefix() == null) { - eName = e.getNodeName(); - } else { - eName = e.getLocalName(); - } - // According to CSS 2 section 5.1 element - // names in selectors are case-sensitive for XML. - if (eName.equals(name)) { - if (namespaceURI != null) { - return namespaceURI.equals(e.getNamespaceURI()); - } else { - return true; - } - } - return false; - // For HTML - // return eName.equalsIgnoreCase(name); - } - - /** - * Returns the specificity of this selector. - */ - @Override - public int getSpecificity() { - return (getLocalName() == null) ? 0 : 1; - } - - /** - * Returns a representation of the selector. - */ - @Override - public String toString() { - String name = getLocalName(); - if (name == null) { - return "*"; - } - return name; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSIdConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSIdConditionImpl.java deleted file mode 100644 index eec162ea03d..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSIdConditionImpl.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.AttributeCondition} interface. - */ -public class CSSIdConditionImpl extends AbstractAttributeCondition { - - /** - * The id attribute namespace URI. - */ - protected String namespaceURI; - - /** - * The id attribute local name. - */ - protected String localName; - - /** - * Creates a new CSSAttributeCondition object. - */ - public CSSIdConditionImpl(String ns, String ln, String value) { - super(value); - namespaceURI = ns; - localName = ln; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_ID_CONDITION; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getNamespaceURI()}. - */ - @Override - public String getNamespaceURI() { - return namespaceURI; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getLocalName()}. - */ - @Override - public String getLocalName() { - return localName; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getSpecified()}. - */ - @Override - public boolean getSpecified() { - return true; - } - - /** - * Tests whether this condition matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - String id = null; - if (e instanceof CSSStylableElement) { - id = ((CSSStylableElement) e).getCSSId(); - } else { - id = e.getAttribute("id"); - } - if (id == null) { - return false; - } - return id.equals(getValue()); - // return super.match(e, pseudoE); - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - attrSet.add(localName); - } - - /** - * Returns the specificity of this condition. - */ - @Override - public int getSpecificity() { - return 1 << 16; - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - return '#' + getValue(); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSLangConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSLangConditionImpl.java deleted file mode 100644 index 4789469f7fa..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSLangConditionImpl.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.LangCondition; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.LangCondition} interface. - */ -public class CSSLangConditionImpl implements LangCondition, ExtendedCondition { - /** - * The language. - */ - protected String lang; - - /** - * The language with a hyphen suffixed. - */ - protected String langHyphen; - - /** - * Creates a new LangCondition object. - */ - public CSSLangConditionImpl(String lang) { - this.lang = lang.toLowerCase(); - this.langHyphen = lang + '-'; - } - - /** - * Indicates whether some other object is "equal to" this one. - * @param obj the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (obj == null || (obj.getClass() != getClass())) { - return false; - } - CSSLangConditionImpl c = (CSSLangConditionImpl)obj; - return c.lang.equals(lang); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_LANG_CONDITION; - } - - /** - * SAC: Implements {@link org.w3c.css.sac.LangCondition#getLang()}. - */ - @Override - public String getLang() { - return lang; - } - - /** - * Returns the specificity of this condition. - */ - @Override - public int getSpecificity() { - return 1 << 8; - } - - /** - * Tests whether this condition matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - String s = e.getAttribute("lang").toLowerCase(); - if (s.equals(lang) || s.startsWith(langHyphen)) { - return true; - } - // s = e.getAttributeNS(XMLConstants.XML_NAMESPACE_URI, - // XMLConstants.XML_LANG_ATTRIBUTE).toLowerCase(); - return s.equals(lang) || s.startsWith(langHyphen); - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - attrSet.add("lang"); - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - return ":lang(" + lang + ')'; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSOneOfAttributeConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSOneOfAttributeConditionImpl.java deleted file mode 100644 index fb4ebbd0428..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSOneOfAttributeConditionImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/******************************************************************************* - * Contributors: - * This class was copied from org.apache.batik.css.engine.sac - * Apache Batik project - initial API and implementation - * Alain Le Guennec - Bug 458334 - *******************************************************************************/ -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.StringTokenizer; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.AttributeCondition} interface. - */ -public class CSSOneOfAttributeConditionImpl extends CSSAttributeConditionImpl { - /** - * Creates a new CSSAttributeCondition object. - */ - public CSSOneOfAttributeConditionImpl(String localName, - String namespaceURI, boolean specified, String value) { - super(localName, namespaceURI, specified, value); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_ONE_OF_ATTRIBUTE_CONDITION; - } - - /** - * Tests whether this condition matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - String attr = e.getAttribute(getLocalName()); - String val = getValue(); - for (StringTokenizer tok = new StringTokenizer(attr); tok.hasMoreElements();) { - String candidate = tok.nextToken(); - if (val.equals(candidate)) { - return true; - } - } - return false; - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - return "[" + getLocalName() + "~=\"" + getValue() + "\"]"; - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSPseudoClassConditionImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSPseudoClassConditionImpl.java deleted file mode 100644 index 1c459d6637b..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSPseudoClassConditionImpl.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; -import org.w3c.dom.Element; - -/** - * This class provides an implementation of the - * {@link org.w3c.css.sac.AttributeCondition} interface. - */ -public class CSSPseudoClassConditionImpl extends AbstractAttributeCondition { - /** - * The namespaceURI. - */ - protected String namespaceURI; - - /** - * Creates a new CSSAttributeCondition object. - */ - public CSSPseudoClassConditionImpl(String namespaceURI, String value) { - super(value); - this.namespaceURI = namespaceURI; - } - - /** - * Indicates whether some other object is "equal to" this one. - * - * @param obj - * the reference object with which to compare. - */ - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) { - return false; - } - CSSPseudoClassConditionImpl c = (CSSPseudoClassConditionImpl) obj; - return c.namespaceURI.equals(namespaceURI); - } - - /** - * equal objects should have equal hashCodes. - * - * @return hashCode of this CSSPseudoClassCondition - */ - @Override - public int hashCode() { - return namespaceURI.hashCode(); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Condition#getConditionType()}. - */ - @Override - public short getConditionType() { - return SAC_PSEUDO_CLASS_CONDITION; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getNamespaceURI()}. - */ - @Override - public String getNamespaceURI() { - return namespaceURI; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getLocalName()}. - */ - @Override - public String getLocalName() { - return null; - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.AttributeCondition#getSpecified()}. - */ - @Override - public boolean getSpecified() { - return false; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - if (pseudoE != null && !pseudoE.equals(getValue())) { - // pseudo instance is filled, it is not valid. - return false; - } - if (!(e instanceof CSSStylableElement element)) { - return false; - } - boolean isPseudoInstanceOf = element.isPseudoInstanceOf(getValue()); - if (!isPseudoInstanceOf) { - return false; - } - if (pseudoE == null) { - // pseudo element is not filled. - // test if this CSSPseudoClassCondition is NOT a static pseudo - // instance - return (!element.isStaticPseudoInstance(getValue())); - } - return true; - } - - /** - * Fills the given set with the attribute names found in this selector. - */ - @Override - public void fillAttributeSet(Set attrSet) { - } - - /** - * Returns a text representation of this object. - */ - @Override - public String toString() { - return ":" + getValue(); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSPseudoElementSelectorImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSPseudoElementSelectorImpl.java deleted file mode 100644 index 5353e2c4885..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSPseudoElementSelectorImpl.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.dom.Element; - -/** - * This class implements the {@link org.w3c.css.sac.ElementSelector} interface. - */ -public class CSSPseudoElementSelectorImpl extends AbstractElementSelector { - - /** - * Creates a new CSSPseudoElementSelector object. - */ - public CSSPseudoElementSelectorImpl(String uri, String name) { - super(uri, name); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.Selector#getSelectorType()}. - */ - @Override - public short getSelectorType() { - return SAC_PSEUDO_ELEMENT_SELECTOR; - } - - /** - * Tests whether this selector matches the given element. - */ - @Override - public boolean match(Element e, String pseudoE) { - return getLocalName().equalsIgnoreCase(pseudoE); - } - - /** - * Returns the specificity of this selector. - */ - @Override - public int getSpecificity() { - return 0; - } - - /** - * Returns a representation of the selector. - */ - @Override - public String toString() { - return ":" + getLocalName(); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSSelectorFactoryImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSSelectorFactoryImpl.java deleted file mode 100644 index 00370115317..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSSelectorFactoryImpl.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - - Copyright 2002, 2014 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import org.w3c.css.sac.CSSException; -import org.w3c.css.sac.CharacterDataSelector; -import org.w3c.css.sac.Condition; -import org.w3c.css.sac.ConditionalSelector; -import org.w3c.css.sac.DescendantSelector; -import org.w3c.css.sac.ElementSelector; -import org.w3c.css.sac.NegativeSelector; -import org.w3c.css.sac.ProcessingInstructionSelector; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorFactory; -import org.w3c.css.sac.SiblingSelector; -import org.w3c.css.sac.SimpleSelector; - -/** - * This class implements the {@link org.w3c.css.sac.SelectorFactory} interface. - */ -public class CSSSelectorFactoryImpl implements SelectorFactory { - - private static final String NOT_IMPLEMENTED_IN_CSS2 = "Not implemented in CSS2"; //$NON-NLS-1$ - - /** - * The instance of this class. - */ - public static final SelectorFactory INSTANCE = new CSSSelectorFactoryImpl(); - - /** - * This class does not need to be instantiated. - */ - protected CSSSelectorFactoryImpl() { - } - - /** - * SAC: Implements {@link - * SelectorFactory#createConditionalSelector(SimpleSelector,Condition)}. - */ - @Override - public ConditionalSelector createConditionalSelector( - SimpleSelector selector, Condition condition) throws CSSException { - return new CSSConditionalSelectorImpl(selector, condition); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createAnyNodeSelector()}. - */ - @Override - public SimpleSelector createAnyNodeSelector() throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createRootNodeSelector()}. - */ - @Override - public SimpleSelector createRootNodeSelector() throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createNegativeSelector(SimpleSelector)}. - */ - @Override - public NegativeSelector createNegativeSelector(SimpleSelector selector) - throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createElementSelector(String,String)}. - */ - @Override - public ElementSelector createElementSelector(String namespaceURI, - String tagName) throws CSSException { - return new CSSElementSelectorImpl(namespaceURI, tagName); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createTextNodeSelector(String)}. - */ - @Override - public CharacterDataSelector createTextNodeSelector(String data) - throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createCDataSectionSelector(String)}. - */ - @Override - public CharacterDataSelector createCDataSectionSelector(String data) - throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * SelectorFactory#createProcessingInstructionSelector(String,String)}. - */ - @Override - public ProcessingInstructionSelector createProcessingInstructionSelector( - String target, String data) throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * org.w3c.css.sac.SelectorFactory#createCommentSelector(String)}. - */ - @Override - public CharacterDataSelector createCommentSelector(String data) - throws CSSException { - throw new CSSException(NOT_IMPLEMENTED_IN_CSS2); - } - - /** - * SAC: Implements {@link - * SelectorFactory#createPseudoElementSelector(String,String)}. - */ - @Override - public ElementSelector createPseudoElementSelector(String namespaceURI, - String pseudoName) throws CSSException { - return new CSSPseudoElementSelectorImpl(namespaceURI, pseudoName); - } - - /** - * SAC: Implements {@link - * SelectorFactory#createDescendantSelector(Selector,SimpleSelector)}. - */ - @Override - public DescendantSelector createDescendantSelector(Selector parent, - SimpleSelector descendant) throws CSSException { - return new CSSDescendantSelectorImpl(parent, descendant); - } - - /** - * SAC: Implements {@link - * SelectorFactory#createChildSelector(Selector,SimpleSelector)}. - */ - @Override - public DescendantSelector createChildSelector(Selector parent, - SimpleSelector child) throws CSSException { - return new CSSChildSelectorImpl(parent, child); - } - - /** - * SAC: Implements {@link - * SelectorFactory#createDirectAdjacentSelector(short,Selector,SimpleSelector)}. - */ - @Override - public SiblingSelector createDirectAdjacentSelector(short nodeType, - Selector child, SimpleSelector directAdjacent) throws CSSException { - return new CSSDirectAdjacentSelectorImpl(nodeType, child, - directAdjacent); - } -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/ExtendedCondition.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/ExtendedCondition.java deleted file mode 100644 index edc785b6760..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/ExtendedCondition.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Condition; -import org.w3c.dom.Element; - -/** - * This interface provides additional features to the - * {@link org.w3c.css.sac.Condition} interface. - */ -public interface ExtendedCondition extends Condition { - - /** - * Tests whether this condition matches the given element. - */ - boolean match(Element e, String pseudoE); - - /** - * Returns the specificity of this condition. - */ - int getSpecificity(); - - /** - * Fills the given set with the attribute names found in this selector. - */ - void fillAttributeSet(Set attrSet); -} diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/ExtendedSelector.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/ExtendedSelector.java deleted file mode 100644 index b30db5d0db1..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/ExtendedSelector.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - - Copyright 2002, 2015 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - */ - -/* This class copied from org.apache.batik.css.engine.sac */ - -package org.eclipse.e4.ui.css.core.impl.sac; - -import java.util.Set; -import org.w3c.css.sac.Selector; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * This interface extends the {@link org.w3c.css.sac.Selector}. - */ -public interface ExtendedSelector extends Selector { - - default boolean match(Element e, Node[] ancestors, int parentIndex, String pseudoE) { - return match(e, pseudoE); - } - - /** - * Tests whether this selector matches the given element. - */ - boolean match(Element e, String pseudoE); - - /** - * Returns the specificity of this selector. - */ - int getSpecificity(); - - /** - * Fills the given set with the attribute names found in this selector. - */ - void fillAttributeSet(Set attrSet); -} diff --git a/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/engine/CSSSWTEngineImpl.java b/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/engine/CSSSWTEngineImpl.java index 8bfc22e01c4..7adcce44634 100644 --- a/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/engine/CSSSWTEngineImpl.java +++ b/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/engine/CSSSWTEngineImpl.java @@ -139,17 +139,22 @@ private boolean isApplicableToReset(WidgetElement element) { @Override public void reapply() { - Shell[] shells = display.getShells(); - for (Shell s : shells) { - try { - s.setRedraw(false); - s.reskin(SWT.ALL); - applyStyles(s, true); - } catch (Exception e) { - ILog.of(getClass()).error(e.getMessage(), e); - } finally { - s.setRedraw(true); + startStylingSession(); + try { + Shell[] shells = display.getShells(); + for (Shell s : shells) { + try { + s.setRedraw(false); + s.reskin(SWT.ALL); + applyStyles(s, true); + } catch (Exception e) { + ILog.of(getClass()).error(e.getMessage(), e); + } finally { + s.setRedraw(true); + } } + } finally { + stopStylingSession(); } } } diff --git a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SelectorMatcherTest.java b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SelectorMatcherTest.java new file mode 100644 index 00000000000..31162dd52c7 --- /dev/null +++ b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/selector/SelectorMatcherTest.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2026 Lars Vogel and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lars Vogel - initial API and implementation + *******************************************************************************/ +package org.eclipse.e4.ui.css.core.impl.engine.selector; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.eclipse.e4.ui.css.core.impl.engine.CSSEngineImpl; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Adjacent; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.And; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeBeginHyphen; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeIncludes; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.AttributeSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Child; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.ClassSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Descendant; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.ElementType; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.IdSelector; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.PseudoClass; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.SelectorList; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Universal; +import org.eclipse.e4.ui.tests.css.core.util.TestElement; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link SelectorMatcher}. The cases mirror those in the + * Phase 1 {@code CSSEngineTest}, but go through the new internal selector + * AST instead of SAC. When Phase 3 Step 1 wires the engine to use this + * matcher, the SAC-based duplicate tests can be retired. + */ +class SelectorMatcherTest { + + private static final TestCSSEngine ENGINE = new TestCSSEngine(); + + private static final class TestCSSEngine extends CSSEngineImpl { + @Override + public void reapply() { + } + } + + private static TestElement element(String tag, String cssClass, String id) { + TestElement e = new TestElement(tag, ENGINE); + if (cssClass != null) { + e.setClass(cssClass); + } + if (id != null) { + e.setId(id); + } + return e; + } + + @Test + void universalMatchesAnything() { + assertTrue(SelectorMatcher.matches(new Universal(), element("Button", null, null), null)); + assertTrue(SelectorMatcher.matches(new Universal(), element("Label", "x", "y"), null)); + } + + @Test + void typeSelectorIsCaseSensitive() { + assertTrue(SelectorMatcher.matches(new ElementType("Button"), element("Button", null, null), null)); + assertFalse(SelectorMatcher.matches(new ElementType("Button"), element("button", null, null), null)); + assertFalse(SelectorMatcher.matches(new ElementType("Button"), element("Label", null, null), null)); + } + + @Test + void classSelector() { + assertTrue(SelectorMatcher.matches(new ClassSelector("foo"), element("Button", "foo", null), null)); + assertFalse(SelectorMatcher.matches(new ClassSelector("foo"), element("Button", "bar", null), null)); + assertFalse(SelectorMatcher.matches(new ClassSelector("foo"), element("Button", null, null), null)); + } + + @Test + void classSelectorMatchesOneOfMultipleClasses() { + assertTrue(SelectorMatcher.matches(new ClassSelector("foo"), element("Button", "foo bar", null), null)); + assertTrue(SelectorMatcher.matches(new ClassSelector("bar"), element("Button", "foo bar", null), null)); + assertFalse(SelectorMatcher.matches(new ClassSelector("baz"), element("Button", "foo bar", null), null)); + } + + @Test + void idSelector() { + assertTrue(SelectorMatcher.matches(new IdSelector("go"), element("Button", null, "go"), null)); + assertFalse(SelectorMatcher.matches(new IdSelector("go"), element("Button", null, "stop"), null)); + assertFalse(SelectorMatcher.matches(new IdSelector("go"), element("Button", null, null), null)); + } + + @Test + void compoundSelector() { + Selectors.Selector selector = new And(new And(new ElementType("Button"), new ClassSelector("primary")), + new IdSelector("go")); + assertTrue(SelectorMatcher.matches(selector, element("Button", "primary", "go"), null)); + assertFalse(SelectorMatcher.matches(selector, element("Label", "primary", "go"), null)); + assertFalse(SelectorMatcher.matches(selector, element("Button", "secondary", "go"), null)); + assertFalse(SelectorMatcher.matches(selector, element("Button", "primary", "stop"), null)); + } + + @Test + void descendantCombinator() { + Selectors.Selector selector = new Descendant(new ElementType("Composite"), new ElementType("Button")); + TestElement composite = element("Composite", null, null); + TestElement intermediate = new TestElement("Group", composite, ENGINE); + TestElement button = new TestElement("Button", intermediate, ENGINE); + assertTrue(SelectorMatcher.matches(selector, button, null)); + + TestElement orphan = element("Button", null, null); + assertFalse(SelectorMatcher.matches(selector, orphan, null)); + } + + @Test + void childCombinator() { + Selectors.Selector selector = new Child(new ElementType("Composite"), new ElementType("Button")); + TestElement composite = element("Composite", null, null); + TestElement direct = new TestElement("Button", composite, ENGINE); + assertTrue(SelectorMatcher.matches(selector, direct, null)); + + TestElement intermediate = new TestElement("Group", composite, ENGINE); + TestElement grandchild = new TestElement("Button", intermediate, ENGINE); + assertFalse(SelectorMatcher.matches(selector, grandchild, null)); + } + + @Test + void attributePresentMatchesEvenWithEmptyValue() { + AttributeSelector selector = new AttributeSelector("style", null); + TestElement withAttr = element("Button", null, null); + withAttr.setAttribute("style", "SWT.PUSH"); + assertTrue(SelectorMatcher.matches(selector, withAttr, null)); + assertFalse(SelectorMatcher.matches(selector, element("Button", null, null), null)); + } + + @Test + void attributeIncludesIsWordBoundaryMatch() { + AttributeIncludes selector = new AttributeIncludes("style", "SWT.CHECK"); + TestElement match = element("Button", null, null); + match.setAttribute("style", "SWT.CHECK SWT.BORDER"); + assertTrue(SelectorMatcher.matches(selector, match, null)); + + TestElement substring = element("Button", null, null); + substring.setAttribute("style", "SWT.CHECK_DELAYED"); + // 'CHECK' is a substring of 'CHECK_DELAYED' but not a whitespace-separated word. + assertFalse(SelectorMatcher.matches(new AttributeIncludes("style", "CHECK"), substring, null)); + } + + @Test + void attributeBeginHyphen() { + AttributeBeginHyphen selector = new AttributeBeginHyphen("lang", "en"); + TestElement exact = element("p", null, null); + exact.setAttribute("lang", "en"); + TestElement prefixed = element("p", null, null); + prefixed.setAttribute("lang", "en-US"); + TestElement other = element("p", null, null); + other.setAttribute("lang", "fr"); + assertTrue(SelectorMatcher.matches(selector, exact, null)); + assertTrue(SelectorMatcher.matches(selector, prefixed, null)); + assertFalse(SelectorMatcher.matches(selector, other, null)); + } + + @Test + void pseudoClassMatchesViaIsPseudoInstanceOf() { + PseudoClass selector = new PseudoClass("selected"); + TestElement on = new TestElement("Button", ENGINE) { + @Override + public boolean isPseudoInstanceOf(String s) { + return "selected".equals(s); + } + }; + TestElement off = element("Button", null, null); + assertTrue(SelectorMatcher.matches(selector, on, null)); + assertFalse(SelectorMatcher.matches(selector, off, null)); + } + + @Test + void selectorListMatchesAnyAlternative() { + SelectorList list = new SelectorList(List.of(new ClassSelector("a"), new ClassSelector("b"))); + assertTrue(SelectorMatcher.matches(list, element("Button", "a", null), null)); + assertTrue(SelectorMatcher.matches(list, element("Button", "b", null), null)); + assertFalse(SelectorMatcher.matches(list, element("Button", "c", null), null)); + } + + @Test + void specificityMatchesCss21() { + assertEquals(0, new Universal().specificity()); + assertEquals(1, new ElementType("Button").specificity()); + assertEquals(10, new ClassSelector("foo").specificity()); + assertEquals(100, new IdSelector("go").specificity()); + assertEquals(11, new And(new ElementType("Button"), new ClassSelector("primary")).specificity()); + assertEquals(111, new And(new And(new ElementType("Button"), new ClassSelector("primary")), + new IdSelector("go")).specificity()); + } + + @Test + void specificityOfSelectorListIsMaxOverAlternatives() { + // "Button, .foo, #go": max specificity is the id (100). + SelectorList list = new SelectorList( + List.of(new ElementType("Button"), new ClassSelector("foo"), new IdSelector("go"))); + assertEquals(100, list.specificity()); + } + + @Test + void adjacentSiblingCombinatorRequiresSiblingSupport() { + // TestElement's ElementAdapter base returns null from getPreviousSibling, + // so adjacent matching cannot succeed against it. Locks in that the + // matcher returns false rather than throwing on elements without + // sibling support. + Adjacent selector = new Adjacent(new ElementType("Label"), new ElementType("Button")); + TestElement parent = element("Composite", null, null); + new TestElement("Label", parent, ENGINE); + TestElement second = new TestElement("Button", parent, ENGINE); + assertFalse(SelectorMatcher.matches(selector, second, null)); + } +} diff --git a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CSSEngineTest.java b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CSSEngineTest.java index fa16ea5395e..31916477fd6 100644 --- a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CSSEngineTest.java +++ b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CSSEngineTest.java @@ -23,10 +23,10 @@ import org.eclipse.e4.ui.css.core.engine.CSSEngine; import org.eclipse.e4.ui.css.core.impl.engine.CSSEngineImpl; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors.Selector; import org.eclipse.e4.ui.tests.css.core.util.TestElement; import org.junit.jupiter.api.Test; -import org.w3c.css.sac.Selector; -import org.w3c.css.sac.SelectorList; import org.w3c.dom.Element; class CSSEngineTest { @@ -55,7 +55,7 @@ private static Selector parse(CSSEngine engine, String selector) throws Exceptio @Test void testSelectorMatch() throws Exception { TestCSSEngine engine = new TestCSSEngine(); - SelectorList list = engine.parseSelectors("Date"); + Selectors.SelectorList list = engine.parseSelectors("Date"); engine.setElementProvider((element, engine1) -> new TestElement(element.getClass().getSimpleName(), engine1)); assertFalse(engine.matches(list.item(0), new Object(), null)); @@ -249,7 +249,7 @@ void testNegativeMatch() throws Exception { @Test void testSelectorListMatch() throws Exception { TestCSSEngine engine = new TestCSSEngine(); - SelectorList list = engine.parseSelectors(".a, .b"); + Selectors.SelectorList list = engine.parseSelectors(".a, .b"); TestElement a = createElement(engine, "Button", "a", null); TestElement b = createElement(engine, "Button", "b", null); TestElement c = createElement(engine, "Button", "c", null); @@ -274,9 +274,9 @@ void testTagNameCaseSensitivity() throws Exception { assertFalse(engine.matches(lower, capitalElement, null)); } - private static boolean matchesAny(CSSEngine engine, SelectorList list, Element element) { - for (int i = 0; i < list.getLength(); i++) { - if (engine.matches(list.item(i), element, null)) { + private static boolean matchesAny(CSSEngine engine, Selectors.SelectorList list, Element element) { + for (Selector selector : list.alternatives()) { + if (engine.matches(selector, element, null)) { return true; } } diff --git a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/parser/SelectorTest.java b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/parser/SelectorTest.java index f3419a83eb0..43a3be1899b 100644 --- a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/parser/SelectorTest.java +++ b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/parser/SelectorTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2014 IBM Corporation and others. + * Copyright (c) 2013, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -21,11 +21,11 @@ import java.io.IOException; import org.eclipse.e4.ui.css.core.engine.CSSEngine; +import org.eclipse.e4.ui.css.core.impl.engine.selector.Selectors; import org.eclipse.e4.ui.tests.css.core.util.ParserTestUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.w3c.css.sac.CSSParseException; -import org.w3c.css.sac.SelectorList; public class SelectorTest { private CSSEngine engine; @@ -37,35 +37,37 @@ public void setUp() throws Exception { @Test void testSimpleSelector() throws Exception { - SelectorList list = engine.parseSelectors("Type1"); + Selectors.SelectorList list = engine.parseSelectors("Type1"); assertNotNull(list); assertEquals(1, list.getLength()); - assertEquals("Type1", list.item(0).toString()); + assertEquals("Type1", list.item(0).text()); } @Test void testMultipleSelectors() throws Exception { - SelectorList list = engine.parseSelectors("Type1, Type2"); + Selectors.SelectorList list = engine.parseSelectors("Type1, Type2"); assertNotNull(list); assertEquals(2, list.getLength()); - assertEquals("Type1", list.item(0).toString()); - assertEquals("Type2", list.item(1).toString()); + assertEquals("Type1", list.item(0).text()); + assertEquals("Type2", list.item(1).text()); } @Test void testClassSelector() throws Exception { - SelectorList list = engine.parseSelectors(".Class1"); + Selectors.SelectorList list = engine.parseSelectors(".Class1"); assertNotNull(list); assertEquals(1, list.getLength()); - assertEquals("*[class=\"Class1\"]", list.item(0).toString()); + assertEquals(".Class1", list.item(0).text()); } @Test void testAttributeSelector() throws Exception { - SelectorList list = engine.parseSelectors("*[class='Class1']"); + Selectors.SelectorList list = engine.parseSelectors("*[class='Class1']"); assertNotNull(list); assertEquals(1, list.getLength()); - assertEquals("*[class=\"Class1\"]", list.item(0).toString()); + // The Universal selector ('*') is folded away since the AttributeSelector + // alone carries the full match condition. + assertEquals("[class='Class1']", list.item(0).text()); } @Test