From 9b24ad6ff4407b0693c21439434b7677414bea50 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Thu, 7 May 2026 07:47:09 +0200 Subject: [PATCH] Merge AbstractCSSEngine into CSSEngineImpl The CSS core engine had two stacked abstract classes with no concrete core implementation: AbstractCSSEngine (1,113 LOC) and a tiny CSSEngineImpl (95 LOC) that only added parser-factory wiring, property-handler registration helpers, and the boolean value converter. Inline the small subclass into the base, keep the name CSSEngineImpl since that is the type SWT engine subclasses and tests already reference, and make makeCSSParser concrete (it was abstract solely so CSSEngineImpl could supply its single implementation). The class remains abstract because the CSSEngine.reapply() method has no sensible default in the core bundle. Update ParserTestUtil's parseCssWithoutImports cast and rename AbstractCSSEngineTest to CSSEngineImplTest in the same pass to keep test class names aligned with production class names. The test's anonymous subclass no longer needs to override makeCSSParser since it is now concrete on the base. All bundles internal (x-friends only); no API surface changed. Contributes to #3980 --- .../core/impl/engine/AbstractCSSEngine.java | 1122 ----------------- .../css/core/impl/engine/CSSEngineImpl.java | 1113 +++++++++++++++- ...EngineTest.java => CSSEngineImplTest.java} | 12 +- .../ui/tests/css/core/CssCoreTestSuite.java | 4 +- .../tests/css/core/util/ParserTestUtil.java | 4 +- 5 files changed, 1102 insertions(+), 1153 deletions(-) delete mode 100644 bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/AbstractCSSEngine.java rename tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/{AbstractCSSEngineTest.java => CSSEngineImplTest.java} (84%) diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/AbstractCSSEngine.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/AbstractCSSEngine.java deleted file mode 100644 index 66823482a9c..00000000000 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/engine/AbstractCSSEngine.java +++ /dev/null @@ -1,1122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008, 2020 Angelo Zerr 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: - * Angelo Zerr - initial API and implementation - * IBM Corporation - ongoing development - * Red Hat Inc. (mistria) - Fixes suggested by FindBugs - * Red Hat Inc. (mistria) - Bug 413348: fix stream leak - * Lars Vogel - Bug 428715 - * Brian de Alwis (MTI) - Performance tweaks (Bug 430829) - * Dirk Fauth - Bug 479896 - * Patrik Suzzi - Bug 500402 - * Daniel Raap - Bug 511836 - *******************************************************************************/ -package org.eclipse.e4.ui.css.core.impl.engine; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.BiConsumer; -import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.IPath; -import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; -import org.eclipse.e4.ui.css.core.dom.ChildVisibilityAwareElement; -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.dom.IElementProvider; -import org.eclipse.e4.ui.css.core.dom.IStreamingNodeList; -import org.eclipse.e4.ui.css.core.dom.parsers.CSSParser; -import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyCompositeHandler; -import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler; -import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler2; -import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler2Delegate; -import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandlerProvider; -import org.eclipse.e4.ui.css.core.dom.properties.converters.ICSSValueConverter; -import org.eclipse.e4.ui.css.core.engine.CSSElementContext; -import org.eclipse.e4.ui.css.core.engine.CSSEngine; -import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler; -import org.eclipse.e4.ui.css.core.exceptions.UnsupportedPropertyException; -import org.eclipse.e4.ui.css.core.impl.dom.CSSRuleListImpl; -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.ExtendedSelector; -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.ConditionalSelector; -import org.w3c.css.sac.DescendantSelector; -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; -import org.w3c.dom.css.CSSImportRule; -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.CSSValue; -import org.w3c.dom.css.DocumentCSS; -import org.w3c.dom.css.ViewCSS; -import org.w3c.dom.stylesheets.StyleSheet; - -/** - * Abstract CSS Engine manage style sheet parsing and store the - * {@link CSSStyleSheet} into {@link DocumentCSS}. - * - * To apply styles, call the {@link #applyStyles(Object, boolean, boolean)} - * method. This method check if {@link ICSSPropertyHandler} is registered for - * apply the CSS property. - * - * @version 1.0.0 - * @author Angelo ZERR - */ -public abstract class AbstractCSSEngine implements CSSEngine { - - /** - * Archives are deliberately identified by exclamation mark in URLs - */ - private static final String ARCHIVE_IDENTIFIER = "!"; - - /** - * Default {@link IResourcesLocatorManager} used to get InputStream, Reader - * resource like Image. - */ - private static final IResourcesLocatorManager defaultResourcesLocatorManager = ResourcesLocatorManager.INSTANCE; - - /** - * w3c {@link DocumentCSS}. - */ - private final ExtendedDocumentCSS documentCSS; - - /** - * w3c {@link ViewCSS}. - */ - private final ViewCSS viewCSS; - - /** - * {@link IElementProvider} used to retrieve w3c Element linked to the - * widget. - */ - private IElementProvider elementProvider; - - protected boolean computeDefaultStyle = false; - - private Map elementsContext = null; - - /** - * CSS Error Handler to intercept error while parsing, applying styles. - */ - private CSSErrorHandler errorHandler; - - private IResourcesLocatorManager resourcesLocatorManager; - - private IResourcesRegistry resourcesRegistry; - - /** - * An ordered list of ICSSPropertyHandlerProvider - */ - protected List propertyHandlerProviders = new ArrayList<>(); - // for performance hold a map of handlers to singleton list - private final Map> propertyHandler2InstanceMap = new HashMap<>(); - - private Map currentCSSPropertiesApplied; - - private boolean throwError; - - private Map valueConverters = null; - - private int parseImport; - - private ResourceRegistryKeyFactory keyFactory; - - public AbstractCSSEngine() { - this(new DocumentCSSImpl()); - } - - public AbstractCSSEngine(ExtendedDocumentCSS documentCSS) { - this.documentCSS = documentCSS; - this.viewCSS = new ViewCSSImpl(documentCSS); - keyFactory = new ResourceRegistryKeyFactory(); - } - - /*--------------- Parse style sheet -----------------*/ - - @Override - public StyleSheet parseStyleSheet(Reader reader) throws IOException { - InputSource source = new InputSource(); - source.setCharacterStream(reader); - return parseStyleSheet(source); - } - - @Override - public StyleSheet parseStyleSheet(InputStream stream) throws IOException { - InputSource source = new InputSource(); - source.setByteStream(stream); - return parseStyleSheet(source); - } - - @Override - public StyleSheet parseStyleSheet(InputSource source) throws IOException { - // Check that CharacterStream or ByteStream is not null - checkInputSource(source); - CSSParser parser = makeCSSParser(); - CSSStyleSheet styleSheet = parser.parseStyleSheet(source); - - CSSRuleList rules = styleSheet.getCssRules(); - int length = rules.getLength(); - CSSRuleListImpl masterList = new CSSRuleListImpl(); - int counter; - for (counter = 0; counter < length; counter++) { - CSSRule rule = rules.item(counter); - if (rule.getType() != CSSRule.IMPORT_RULE) { - break; - } - // processing an import CSS - CSSImportRule importRule = (CSSImportRule) rule; - URL url = null; - if (importRule.getHref().startsWith("platform")) { - url = FileLocator.resolve(new URL(importRule.getHref())); - } else { - IPath p = IPath.fromOSString(source.getURI()); - IPath trim = p.removeLastSegments(1); - boolean isArchive = source.getURI().contains(ARCHIVE_IDENTIFIER); - url = FileLocator - .resolve(new URL(trim.addTrailingSeparator().toString() + ((CSSImportRule) rule).getHref())); - File testFile = new File(url.getFile()); - if (!isArchive&&!testFile.exists()) { - // look in platform default - String path = getResourcesLocatorManager().resolve((importRule).getHref()); - testFile = new File(new URL(path).getFile()); - if (testFile.exists()) { - url = new URL(path); - } - } - } - try (InputStream stream = url.openStream()) { - InputSource tempStream = new InputSource(); - tempStream.setURI(url.toString()); - tempStream.setByteStream(stream); - parseImport++; - try { - styleSheet = (CSSStyleSheet) this.parseStyleSheet(tempStream); - } finally { - parseImport--; - } - CSSRuleList tempRules = styleSheet.getCssRules(); - for (int j = 0; j < tempRules.getLength(); j++) { - masterList.add(tempRules.item(j)); - } - } - } - - // add remaining non import rules - for (int i = counter; i < length; i++) { - masterList.add(rules.item(i)); - } - - // final stylesheet - CSSStyleSheetImpl s = new CSSStyleSheetImpl(); - s.setRuleList(masterList); - if (parseImport == 0) { - documentCSS.addStyleSheet(s); - } - return s; - } - - private void processNodeList(NodeList nodes, BiConsumer consumer, boolean applyStylesToChildNodes) { - if (nodes instanceof IStreamingNodeList) { - ((IStreamingNodeList) nodes).stream().forEach(child -> { - consumer.accept(child, applyStylesToChildNodes); - }); - } else { - int length = nodes.getLength(); - for (int k = 0; k < length; k++) { - consumer.accept(nodes.item(k), applyStylesToChildNodes); - } - } - } - - /** - * Return true if source is valid and false otherwise. - */ - private void checkInputSource(InputSource source) throws IOException { - Reader reader = source.getCharacterStream(); - InputStream stream = source.getByteStream(); - if (reader == null && stream == null) { - throw new IOException( - "CharacterStream or ByteStream cannot be null for the InputSource."); - } - } - - /*--------------- Parse style declaration -----------------*/ - - @Override - public CSSStyleDeclaration parseStyleDeclaration(String style) { - try { - return parseStyleDeclaration(new StringReader(style)); - } catch (IOException e) { - throw new IllegalStateException("StringReader cannot throw IOException", e); //$NON-NLS-1$ - } - } - - @Override - public CSSStyleDeclaration parseStyleDeclaration(Reader reader) throws IOException { - InputSource source = new InputSource(); - source.setCharacterStream(reader); - return parseStyleDeclaration(source); - } - - @Override - public CSSStyleDeclaration parseStyleDeclaration(InputStream stream) throws IOException { - InputSource source = new InputSource(); - source.setByteStream(stream); - return parseStyleDeclaration(source); - } - - @Override - public CSSStyleDeclaration parseStyleDeclaration(InputSource source) throws IOException { - checkInputSource(source); - CSSParser parser = makeCSSParser(); - return parser.parseStyleDeclaration(source); - } - - /*--------------- Parse CSS Selector -----------------*/ - - @Override - public SelectorList parseSelectors(String selector) { - try { - return parseSelectors(new StringReader(selector)); - } catch (IOException e) { - throw new IllegalStateException("StringReader cannot throw IOException", e); //$NON-NLS-1$ - } - } - - @Override - public SelectorList parseSelectors(Reader reader) throws IOException { - InputSource source = new InputSource(); - source.setCharacterStream(reader); - return parseSelectors(source); - } - - @Override - public SelectorList parseSelectors(InputStream stream) throws IOException { - InputSource source = new InputSource(); - source.setByteStream(stream); - return parseSelectors(source); - } - - @Override - public SelectorList parseSelectors(InputSource source) throws IOException { - checkInputSource(source); - CSSParser parser = makeCSSParser(); - return parser.parseSelectors(source); - } - - /*--------------- Parse CSS Property Value-----------------*/ - - @Override - public CSSValue parsePropertyValue(Reader reader) throws IOException { - InputSource source = new InputSource(); - source.setCharacterStream(reader); - return parsePropertyValue(source); - } - - @Override - public CSSValue parsePropertyValue(InputStream stream) throws IOException { - InputSource source = new InputSource(); - source.setByteStream(stream); - return parsePropertyValue(source); - } - - @Override - public CSSValue parsePropertyValue(String value) { - try { - return parsePropertyValue(new StringReader(value)); - } catch (IOException e) { - throw new IllegalStateException("StringReader cannot throw IOException", e); //$NON-NLS-1$ - } - } - - @Override - public CSSValue parsePropertyValue(InputSource source) throws IOException { - checkInputSource(source); - CSSParser parser = makeCSSParser(); - return parser.parsePropertyValue(source); - } - - /*--------------- Apply styles -----------------*/ - - @Override - public void applyStyles(Object element, boolean applyStylesToChildNodes) { - applyStyles(element, applyStylesToChildNodes, computeDefaultStyle); - } - - @Override - public void applyStyles(Object element, boolean applyStylesToChildNodes, boolean computeDefaultStyle) { - Element elt = getElement(element); - if (elt == null || !isVisible(elt)) { - return; - } - - /* - * Compute new Style to apply. - */ - CSSStyleDeclaration style = viewCSS.getComputedStyle(elt, null); - if (computeDefaultStyle) { - if (applyStylesToChildNodes) { - this.computeDefaultStyle = computeDefaultStyle; - } - /* - * Apply default style. - */ - applyDefaultStyleDeclaration(element, false, style, null); - } - - /* - * Manage static pseudo instances - */ - String[] pseudoInstances = getStaticPseudoInstances(elt); - if (pseudoInstances != null && pseudoInstances.length > 0) { - // there are static pseudo instances defined, loop for it and - // apply styles for each pseudo instance. - for (String pseudoInstance : pseudoInstances) { - CSSStyleDeclaration styleWithPseudoInstance = viewCSS.getComputedStyle(elt, pseudoInstance); - if (computeDefaultStyle) { - /* - * Apply default style for the current pseudo instance. - */ - applyDefaultStyleDeclaration(element, false, styleWithPseudoInstance, pseudoInstance); - } - - if (styleWithPseudoInstance != null) { - CSSRule parentRule = styleWithPseudoInstance.getParentRule(); - if (parentRule instanceof ExtendedCSSRule) { - applyConditionalPseudoStyle((ExtendedCSSRule) parentRule, pseudoInstance, element, styleWithPseudoInstance); - } else { - applyStyleDeclaration(elt, styleWithPseudoInstance, pseudoInstance); - } - } - } - } - - if (style != null) { - applyStyleDeclaration(elt, style, null); - } - try { - // Apply inline style - applyInlineStyle(elt, false); - } catch (Exception e) { - handleExceptions(e); - } - - if (applyStylesToChildNodes) { - /* - * Style all children recursive. - */ - NodeList nodes = elt instanceof ChildVisibilityAwareElement c - ? c.getVisibleChildNodes() - : elt.getChildNodes(); - if (nodes != null) { - processNodeList(nodes, this::applyStyles, applyStylesToChildNodes); - onStylesAppliedToChildNodes(elt, nodes); - } - } - } - - /** - * Allow the CSS engine to skip particular elements if they are not visible. - * Elements need to be restyled when they become visible. - * - * @return true if the element is visible, false if not visible. - */ - protected boolean isVisible(Element elt) { - Node parentNode = elt.getParentNode(); - if (parentNode instanceof ChildVisibilityAwareElement) { - NodeList l = ((ChildVisibilityAwareElement) parentNode).getVisibleChildNodes(); - if (l != null) { - if (l instanceof IStreamingNodeList) { - return ((IStreamingNodeList) l).stream().anyMatch(node -> node == elt); - } else { - int length = l.getLength(); - for (int i = 0; i < length; i++) { - if (l.item(i) == elt) { - return true; - } - } - } - } - return false; - } - 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; - } - } - } - } - } - - protected String[] getStaticPseudoInstances(Element element) { - if (element instanceof CSSStylableElement stylableElement) { - return stylableElement.getStaticPseudoInstances(); - } - return null; - } - - /** - * Callback method called when styles applied of nodes - * children of the element. - */ - protected void onStylesAppliedToChildNodes(Element element, NodeList nodes) { - if (element instanceof CSSStylableElement) { - ((CSSStylableElement) element).onStylesApplied(nodes); - } - } - - /*--------------- Apply style declaration -----------------*/ - - @Override - public void applyStyleDeclaration(Object element, CSSStyleDeclaration style, String pseudo) { - // Apply style - boolean avoidanceCacheInstalled = currentCSSPropertiesApplied == null; - if (avoidanceCacheInstalled) { - currentCSSPropertiesApplied = new HashMap<>(); - } - List handlers2 = Collections.emptyList(); - for (int i = 0; i < style.getLength(); i++) { - String property = style.item(i); - CSSValue value = style.getPropertyCSSValue(property); - try { - ICSSPropertyHandler handler = this.applyCSSProperty(element, property, value, pseudo); - ICSSPropertyHandler2 propertyHandler2 = null; - if (handler instanceof ICSSPropertyHandler2) { - propertyHandler2 = (ICSSPropertyHandler2) handler; - } else if (handler instanceof ICSSPropertyHandler2Delegate) { - propertyHandler2 = ((ICSSPropertyHandler2Delegate) handler).getCSSPropertyHandler2(); - } - if (propertyHandler2 != null) { - switch (handlers2.size()) { - case 0: - handlers2 = propertyHandler2InstanceMap.computeIfAbsent(propertyHandler2, - Collections::singletonList); - break; - case 1: - handlers2 = new ArrayList<>(handlers2); - handlers2.add(propertyHandler2); - break; - default: - if (!handlers2.contains(propertyHandler2)) { - handlers2.add(propertyHandler2); - } - } - } - } catch (Exception e) { - if (throwError || (!throwError && !(e instanceof UnsupportedPropertyException))) { - handleExceptions(e); - } - } - } - for (ICSSPropertyHandler2 handler2 : handlers2) { - try { - handler2.onAllCSSPropertiesApplyed(element, this, pseudo); - } catch (Exception e) { - handleExceptions(e); - } - } - if (avoidanceCacheInstalled) { - currentCSSPropertiesApplied = null; - } - - } - - @Override - public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, - Reader reader) throws IOException { - CSSStyleDeclaration style = parseStyleDeclaration(reader); - this.applyStyleDeclaration(node, style, null); - return style; - } - - @Override - public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, InputStream stream) throws IOException { - CSSStyleDeclaration style = parseStyleDeclaration(stream); - this.applyStyleDeclaration(node, style, null); - return style; - } - - @Override - public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, InputSource source) throws IOException { - CSSStyleDeclaration style = parseStyleDeclaration(source); - this.applyStyleDeclaration(node, style, null); - return style; - } - - @Override - public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, String style) throws IOException { - CSSStyleDeclaration styleDeclaration = parseStyleDeclaration(style); - this.applyStyleDeclaration(node, styleDeclaration, null); - return styleDeclaration; - } - - /*--------------- Apply inline style -----------------*/ - - @Override - public void applyInlineStyle(Object node, boolean applyStylesToChildNodes) { - Element elt = getElement(node); - if (elt != null) { - if (elt instanceof CSSStylableElement stylableElement) { - String style = stylableElement.getCSSStyle(); - if (style != null && style.length() > 0) { - try { - parseAndApplyStyleDeclaration(stylableElement.getNativeWidget(), style); - } catch (IOException e) { - handleExceptions(e); - } - } - } - if (applyStylesToChildNodes) { - /* - * Style all children recursive. - */ - NodeList nodes = elt.getChildNodes(); - if (nodes != null) { - processNodeList(nodes, this::applyInlineStyle, applyStylesToChildNodes); - } - } - } - } - - /*--------------- Initial Style -----------------*/ - - @Override - public CSSStyleDeclaration getDefaultStyleDeclaration(Object element, String pseudoE) { - return getDefaultStyleDeclaration(element, null, pseudoE); - } - - public CSSStyleDeclaration getDefaultStyleDeclaration(Object widget, CSSStyleDeclaration newStyle, String pseudoE) { - CSSStyleDeclaration style = null; - for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { - try { - style = provider.getDefaultCSSStyleDeclaration(this, widget, newStyle, pseudoE); - } catch (Exception e) { - handleExceptions(e); - } - } - return style; - } - - @Override - public void applyDefaultStyleDeclaration(Object element, boolean applyStylesToChildNodes) { - applyDefaultStyleDeclaration(element, applyStylesToChildNodes, null, null); - } - - public void applyDefaultStyleDeclaration(Object element, boolean applyStylesToChildNodes, - CSSStyleDeclaration newStyle, String pseudoE) { - // Initial styles must be computed or applied - Element elt = getElement(element); - if (elt != null) { - if (elt instanceof CSSStylableElement stylableElement) { - CSSStyleDeclaration oldDefaultStyleDeclaration = stylableElement.getDefaultStyleDeclaration(pseudoE); - CSSStyleDeclaration defaultStyleDeclaration = getDefaultStyleDeclaration( - element, newStyle, pseudoE); - if (oldDefaultStyleDeclaration != null) { - // Second apply styles, apply the initial style - // before apply the new style - try { - throwError = false; - applyStyleDeclaration(element, defaultStyleDeclaration, pseudoE); - } finally { - throwError = true; - } - } - } - if (applyStylesToChildNodes) { - /* - * Style all children recursive. - */ - NodeList nodes = elt.getChildNodes(); - if (nodes != null) { - processNodeList(nodes, this::applyDefaultStyleDeclaration, applyStylesToChildNodes); - onStylesAppliedToChildNodes(elt, nodes); - } - } - } - } - - /** - * Delegates the handle method. - * - * @param element - * may be a widget or a node or some object - */ - @Override - public ICSSPropertyHandler applyCSSProperty(Object element, String property, CSSValue value, String pseudo) - throws Exception { - if (currentCSSPropertiesApplied != null && currentCSSPropertiesApplied.containsKey(property)) { - // CSS Property was already applied, ignore it. - return null; - } - - element = getElement(element); // in case we're passed a node - if ("inherit".equals(value.getCssText())) { - // go to parent node - Element actualElement = (Element) element; - Node parentNode = actualElement.getParentNode(); - // get CSS property value - String parentValueString = retrieveCSSProperty(parentNode, property, pseudo); - // and convert it to a CSS value, overriding the "inherit" setting - // with the parent value - value = parsePropertyValue(parentValueString); - } - - for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { - Collection handlers = provider.getCSSPropertyHandlers(element, property); - if (handlers == null) { - continue; - } - for (ICSSPropertyHandler handler : handlers) { - try { - boolean result = handler.applyCSSProperty(element, property, value, pseudo, this); - if (result) { - // Add CSS Property to flag that this CSS Property was - // applied. - if (currentCSSPropertiesApplied != null) { - currentCSSPropertiesApplied.put(property, property); - } - return handler; - } - } catch (Exception e) { - if (throwError || (!throwError && !(e instanceof UnsupportedPropertyException))) { - handleExceptions(e); - } - } - } - } - - return null; - } - - @Override - public String retrieveCSSProperty(Object element, String property, String pseudo) { - try { - element = getElement(element); // in case we're passed a node - for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { - Collection handlers = provider.getCSSPropertyHandlers(element, property); - if (handlers == null) { - continue; - } - for (ICSSPropertyHandler handler : handlers) { - String value = handler.retrieveCSSProperty(element, property, pseudo, this); - if (!StringUtils.isEmpty(value)) { - return value; - } - } - } - } catch (Exception e) { - handleExceptions(e); - } - return null; - } - - @Override - public String[] getCSSCompositePropertiesNames(String property) { - try { - Collection handlers = getCSSPropertyHandlers(property); - if (handlers == null) { - return null; - } - for (ICSSPropertyHandler handler : handlers) { - if (handler instanceof ICSSPropertyCompositeHandler compositeHandler) { - if (compositeHandler.isCSSPropertyComposite(property)) { - return compositeHandler.getCSSPropertiesNames(property); - } - } - } - } catch (Exception e) { - handleExceptions(e); - } - return null; - } - - protected Collection getCSSPropertyHandlers(String property) throws Exception { - Collection handlers = new ArrayList<>(); - for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { - Collection h = provider.getCSSPropertyHandlers(property); - if (handlers == null) { - handlers = h; - } else { - handlers = new ArrayList<>(handlers); - handlers.addAll(h); - } - } - return handlers; - } - - /** - * Return the set of property names and handlers for the provided node. - * - * @return the property names and handlers - */ - @Override - public Collection getCSSProperties(Object element) { - Set properties = new HashSet<>(); - for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { - properties.addAll(provider.getCSSProperties(element)); - } - return properties; - } - - /*--------------- Dynamic pseudo classes -----------------*/ - - @Override - public IElementProvider getElementProvider() { - return elementProvider; - } - - @Override - public void setElementProvider(IElementProvider elementProvider) { - this.elementProvider = elementProvider; - } - - /** - * Return the w3c Element linked to the Object element. - */ - @Override - public Element getElement(Object element) { - Element elt = null; - if (element == null) { - return elt; - } - CSSElementContext elementContext = getCSSElementContext(element); - if (elementContext != null) { - if (!elementContext.elementMustBeRefreshed(elementProvider)) { - return elementContext.getElement(); - } - } - if (element instanceof Element) { - elt = (Element) element; - } else if (elementProvider != null) { - elt = elementProvider.getElement(element, this); - } - if (elt != null) { - if (elementContext == null) { - elementContext = new CSSElementContextImpl(); - Object nativeWidget = getNativeWidget(element); - hookNativeWidget(nativeWidget); - getElementsContext().put(nativeWidget, elementContext); - } - elementContext.setElementProvider(elementProvider); - elementContext.setElement(elt); - if (elt instanceof CSSStylableElement) { - // Initialize CSS stylable element - ((CSSStylableElement)elt).initialize(); - } - - } - return elt; - } - - /** - * Called when an element context is created for a native widget and - * registered with this engine. Subclasses should override and install - * a listener on the widget that will call {@link #handleWidgetDisposed(Object)} - * when the widget is disposed. - *

- * The default implementation of this method does nothing. - *

- * - * @param widget the native widget to hook - */ - protected void hookNativeWidget(Object widget) { - } - - /** - * Called when a widget is disposed. Removes the element context - * from the element contexts map and the widgets map. Overriding - * classes must call the super implementation. - */ - @Override - public void handleWidgetDisposed(Object widget) { - if (elementsContext != null) { - elementsContext.remove(widget); - } - } - - @Override - public CSSElementContext getCSSElementContext(Object element) { - Object o = getNativeWidget(element); - return getElementsContext().get(o); - } - - public Object getNativeWidget(Object element) { - Object o = element; - if (element instanceof CSSStylableElement) { - o = ((CSSStylableElement) o).getNativeWidget(); - } - return o; - } - - protected Map getElementsContext() { - if (elementsContext == null) { - elementsContext = new HashMap<>(); - } - return elementsContext; - } - - @Override - public boolean matches(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... - } - return false; - } - - /*--------------- Error Handler -----------------*/ - - /** - * Handle exceptions thrown while parsing, applying styles. By default this - * method call CSS Error Handler if it is initialized. - */ - @Override - public void handleExceptions(Exception e) { - if (errorHandler != null) { - errorHandler.error(e); - } - } - - @Override - public CSSErrorHandler getErrorHandler() { - return errorHandler; - } - - /** - * Set the CSS Error Handler to manage exception. - */ - @Override - public void setErrorHandler(CSSErrorHandler errorHandler) { - this.errorHandler = errorHandler; - } - - /*--------------- Resources Locator Manager -----------------*/ - - @Override - public IResourcesLocatorManager getResourcesLocatorManager() { - if (resourcesLocatorManager == null) { - return defaultResourcesLocatorManager; - } - return resourcesLocatorManager; - } - - @Override - public void setResourcesLocatorManager( - IResourcesLocatorManager resourcesLocatorManager) { - this.resourcesLocatorManager = resourcesLocatorManager; - } - - /*--------------- Document/View CSS -----------------*/ - - @Override - public DocumentCSS getDocumentCSS() { - return documentCSS; - } - - @Override - public ViewCSS getViewCSS() { - return viewCSS; - } - - @Override - public void dispose() { - reset(); - // Call dispose for each CSSStylableElement which was registered - Collection contexts = elementsContext.values(); - for (CSSElementContext context : contexts) { - Element element = context.getElement(); - if (element instanceof CSSStylableElement) { - ((CSSStylableElement) element).dispose(); - } - } - // FIXME: should dispose element provider and the property handler - // providers - elementsContext = null; - if (resourcesRegistry != null) { - resourcesRegistry.dispose(); - } - } - - @Override - public void reset() { - // Remove All Style Sheets - documentCSS.removeAllStyleSheets(); - } - - /*--------------- Resources Registry -----------------*/ - - @Override - public IResourcesRegistry getResourcesRegistry() { - return resourcesRegistry; - } - - @Override - public void setResourcesRegistry(IResourcesRegistry resourcesRegistry) { - this.resourcesRegistry = resourcesRegistry; - } - - public void registerCSSPropertyHandlerProvider(ICSSPropertyHandlerProvider handlerProvider) { - propertyHandlerProviders.add(handlerProvider); - } - - public void unregisterCSSPropertyHandlerProvider(ICSSPropertyHandlerProvider handlerProvider) { - propertyHandlerProviders.remove(handlerProvider); - } - - /*--------------- CSS Value Converter -----------------*/ - - @Override - public void registerCSSValueConverter(ICSSValueConverter converter) { - if (valueConverters == null) { - valueConverters = new HashMap<>(); - } - valueConverters.put(converter.getToType(), converter); - } - - @Override - public void unregisterCSSValueConverter(ICSSValueConverter converter) { - if (valueConverters == null) { - return; - } - valueConverters.remove(converter); - } - - @Override - public ICSSValueConverter getCSSValueConverter(Object toType) { - if (valueConverters != null) { - return valueConverters.get(toType); - } - return null; - } - - @Override - public Object convert(CSSValue value, Object toType, Object context) throws Exception { - if ("unset".equals(value.getCssText())) { - return null; - } - Object key = keyFactory.createKey(value); - Object newValue = getResource(toType, key); - - if (newValue == null) { - ICSSValueConverter converter = getCSSValueConverter(toType); - if (converter != null) { - newValue = converter.convert(value, this, context); - // cache it - registerResource(toType, key, newValue); - } - } - return newValue; - } - - private Object getResource(Object toType, Object key) { - if (key != null && getResourcesRegistry() != null) { - return getResourcesRegistry().getResource(toType, key); - } - return null; - } - - private void registerResource(Object toType, Object key, Object resource) { - if (key != null && resource != null && getResourcesRegistry() != null) { - getResourcesRegistry().registerResource(toType, key, resource); - } - } - - @Override - public String convert(Object value, Object toType, Object context) - throws Exception { - if (value == null) { - return null; - } - ICSSValueConverter converter = getCSSValueConverter(toType); - if (converter != null) { - return converter.convert(value, this, context); - } - return null; - } - - /*--------------- Abstract methods -----------------*/ - - /** - * Return instance of CSS Parser. - */ - public abstract CSSParser makeCSSParser(); - - protected void setResourceRegistryKeyFactory(ResourceRegistryKeyFactory keyFactory) { - this.keyFactory = keyFactory; - } -} 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 a463e82452d..bfa459895e9 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 Angelo Zerr and others. + * Copyright (c) 2008, 2020 Angelo Zerr and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -10,56 +10,1130 @@ * * Contributors: * Angelo Zerr - initial API and implementation - * Brian de Alwis (MTI) - move out registry-specific element provisioning + * IBM Corporation - ongoing development + * Red Hat Inc. (mistria) - Fixes suggested by FindBugs + * Red Hat Inc. (mistria) - Bug 413348: fix stream leak + * Lars Vogel - Bug 428715 + * Brian de Alwis (MTI) - Performance tweaks (Bug 430829) + * Dirk Fauth - Bug 479896 + * Patrik Suzzi - Bug 500402 + * Daniel Raap - Bug 511836 *******************************************************************************/ package org.eclipse.e4.ui.css.core.impl.engine; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IPath; +import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; +import org.eclipse.e4.ui.css.core.dom.ChildVisibilityAwareElement; +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.dom.IElementProvider; +import org.eclipse.e4.ui.css.core.dom.IStreamingNodeList; import org.eclipse.e4.ui.css.core.dom.parsers.CSSParser; import org.eclipse.e4.ui.css.core.dom.parsers.CSSParserFactory; import org.eclipse.e4.ui.css.core.dom.parsers.ICSSParserFactory; +import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyCompositeHandler; import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler; +import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler2; +import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler2Delegate; +import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandlerProvider; import org.eclipse.e4.ui.css.core.dom.properties.converters.CSSValueBooleanConverterImpl; +import org.eclipse.e4.ui.css.core.dom.properties.converters.ICSSValueConverter; import org.eclipse.e4.ui.css.core.dom.properties.providers.CSSPropertyHandlerLazyProviderImpl; import org.eclipse.e4.ui.css.core.dom.properties.providers.CSSPropertyHandlerSimpleProviderImpl; +import org.eclipse.e4.ui.css.core.engine.CSSElementContext; +import org.eclipse.e4.ui.css.core.engine.CSSEngine; +import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler; +import org.eclipse.e4.ui.css.core.exceptions.UnsupportedPropertyException; +import org.eclipse.e4.ui.css.core.impl.dom.CSSRuleListImpl; +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.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.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; +import org.w3c.dom.css.CSSImportRule; +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.CSSValue; +import org.w3c.dom.css.DocumentCSS; +import org.w3c.dom.css.ViewCSS; +import org.w3c.dom.stylesheets.StyleSheet; -public abstract class CSSEngineImpl extends AbstractCSSEngine { +/** + * Abstract CSS Engine manage style sheet parsing and store the + * {@link CSSStyleSheet} into {@link DocumentCSS}. + * + * To apply styles, call the {@link #applyStyles(Object, boolean, boolean)} + * method. This method check if {@link ICSSPropertyHandler} is registered for + * apply the CSS property. + * + * @version 1.0.0 + * @author Angelo ZERR + */ +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 + */ + private static final String ARCHIVE_IDENTIFIER = "!"; + + /** + * Default {@link IResourcesLocatorManager} used to get InputStream, Reader + * resource like Image. + */ + private static final IResourcesLocatorManager defaultResourcesLocatorManager = ResourcesLocatorManager.INSTANCE; + + /** + * w3c {@link DocumentCSS}. + */ + private final ExtendedDocumentCSS documentCSS; + + /** + * w3c {@link ViewCSS}. + */ + private final ViewCSS viewCSS; + + /** + * {@link IElementProvider} used to retrieve w3c Element linked to the + * widget. + */ + private IElementProvider elementProvider; + + protected boolean computeDefaultStyle = false; + + private Map elementsContext = null; + + /** + * CSS Error Handler to intercept error while parsing, applying styles. + */ + private CSSErrorHandler errorHandler; + + private IResourcesLocatorManager resourcesLocatorManager; + + private IResourcesRegistry resourcesRegistry; + + /** + * An ordered list of ICSSPropertyHandlerProvider + */ + protected List propertyHandlerProviders = new ArrayList<>(); + // for performance hold a map of handlers to singleton list + private final Map> propertyHandler2InstanceMap = new HashMap<>(); + + private Map currentCSSPropertiesApplied; + + private boolean throwError; + + private Map valueConverters = null; + + private int parseImport; + + private ResourceRegistryKeyFactory keyFactory; + private CSSPropertyHandlerSimpleProviderImpl handlerProvider; private CSSPropertyHandlerLazyProviderImpl lazyHandlerProvider; public CSSEngineImpl() { - super(); - - // Register SWT Boolean CSSValue Converter - super.registerCSSValueConverter(CSSValueBooleanConverterImpl.INSTANCE); + this(new DocumentCSSImpl()); } public CSSEngineImpl(ExtendedDocumentCSS documentCSS) { - super(documentCSS); - // Register SWT Boolean CSSValue Converter - super.registerCSSValueConverter(CSSValueBooleanConverterImpl.INSTANCE); + this.documentCSS = documentCSS; + this.viewCSS = new ViewCSSImpl(documentCSS); + keyFactory = new ResourceRegistryKeyFactory(); + registerCSSValueConverter(CSSValueBooleanConverterImpl.INSTANCE); + } + + /*--------------- Parse style sheet -----------------*/ + + @Override + public StyleSheet parseStyleSheet(Reader reader) throws IOException { + InputSource source = new InputSource(); + source.setCharacterStream(reader); + return parseStyleSheet(source); + } + + @Override + public StyleSheet parseStyleSheet(InputStream stream) throws IOException { + InputSource source = new InputSource(); + source.setByteStream(stream); + return parseStyleSheet(source); + } + + @Override + public StyleSheet parseStyleSheet(InputSource source) throws IOException { + // Check that CharacterStream or ByteStream is not null + checkInputSource(source); + CSSParser parser = makeCSSParser(); + CSSStyleSheet styleSheet = parser.parseStyleSheet(source); + + CSSRuleList rules = styleSheet.getCssRules(); + int length = rules.getLength(); + CSSRuleListImpl masterList = new CSSRuleListImpl(); + int counter; + for (counter = 0; counter < length; counter++) { + CSSRule rule = rules.item(counter); + if (rule.getType() != CSSRule.IMPORT_RULE) { + break; + } + // processing an import CSS + CSSImportRule importRule = (CSSImportRule) rule; + URL url = null; + if (importRule.getHref().startsWith("platform")) { + url = FileLocator.resolve(new URL(importRule.getHref())); + } else { + IPath p = IPath.fromOSString(source.getURI()); + IPath trim = p.removeLastSegments(1); + boolean isArchive = source.getURI().contains(ARCHIVE_IDENTIFIER); + url = FileLocator + .resolve(new URL(trim.addTrailingSeparator().toString() + ((CSSImportRule) rule).getHref())); + File testFile = new File(url.getFile()); + if (!isArchive&&!testFile.exists()) { + // look in platform default + String path = getResourcesLocatorManager().resolve((importRule).getHref()); + testFile = new File(new URL(path).getFile()); + if (testFile.exists()) { + url = new URL(path); + } + } + } + try (InputStream stream = url.openStream()) { + InputSource tempStream = new InputSource(); + tempStream.setURI(url.toString()); + tempStream.setByteStream(stream); + parseImport++; + try { + styleSheet = (CSSStyleSheet) this.parseStyleSheet(tempStream); + } finally { + parseImport--; + } + CSSRuleList tempRules = styleSheet.getCssRules(); + for (int j = 0; j < tempRules.getLength(); j++) { + masterList.add(tempRules.item(j)); + } + } + } + + // add remaining non import rules + for (int i = counter; i < length; i++) { + masterList.add(rules.item(i)); + } + + // final stylesheet + CSSStyleSheetImpl s = new CSSStyleSheetImpl(); + s.setRuleList(masterList); + if (parseImport == 0) { + documentCSS.addStyleSheet(s); + } + return s; + } + + private void processNodeList(NodeList nodes, BiConsumer consumer, boolean applyStylesToChildNodes) { + if (nodes instanceof IStreamingNodeList) { + ((IStreamingNodeList) nodes).stream().forEach(child -> { + consumer.accept(child, applyStylesToChildNodes); + }); + } else { + int length = nodes.getLength(); + for (int k = 0; k < length; k++) { + consumer.accept(nodes.item(k), applyStylesToChildNodes); + } + } + } + + /** + * Return true if source is valid and false otherwise. + */ + private void checkInputSource(InputSource source) throws IOException { + Reader reader = source.getCharacterStream(); + InputStream stream = source.getByteStream(); + if (reader == null && stream == null) { + throw new IOException( + "CharacterStream or ByteStream cannot be null for the InputSource."); + } + } + + /*--------------- Parse style declaration -----------------*/ + + @Override + public CSSStyleDeclaration parseStyleDeclaration(String style) { + try { + return parseStyleDeclaration(new StringReader(style)); + } catch (IOException e) { + throw new IllegalStateException("StringReader cannot throw IOException", e); //$NON-NLS-1$ + } + } + + @Override + public CSSStyleDeclaration parseStyleDeclaration(Reader reader) throws IOException { + InputSource source = new InputSource(); + source.setCharacterStream(reader); + return parseStyleDeclaration(source); + } + + @Override + public CSSStyleDeclaration parseStyleDeclaration(InputStream stream) throws IOException { + InputSource source = new InputSource(); + source.setByteStream(stream); + return parseStyleDeclaration(source); + } + + @Override + public CSSStyleDeclaration parseStyleDeclaration(InputSource source) throws IOException { + checkInputSource(source); + CSSParser parser = makeCSSParser(); + return parser.parseStyleDeclaration(source); + } + + /*--------------- Parse CSS Selector -----------------*/ + + @Override + public SelectorList parseSelectors(String selector) { + try { + return parseSelectors(new StringReader(selector)); + } catch (IOException e) { + throw new IllegalStateException("StringReader cannot throw IOException", e); //$NON-NLS-1$ + } + } + + @Override + public SelectorList parseSelectors(Reader reader) throws IOException { + InputSource source = new InputSource(); + source.setCharacterStream(reader); + return parseSelectors(source); + } + + @Override + public SelectorList parseSelectors(InputStream stream) throws IOException { + InputSource source = new InputSource(); + source.setByteStream(stream); + return parseSelectors(source); + } + + @Override + public SelectorList parseSelectors(InputSource source) throws IOException { + checkInputSource(source); + CSSParser parser = makeCSSParser(); + return parser.parseSelectors(source); + } + + /*--------------- Parse CSS Property Value-----------------*/ + + @Override + public CSSValue parsePropertyValue(Reader reader) throws IOException { + InputSource source = new InputSource(); + source.setCharacterStream(reader); + return parsePropertyValue(source); } @Override + public CSSValue parsePropertyValue(InputStream stream) throws IOException { + InputSource source = new InputSource(); + source.setByteStream(stream); + return parsePropertyValue(source); + } + + @Override + public CSSValue parsePropertyValue(String value) { + try { + return parsePropertyValue(new StringReader(value)); + } catch (IOException e) { + throw new IllegalStateException("StringReader cannot throw IOException", e); //$NON-NLS-1$ + } + } + + @Override + public CSSValue parsePropertyValue(InputSource source) throws IOException { + checkInputSource(source); + CSSParser parser = makeCSSParser(); + return parser.parsePropertyValue(source); + } + + /*--------------- Apply styles -----------------*/ + + @Override + public void applyStyles(Object element, boolean applyStylesToChildNodes) { + applyStyles(element, applyStylesToChildNodes, computeDefaultStyle); + } + + @Override + public void applyStyles(Object element, boolean applyStylesToChildNodes, boolean computeDefaultStyle) { + Element elt = getElement(element); + if (elt == null || !isVisible(elt)) { + return; + } + + /* + * Compute new Style to apply. + */ + CSSStyleDeclaration style = viewCSS.getComputedStyle(elt, null); + if (computeDefaultStyle) { + if (applyStylesToChildNodes) { + this.computeDefaultStyle = computeDefaultStyle; + } + /* + * Apply default style. + */ + applyDefaultStyleDeclaration(element, false, style, null); + } + + /* + * Manage static pseudo instances + */ + String[] pseudoInstances = getStaticPseudoInstances(elt); + if (pseudoInstances != null && pseudoInstances.length > 0) { + // there are static pseudo instances defined, loop for it and + // apply styles for each pseudo instance. + for (String pseudoInstance : pseudoInstances) { + CSSStyleDeclaration styleWithPseudoInstance = viewCSS.getComputedStyle(elt, pseudoInstance); + if (computeDefaultStyle) { + /* + * Apply default style for the current pseudo instance. + */ + applyDefaultStyleDeclaration(element, false, styleWithPseudoInstance, pseudoInstance); + } + + if (styleWithPseudoInstance != null) { + CSSRule parentRule = styleWithPseudoInstance.getParentRule(); + if (parentRule instanceof ExtendedCSSRule) { + applyConditionalPseudoStyle((ExtendedCSSRule) parentRule, pseudoInstance, element, styleWithPseudoInstance); + } else { + applyStyleDeclaration(elt, styleWithPseudoInstance, pseudoInstance); + } + } + } + } + + if (style != null) { + applyStyleDeclaration(elt, style, null); + } + try { + // Apply inline style + applyInlineStyle(elt, false); + } catch (Exception e) { + handleExceptions(e); + } + + if (applyStylesToChildNodes) { + /* + * Style all children recursive. + */ + NodeList nodes = elt instanceof ChildVisibilityAwareElement c + ? c.getVisibleChildNodes() + : elt.getChildNodes(); + if (nodes != null) { + processNodeList(nodes, this::applyStyles, applyStylesToChildNodes); + onStylesAppliedToChildNodes(elt, nodes); + } + } + } + + /** + * Allow the CSS engine to skip particular elements if they are not visible. + * Elements need to be restyled when they become visible. + * + * @return true if the element is visible, false if not visible. + */ + protected boolean isVisible(Element elt) { + Node parentNode = elt.getParentNode(); + if (parentNode instanceof ChildVisibilityAwareElement) { + NodeList l = ((ChildVisibilityAwareElement) parentNode).getVisibleChildNodes(); + if (l != null) { + if (l instanceof IStreamingNodeList) { + return ((IStreamingNodeList) l).stream().anyMatch(node -> node == elt); + } else { + int length = l.getLength(); + for (int i = 0; i < length; i++) { + if (l.item(i) == elt) { + return true; + } + } + } + } + return false; + } + 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; + } + } + } + } + } + + protected String[] getStaticPseudoInstances(Element element) { + if (element instanceof CSSStylableElement stylableElement) { + return stylableElement.getStaticPseudoInstances(); + } + return null; + } + + /** + * Callback method called when styles applied of nodes + * children of the element. + */ + protected void onStylesAppliedToChildNodes(Element element, NodeList nodes) { + if (element instanceof CSSStylableElement) { + ((CSSStylableElement) element).onStylesApplied(nodes); + } + } + + /*--------------- Apply style declaration -----------------*/ + + @Override + public void applyStyleDeclaration(Object element, CSSStyleDeclaration style, String pseudo) { + // Apply style + boolean avoidanceCacheInstalled = currentCSSPropertiesApplied == null; + if (avoidanceCacheInstalled) { + currentCSSPropertiesApplied = new HashMap<>(); + } + List handlers2 = Collections.emptyList(); + for (int i = 0; i < style.getLength(); i++) { + String property = style.item(i); + CSSValue value = style.getPropertyCSSValue(property); + try { + ICSSPropertyHandler handler = this.applyCSSProperty(element, property, value, pseudo); + ICSSPropertyHandler2 propertyHandler2 = null; + if (handler instanceof ICSSPropertyHandler2) { + propertyHandler2 = (ICSSPropertyHandler2) handler; + } else if (handler instanceof ICSSPropertyHandler2Delegate) { + propertyHandler2 = ((ICSSPropertyHandler2Delegate) handler).getCSSPropertyHandler2(); + } + if (propertyHandler2 != null) { + switch (handlers2.size()) { + case 0: + handlers2 = propertyHandler2InstanceMap.computeIfAbsent(propertyHandler2, + Collections::singletonList); + break; + case 1: + handlers2 = new ArrayList<>(handlers2); + handlers2.add(propertyHandler2); + break; + default: + if (!handlers2.contains(propertyHandler2)) { + handlers2.add(propertyHandler2); + } + } + } + } catch (Exception e) { + if (throwError || (!throwError && !(e instanceof UnsupportedPropertyException))) { + handleExceptions(e); + } + } + } + for (ICSSPropertyHandler2 handler2 : handlers2) { + try { + handler2.onAllCSSPropertiesApplyed(element, this, pseudo); + } catch (Exception e) { + handleExceptions(e); + } + } + if (avoidanceCacheInstalled) { + currentCSSPropertiesApplied = null; + } + + } + + @Override + public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, + Reader reader) throws IOException { + CSSStyleDeclaration style = parseStyleDeclaration(reader); + this.applyStyleDeclaration(node, style, null); + return style; + } + + @Override + public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, InputStream stream) throws IOException { + CSSStyleDeclaration style = parseStyleDeclaration(stream); + this.applyStyleDeclaration(node, style, null); + return style; + } + + @Override + public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, InputSource source) throws IOException { + CSSStyleDeclaration style = parseStyleDeclaration(source); + this.applyStyleDeclaration(node, style, null); + return style; + } + + @Override + public CSSStyleDeclaration parseAndApplyStyleDeclaration(Object node, String style) throws IOException { + CSSStyleDeclaration styleDeclaration = parseStyleDeclaration(style); + this.applyStyleDeclaration(node, styleDeclaration, null); + return styleDeclaration; + } + + /*--------------- Apply inline style -----------------*/ + + @Override + public void applyInlineStyle(Object node, boolean applyStylesToChildNodes) { + Element elt = getElement(node); + if (elt != null) { + if (elt instanceof CSSStylableElement stylableElement) { + String style = stylableElement.getCSSStyle(); + if (style != null && style.length() > 0) { + try { + parseAndApplyStyleDeclaration(stylableElement.getNativeWidget(), style); + } catch (IOException e) { + handleExceptions(e); + } + } + } + if (applyStylesToChildNodes) { + /* + * Style all children recursive. + */ + NodeList nodes = elt.getChildNodes(); + if (nodes != null) { + processNodeList(nodes, this::applyInlineStyle, applyStylesToChildNodes); + } + } + } + } + + /*--------------- Initial Style -----------------*/ + + @Override + public CSSStyleDeclaration getDefaultStyleDeclaration(Object element, String pseudoE) { + return getDefaultStyleDeclaration(element, null, pseudoE); + } + + public CSSStyleDeclaration getDefaultStyleDeclaration(Object widget, CSSStyleDeclaration newStyle, String pseudoE) { + CSSStyleDeclaration style = null; + for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { + try { + style = provider.getDefaultCSSStyleDeclaration(this, widget, newStyle, pseudoE); + } catch (Exception e) { + handleExceptions(e); + } + } + return style; + } + + @Override + public void applyDefaultStyleDeclaration(Object element, boolean applyStylesToChildNodes) { + applyDefaultStyleDeclaration(element, applyStylesToChildNodes, null, null); + } + + public void applyDefaultStyleDeclaration(Object element, boolean applyStylesToChildNodes, + CSSStyleDeclaration newStyle, String pseudoE) { + // Initial styles must be computed or applied + Element elt = getElement(element); + if (elt != null) { + if (elt instanceof CSSStylableElement stylableElement) { + CSSStyleDeclaration oldDefaultStyleDeclaration = stylableElement.getDefaultStyleDeclaration(pseudoE); + CSSStyleDeclaration defaultStyleDeclaration = getDefaultStyleDeclaration( + element, newStyle, pseudoE); + if (oldDefaultStyleDeclaration != null) { + // Second apply styles, apply the initial style + // before apply the new style + try { + throwError = false; + applyStyleDeclaration(element, defaultStyleDeclaration, pseudoE); + } finally { + throwError = true; + } + } + } + if (applyStylesToChildNodes) { + /* + * Style all children recursive. + */ + NodeList nodes = elt.getChildNodes(); + if (nodes != null) { + processNodeList(nodes, this::applyDefaultStyleDeclaration, applyStylesToChildNodes); + onStylesAppliedToChildNodes(elt, nodes); + } + } + } + } + + /** + * Delegates the handle method. + * + * @param element + * may be a widget or a node or some object + */ + @Override + public ICSSPropertyHandler applyCSSProperty(Object element, String property, CSSValue value, String pseudo) + throws Exception { + if (currentCSSPropertiesApplied != null && currentCSSPropertiesApplied.containsKey(property)) { + // CSS Property was already applied, ignore it. + return null; + } + + element = getElement(element); // in case we're passed a node + if ("inherit".equals(value.getCssText())) { + // go to parent node + Element actualElement = (Element) element; + Node parentNode = actualElement.getParentNode(); + // get CSS property value + String parentValueString = retrieveCSSProperty(parentNode, property, pseudo); + // and convert it to a CSS value, overriding the "inherit" setting + // with the parent value + value = parsePropertyValue(parentValueString); + } + + for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { + Collection handlers = provider.getCSSPropertyHandlers(element, property); + if (handlers == null) { + continue; + } + for (ICSSPropertyHandler handler : handlers) { + try { + boolean result = handler.applyCSSProperty(element, property, value, pseudo, this); + if (result) { + // Add CSS Property to flag that this CSS Property was + // applied. + if (currentCSSPropertiesApplied != null) { + currentCSSPropertiesApplied.put(property, property); + } + return handler; + } + } catch (Exception e) { + if (throwError || (!throwError && !(e instanceof UnsupportedPropertyException))) { + handleExceptions(e); + } + } + } + } + + return null; + } + + @Override + public String retrieveCSSProperty(Object element, String property, String pseudo) { + try { + element = getElement(element); // in case we're passed a node + for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { + Collection handlers = provider.getCSSPropertyHandlers(element, property); + if (handlers == null) { + continue; + } + for (ICSSPropertyHandler handler : handlers) { + String value = handler.retrieveCSSProperty(element, property, pseudo, this); + if (!StringUtils.isEmpty(value)) { + return value; + } + } + } + } catch (Exception e) { + handleExceptions(e); + } + return null; + } + + @Override + public String[] getCSSCompositePropertiesNames(String property) { + try { + Collection handlers = getCSSPropertyHandlers(property); + if (handlers == null) { + return null; + } + for (ICSSPropertyHandler handler : handlers) { + if (handler instanceof ICSSPropertyCompositeHandler compositeHandler) { + if (compositeHandler.isCSSPropertyComposite(property)) { + return compositeHandler.getCSSPropertiesNames(property); + } + } + } + } catch (Exception e) { + handleExceptions(e); + } + return null; + } + + protected Collection getCSSPropertyHandlers(String property) throws Exception { + Collection handlers = new ArrayList<>(); + for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { + Collection h = provider.getCSSPropertyHandlers(property); + if (handlers == null) { + handlers = h; + } else { + handlers = new ArrayList<>(handlers); + handlers.addAll(h); + } + } + return handlers; + } + + /** + * Return the set of property names and handlers for the provided node. + * + * @return the property names and handlers + */ + @Override + public Collection getCSSProperties(Object element) { + Set properties = new HashSet<>(); + for (ICSSPropertyHandlerProvider provider : propertyHandlerProviders) { + properties.addAll(provider.getCSSProperties(element)); + } + return properties; + } + + /*--------------- Dynamic pseudo classes -----------------*/ + + @Override + public IElementProvider getElementProvider() { + return elementProvider; + } + + @Override + public void setElementProvider(IElementProvider elementProvider) { + this.elementProvider = elementProvider; + } + + /** + * Return the w3c Element linked to the Object element. + */ + @Override + public Element getElement(Object element) { + Element elt = null; + if (element == null) { + return elt; + } + CSSElementContext elementContext = getCSSElementContext(element); + if (elementContext != null) { + if (!elementContext.elementMustBeRefreshed(elementProvider)) { + return elementContext.getElement(); + } + } + if (element instanceof Element) { + elt = (Element) element; + } else if (elementProvider != null) { + elt = elementProvider.getElement(element, this); + } + if (elt != null) { + if (elementContext == null) { + elementContext = new CSSElementContextImpl(); + Object nativeWidget = getNativeWidget(element); + hookNativeWidget(nativeWidget); + getElementsContext().put(nativeWidget, elementContext); + } + elementContext.setElementProvider(elementProvider); + elementContext.setElement(elt); + if (elt instanceof CSSStylableElement) { + // Initialize CSS stylable element + ((CSSStylableElement)elt).initialize(); + } + + } + return elt; + } + + /** + * Called when an element context is created for a native widget and + * registered with this engine. Subclasses should override and install + * a listener on the widget that will call {@link #handleWidgetDisposed(Object)} + * when the widget is disposed. + *

+ * The default implementation of this method does nothing. + *

+ * + * @param widget the native widget to hook + */ + protected void hookNativeWidget(Object widget) { + } + + /** + * Called when a widget is disposed. Removes the element context + * from the element contexts map and the widgets map. Overriding + * classes must call the super implementation. + */ + @Override + public void handleWidgetDisposed(Object widget) { + if (elementsContext != null) { + elementsContext.remove(widget); + } + } + + @Override + public CSSElementContext getCSSElementContext(Object element) { + Object o = getNativeWidget(element); + return getElementsContext().get(o); + } + + public Object getNativeWidget(Object element) { + Object o = element; + if (element instanceof CSSStylableElement) { + o = ((CSSStylableElement) o).getNativeWidget(); + } + return o; + } + + protected Map getElementsContext() { + if (elementsContext == null) { + elementsContext = new HashMap<>(); + } + return elementsContext; + } + + @Override + public boolean matches(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... + } + return false; + } + + /*--------------- Error Handler -----------------*/ + + /** + * Handle exceptions thrown while parsing, applying styles. By default this + * method call CSS Error Handler if it is initialized. + */ + @Override + public void handleExceptions(Exception e) { + if (errorHandler != null) { + errorHandler.error(e); + } + } + + @Override + public CSSErrorHandler getErrorHandler() { + return errorHandler; + } + + /** + * Set the CSS Error Handler to manage exception. + */ + @Override + public void setErrorHandler(CSSErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + /*--------------- Resources Locator Manager -----------------*/ + + @Override + public IResourcesLocatorManager getResourcesLocatorManager() { + if (resourcesLocatorManager == null) { + return defaultResourcesLocatorManager; + } + return resourcesLocatorManager; + } + + @Override + public void setResourcesLocatorManager( + IResourcesLocatorManager resourcesLocatorManager) { + this.resourcesLocatorManager = resourcesLocatorManager; + } + + /*--------------- Document/View CSS -----------------*/ + + @Override + public DocumentCSS getDocumentCSS() { + return documentCSS; + } + + @Override + public ViewCSS getViewCSS() { + return viewCSS; + } + + @Override + public void dispose() { + reset(); + // Call dispose for each CSSStylableElement which was registered + Collection contexts = elementsContext.values(); + for (CSSElementContext context : contexts) { + Element element = context.getElement(); + if (element instanceof CSSStylableElement) { + ((CSSStylableElement) element).dispose(); + } + } + // FIXME: should dispose element provider and the property handler + // providers + elementsContext = null; + if (resourcesRegistry != null) { + resourcesRegistry.dispose(); + } + } + + @Override + public void reset() { + // Remove All Style Sheets + documentCSS.removeAllStyleSheets(); + } + + /*--------------- Resources Registry -----------------*/ + + @Override + public IResourcesRegistry getResourcesRegistry() { + return resourcesRegistry; + } + + @Override + public void setResourcesRegistry(IResourcesRegistry resourcesRegistry) { + this.resourcesRegistry = resourcesRegistry; + } + + public void registerCSSPropertyHandlerProvider(ICSSPropertyHandlerProvider handlerProvider) { + propertyHandlerProviders.add(handlerProvider); + } + + public void unregisterCSSPropertyHandlerProvider(ICSSPropertyHandlerProvider handlerProvider) { + propertyHandlerProviders.remove(handlerProvider); + } + + /*--------------- CSS Value Converter -----------------*/ + + @Override + public void registerCSSValueConverter(ICSSValueConverter converter) { + if (valueConverters == null) { + valueConverters = new HashMap<>(); + } + valueConverters.put(converter.getToType(), converter); + } + + @Override + public void unregisterCSSValueConverter(ICSSValueConverter converter) { + if (valueConverters == null) { + return; + } + valueConverters.remove(converter); + } + + @Override + public ICSSValueConverter getCSSValueConverter(Object toType) { + if (valueConverters != null) { + return valueConverters.get(toType); + } + return null; + } + + @Override + public Object convert(CSSValue value, Object toType, Object context) throws Exception { + if ("unset".equals(value.getCssText())) { + return null; + } + Object key = keyFactory.createKey(value); + Object newValue = getResource(toType, key); + + if (newValue == null) { + ICSSValueConverter converter = getCSSValueConverter(toType); + if (converter != null) { + newValue = converter.convert(value, this, context); + // cache it + registerResource(toType, key, newValue); + } + } + return newValue; + } + + private Object getResource(Object toType, Object key) { + if (key != null && getResourcesRegistry() != null) { + return getResourcesRegistry().getResource(toType, key); + } + return null; + } + + private void registerResource(Object toType, Object key, Object resource) { + if (key != null && resource != null && getResourcesRegistry() != null) { + getResourcesRegistry().registerResource(toType, key, resource); + } + } + + @Override + public String convert(Object value, Object toType, Object context) + throws Exception { + if (value == null) { + return null; + } + ICSSValueConverter converter = getCSSValueConverter(toType); + if (converter != null) { + return converter.convert(value, this, context); + } + return null; + } + + /** + * Return instance of CSS Parser, configured with the Batik selector + * factory and the platform's class/id condition factory. + */ public CSSParser makeCSSParser() { - // Create CSS Parser ICSSParserFactory factory = CSSParserFactory.newInstance(); CSSParser parser = factory.makeCSSParser(); - - // Register Batik CSS Selector factory. parser.setSelectorFactory(CSSSelectorFactoryImpl.INSTANCE); - - // Register Custom CSS Condition factory. parser.setConditionFactory(CONDITIONFACTORY_INSTANCE); - return parser; } @@ -71,7 +1145,7 @@ public void registerCSSPropertyHandler(Class cl, ICSSPropertyHandler handler) private void initHandlerProviderIfNeed() { if (handlerProvider == null) { handlerProvider = new CSSPropertyHandlerSimpleProviderImpl(); - super.registerCSSPropertyHandlerProvider(handlerProvider); + registerCSSPropertyHandlerProvider(handlerProvider); } } @@ -83,7 +1157,7 @@ public void registerCSSProperty(String propertyName, Class { // throws NPE if parameter is null diff --git a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CssCoreTestSuite.java b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CssCoreTestSuite.java index 60911cc40ec..63b3ca7cd77 100644 --- a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CssCoreTestSuite.java +++ b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CssCoreTestSuite.java @@ -15,7 +15,7 @@ *******************************************************************************/ package org.eclipse.e4.ui.tests.css.core; -import org.eclipse.e4.ui.css.core.impl.engine.AbstractCSSEngineTest; +import org.eclipse.e4.ui.css.core.impl.engine.CSSEngineImplTest; import org.eclipse.e4.ui.tests.css.core.dom.CSSPropertyHandlerProviderTest; import org.eclipse.e4.ui.tests.css.core.parser.CascadeTest; import org.eclipse.e4.ui.tests.css.core.parser.FontFaceRulesTest; @@ -44,7 +44,7 @@ CSSEngineTest.class, ImportTest.class, InheritTest.class, - AbstractCSSEngineTest.class, + CSSEngineImplTest.class, CSSPropertyHandlerProviderTest.class }) @Suite diff --git a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/util/ParserTestUtil.java b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/util/ParserTestUtil.java index 21fd0fffcbc..e72b95fd186 100644 --- a/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/util/ParserTestUtil.java +++ b/tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/util/ParserTestUtil.java @@ -19,7 +19,7 @@ import org.eclipse.e4.ui.css.core.dom.parsers.CSSParser; import org.eclipse.e4.ui.css.core.engine.CSSEngine; import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler; -import org.eclipse.e4.ui.css.core.impl.engine.AbstractCSSEngine; +import org.eclipse.e4.ui.css.core.impl.engine.CSSEngineImpl; import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl; import org.eclipse.swt.widgets.Display; import org.w3c.css.sac.InputSource; @@ -51,7 +51,7 @@ public static CSSStyleSheet parseCss(String css) */ public static CSSStyleSheet parseCssWithoutImports(String css) throws IOException { - CSSParser parser = ((AbstractCSSEngine) createEngine()).makeCSSParser(); + CSSParser parser = ((CSSEngineImpl) createEngine()).makeCSSParser(); InputSource source = new InputSource(); source.setCharacterStream(new StringReader(css)); return parser.parseStyleSheet(source);