package ca.concordia.cssanalyser.parser.flute;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.w3c.css.sac.CSSException;
import org.w3c.css.sac.Condition;
import org.w3c.css.sac.ConditionalSelector;
import org.w3c.css.sac.DocumentHandler;
import org.w3c.css.sac.InputSource;
import org.w3c.css.sac.LexicalUnit;
import org.w3c.css.sac.Locator;
import org.w3c.css.sac.SACMediaList;
import org.w3c.css.sac.SelectorList;
import org.w3c.flute.parser.LexicalUnitImpl;
import org.w3c.flute.parser.selectors.AdjacentSelector;
import org.w3c.flute.parser.selectors.AndConditionImpl;
import org.w3c.flute.parser.selectors.AttributeConditionImpl;
import org.w3c.flute.parser.selectors.BeginHyphenAttributeConditionImpl;
import org.w3c.flute.parser.selectors.CaretCondition;
import org.w3c.flute.parser.selectors.ChildSelectorImpl;
import org.w3c.flute.parser.selectors.ClassConditionImpl;
import org.w3c.flute.parser.selectors.ConditionalSelectorImpl;
import org.w3c.flute.parser.selectors.ContainsCondition;
import org.w3c.flute.parser.selectors.DescendantSelectorImpl;
import org.w3c.flute.parser.selectors.DirectAdjacentSelectorImpl;
import org.w3c.flute.parser.selectors.ElementSelectorImpl;
import org.w3c.flute.parser.selectors.EndsWithCondition;
import org.w3c.flute.parser.selectors.FunctionPseudoClassCondition;
import org.w3c.flute.parser.selectors.IdConditionImpl;
import org.w3c.flute.parser.selectors.LangConditionImpl;
import org.w3c.flute.parser.selectors.NegativeConditionImpl;
import org.w3c.flute.parser.selectors.OneOfAttributeConditionImpl;
import org.w3c.flute.parser.selectors.PseudoClassConditionImpl;
import org.w3c.flute.parser.selectors.PseudoElementCondition;
import org.w3c.flute.parser.selectors.PseudoElementSelectorImpl;
import ca.concordia.cssanalyser.app.FileLogger;
import ca.concordia.cssanalyser.cssmodel.LocationInfo;
import ca.concordia.cssanalyser.cssmodel.StyleSheet;
import ca.concordia.cssanalyser.cssmodel.declaration.Declaration;
import ca.concordia.cssanalyser.cssmodel.declaration.DeclarationFactory;
import ca.concordia.cssanalyser.cssmodel.declaration.value.DeclarationEquivalentValue;
import ca.concordia.cssanalyser.cssmodel.declaration.value.DeclarationValue;
import ca.concordia.cssanalyser.cssmodel.declaration.value.DeclarationValueFactory;
import ca.concordia.cssanalyser.cssmodel.declaration.value.ValueType;
import ca.concordia.cssanalyser.cssmodel.media.MediaQueryList;
import ca.concordia.cssanalyser.cssmodel.selectors.AdjacentSiblingSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.BaseSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.ChildSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.Combinator;
import ca.concordia.cssanalyser.cssmodel.selectors.DescendantSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.GroupingSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.NegationPseudoClass;
import ca.concordia.cssanalyser.cssmodel.selectors.PseudoClass;
import ca.concordia.cssanalyser.cssmodel.selectors.PseudoElement;
import ca.concordia.cssanalyser.cssmodel.selectors.Selector;
import ca.concordia.cssanalyser.cssmodel.selectors.SiblingSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.SimpleSelector;
import ca.concordia.cssanalyser.cssmodel.selectors.conditions.SelectorCondition;
import ca.concordia.cssanalyser.cssmodel.selectors.conditions.SelectorConditionType;
public class CSSDocumentHandler implements DocumentHandler {
private static final Logger LOGGER = FileLogger.getLogger(CSSDocumentHandler.class);
private Selector currentSelector;
private Set<MediaQueryList> currentMediaQueryLists;
private StyleSheet styleSheet;
private int numberOfVisitedElements = 0;
public CSSDocumentHandler(StyleSheet styleSheet) {
this.styleSheet = styleSheet;
currentMediaQueryLists = new LinkedHashSet<>();
}
@Override
public void startDocument(InputSource arg0) throws CSSException {
}
@Override
public void endDocument(InputSource arg0) throws CSSException {
}
@Override
public void comment(String arg0) throws CSSException {
}
@Override
public void startFontFace() throws CSSException {
}
@Override
public void endFontFace() throws CSSException {
}
@Override
public void startPage(String arg0, String arg1) throws CSSException {
}
@Override
public void endPage(String arg0, String arg1) throws CSSException {
}
@Override
public void ignorableAtRule(String arg0) throws CSSException {
// the rules starting with @ which are ignorable
}
@Override
public void importStyle(String path, SACMediaList forMedia, String arg2)
throws CSSException {
}
public void importStyle(String path, MediaQueryList forMedia, String arg2) throws CSSException {
//According to CSS3 '@import' rules must occur before all rules other than '@charset' rule
File file = new File(styleSheet.getFilePath());
String parentFolder = file.getParent();
FluteCSSParser parser = new FluteCSSParser();
try {
StyleSheet importedStyleSheet = parser.parseExternalCSS(parentFolder + "/" + path);
importedStyleSheet.addMediaQueryList(forMedia);
styleSheet.addSelectors(importedStyleSheet);
} catch (Exception ex) {
LOGGER.warn("Couldn't parse or import " + parentFolder + "/" + path);
}
}
@Override
public void namespaceDeclaration(String arg0, String arg1) throws CSSException {
}
@Override
public void startMedia(SACMediaList mediaList) throws CSSException {
// if (currentMediaQueryList == null) {
// currentMediaQueryList = getMedia(mediaList);
// } else {
// MediaQueryList groupedMedia;
// if (currentMediaQueryList instanceof MediaQuery) {
// groupedMedia = new MediaQueryList();
// groupedMedia.addMedia((MediaQuery) currentMediaQueryList);
// } else {
// groupedMedia = (MediaQueryList)currentMediaQueryList;
// }
// Media tempMedia = getMedia(mediaList);
// if (tempMedia instanceof MediaQuery)
// groupedMedia.addMedia((MediaQuery)tempMedia);
// else
// groupedMedia.addAllMedia((MediaQueryList)tempMedia);
// currentMediaQueryList = groupedMedia;
// }
}
// Change these methods to accept media query list. also the parser
public void startMedia(MediaQueryList mediaQueryList) {
currentMediaQueryLists.add(mediaQueryList);
}
public void endMedia(MediaQueryList mediaQueryList) {
currentMediaQueryLists.remove(mediaQueryList);
}
// private Media getMedia(SACMediaList sacMedia) {
// Media media;
// if (sacMedia.getLength() == 1) {
// media = new MediaQuery(sacMedia.item(0));
// } else {
// MediaQueryList groupedMedia = new MediaQueryList();
// for (int i = 0; i < sacMedia.getLength(); i++)
// groupedMedia.addMedia(new MediaQuery(sacMedia.item(i)));
// media = groupedMedia;
// }
// return media;
// }
@Override
public void endMedia(SACMediaList mediaList) throws CSSException {
// if (currentMediaQueryList instanceof MediaQuery) {
// currentMediaQueryList = null;
// } else {
// MediaQueryList groupedMedia = (MediaQueryList)currentMediaQueryList;
// for (int i = 0; i < mediaList.getLength(); i++) {
// groupedMedia.removeMedia(mediaList.item(i));
// }
// if (groupedMedia.size() == 1)
// currentMediaQueryList = new MediaQuery(groupedMedia.getAtomicMedia(0).getMediaType());
// else if (groupedMedia.size() == 0)
// currentMediaQueryList = null;
// }
}
@Override
public void startSelector(SelectorList selectorList) throws CSSException {
throw new CSSException("No locator is provided.");
}
public void startSelector(SelectorList selectorList, Locator loc) {
numberOfVisitedElements++;
currentSelector = getSelector(selectorList, loc);
if (currentSelector != null)
styleSheet.addSelector(currentSelector);
}
@Override
public void endSelector(SelectorList selectorList) throws CSSException {
currentSelector = null;
}
@Override
public void property(String propertyName, LexicalUnit values, boolean isImportant)
throws CSSException {
// property(arg0, arg1, arg2, null);
throw new RuntimeException("No locator provided");
}
public void property(String propertyName, LexicalUnit values, boolean isImportant, Locator locator) {
try {
List<DeclarationValue> valuesList = getAllValues(propertyName, values);
Declaration newDeclaration = null;
newDeclaration = DeclarationFactory.getDeclaration(propertyName, valuesList, currentSelector, isImportant, true, new LocationInfo(locator.getLineNumber(), locator.getColumnNumber()));
if (currentSelector != null)
currentSelector.addDeclaration(newDeclaration);
} catch (Exception ex) {
LOGGER.warn(ex.toString());
}
}
/**
* Gets a {@link Selector} from a SAC Selector List
* @param list a SAC selector list, a list of comma separated SAC selectors
* @param locator SAC Locator pointing to the location of the selector list
* @return
*/
private Selector getSelector(SelectorList list, Locator locator) {
Selector s = null;
int line = -1, column = -1;
if (list.getLength() > 1) {
GroupingSelector groupedSelectors = new GroupingSelector();
for (int i = 0; i < list.getLength(); i++) {
try {
BaseSelector newAtomicSelector = SACSelectorToAtomicSelector(list.item(i));
newAtomicSelector.setLocationInfo(
new LocationInfo(
locator.getLineNumber(),
locator.getColumnNumber() - newAtomicSelector.toString().length() + 1));
if (currentMediaQueryLists.size() > 0)
newAtomicSelector.addMediaQueryLists(currentMediaQueryLists);
groupedSelectors.add(newAtomicSelector);
} catch (Exception ex) {
LOGGER.warn(ex.toString());
}
}
line = locator.getLineNumber();
column = locator.getColumnNumber() - groupedSelectors.toString().length() + 1;
groupedSelectors.addMediaQueryLists(currentMediaQueryLists);
s = groupedSelectors;
} else {
try {
s = SACSelectorToAtomicSelector(list.item(0));
line = locator.getLineNumber();
column = locator.getColumnNumber() - s.toString().length() + 1;
if (currentMediaQueryLists.size() > 0)
s.addMediaQueryLists(currentMediaQueryLists);
// styleSheet.addSelector(currentSelector);
} catch (Exception ex) {
LOGGER.warn(ex.toString());
}
}
s.setLocationInfo(new LocationInfo(line, column));
return s;
}
/**
* Returns an {@link BaseSelector} from a given SAC selector
* Adapted from GWT http://google-web-toolkit.googlecode.com/svn-history/r7441/trunk/user/src/com/google/gwt/resources/css/GenerateCssAst.java
* @param selector
* @return
* @throws Exception
*/
private BaseSelector SACSelectorToAtomicSelector(org.w3c.css.sac.Selector selector) throws Exception {
// if (selector instanceof CharacterDataSelector) {
// Unimplemented in flute?
// }
if (selector instanceof ElementSelectorImpl) {
ElementSelectorImpl sacElementSelector = (ElementSelectorImpl) selector;
SimpleSelector atomicElementSelector = new SimpleSelector();
String elementName;
if (sacElementSelector.getLocalName() == null) {
elementName = "*";
} else {
elementName = sacElementSelector.getLocalName();
}
atomicElementSelector.setSelectedElementName(elementName);
return atomicElementSelector;
} else if (selector instanceof DescendantSelectorImpl) {
DescendantSelectorImpl sacDescendantSelector = (DescendantSelectorImpl) selector;
BaseSelector parentAtomicSelector = SACSelectorToAtomicSelector(sacDescendantSelector.getAncestorSelector());
SimpleSelector childAtomicSelector = (SimpleSelector)SACSelectorToAtomicSelector(sacDescendantSelector.getSimpleSelector());
DescendantSelector s = new DescendantSelector(parentAtomicSelector, childAtomicSelector);
return s;
} else if (selector instanceof ChildSelectorImpl) {
/*
* In fact we have three different occasions wherein this happens: A
* > B :first-letter :first-line
*/
ChildSelectorImpl sacChildSelectorImpl = (ChildSelectorImpl) selector;
BaseSelector parentAtomicSelector = SACSelectorToAtomicSelector(sacChildSelectorImpl.getAncestorSelector());
SimpleSelector childAtomicSelector = (SimpleSelector)SACSelectorToAtomicSelector(sacChildSelectorImpl.getSimpleSelector());
BaseSelector selectorToReturn;
if (sacChildSelectorImpl.getSimpleSelector() instanceof PseudoElementSelectorImpl) {
selectorToReturn = parentAtomicSelector;
PseudoElementSelectorImpl pseudoClass = (PseudoElementSelectorImpl) sacChildSelectorImpl.getSimpleSelector();
SimpleSelector simpleSelector;
if (selectorToReturn instanceof SimpleSelector) // in case of .test:test
simpleSelector = ((SimpleSelector) selectorToReturn);
else // in case of .test .test2:test
simpleSelector = ((Combinator)selectorToReturn).getRightHandSideSelector();
simpleSelector.addPseudoClass(new PseudoClass(pseudoClass.getLocalName()));
} else {
selectorToReturn = new ChildSelector(parentAtomicSelector, childAtomicSelector);
}
return selectorToReturn;
} else if (selector instanceof PseudoElementSelectorImpl) {
PseudoElementSelectorImpl pseudoElementSelector = (PseudoElementSelectorImpl) selector;
SimpleSelector atomicElementSelector = new SimpleSelector();
atomicElementSelector.addPseudoClass(new PseudoClass(pseudoElementSelector.getLocalName()));
return atomicElementSelector;
} else if (selector instanceof DirectAdjacentSelectorImpl) {
DirectAdjacentSelectorImpl sacDirectAdjacentSelector = (DirectAdjacentSelectorImpl) selector;
BaseSelector parentSelector = SACSelectorToAtomicSelector(sacDirectAdjacentSelector.getSelector());
SimpleSelector childSelector = (SimpleSelector)SACSelectorToAtomicSelector(sacDirectAdjacentSelector.getSiblingSelector());
return new AdjacentSiblingSelector(parentSelector, childSelector);
} else if (selector instanceof AdjacentSelector) {
AdjacentSelector sacAdjacentSelector = (AdjacentSelector) selector;
BaseSelector parentSelector = SACSelectorToAtomicSelector(sacAdjacentSelector.getSelector());
SimpleSelector childSelector = (SimpleSelector)SACSelectorToAtomicSelector(sacAdjacentSelector.getSiblingSelector());
return new SiblingSelector(parentSelector, childSelector);
} else if (selector instanceof ConditionalSelectorImpl) {
ConditionalSelector sacConditionalSelector = (ConditionalSelectorImpl) selector;
SimpleSelector atomicElementSelector = (SimpleSelector) SACSelectorToAtomicSelector(sacConditionalSelector.getSimpleSelector());
getConditions(sacConditionalSelector.getCondition(), atomicElementSelector);
return atomicElementSelector;
} else {
throw new Exception("Selector not supported: " + selector);
}
}
/**
* Adds the conditions (like pseudo classes, etc) to the given selector,
* based on the SAC conditions
* @param sacCondition
* @param atomicElementSelector
* @throws Exception
*/
private void getConditions(Condition sacCondition, SimpleSelector atomicElementSelector) throws Exception {
if (sacCondition == null)
return;
if (sacCondition instanceof AndConditionImpl) {
AndConditionImpl andCondition = (AndConditionImpl) sacCondition;
getConditions(andCondition.getFirstCondition(),
atomicElementSelector);
getConditions(andCondition.getSecondCondition(),
atomicElementSelector);
} else if (sacCondition instanceof ClassConditionImpl) {
ClassConditionImpl classCond = (ClassConditionImpl) sacCondition;
atomicElementSelector.addClassName(classCond.getValue());
} else if (sacCondition instanceof PseudoClassConditionImpl) {
PseudoClassConditionImpl pseudoCond = (PseudoClassConditionImpl) sacCondition;
atomicElementSelector.addPseudoClass(new PseudoClass(pseudoCond
.getValue()));
} else if (sacCondition instanceof IdConditionImpl) {
IdConditionImpl c = (IdConditionImpl) sacCondition;
atomicElementSelector.setElementID(c.getValue());
} else if (sacCondition instanceof LangConditionImpl) {
LangConditionImpl langCondition = (LangConditionImpl) sacCondition;
atomicElementSelector.addPseudoClass(new PseudoClass("lang",
langCondition.getLang()));
} else if (sacCondition instanceof AttributeConditionImpl) {
AttributeConditionImpl attributeConditionImpl = (AttributeConditionImpl) sacCondition;
SelectorCondition selectorCondition = new SelectorCondition(
attributeConditionImpl.getLocalName());
String value = attributeConditionImpl.getValue();
if (value != null) {
selectorCondition
.setConditionType(SelectorConditionType.VALUE_EQUALS_EXACTLY);
selectorCondition.setValue(attributeConditionImpl
.getValue());
}
atomicElementSelector.addCondition(selectorCondition);
} else if (sacCondition instanceof OneOfAttributeConditionImpl) {
OneOfAttributeConditionImpl oneOfAttrCondition = (OneOfAttributeConditionImpl) sacCondition;
SelectorCondition selectorCondition = new SelectorCondition(
oneOfAttrCondition.getLocalName(),
oneOfAttrCondition.getValue(),
SelectorConditionType.VALUE_CONTAINS_WORD_SPACE_SEPARATED);
atomicElementSelector.addCondition(selectorCondition);
} else if (sacCondition instanceof BeginHyphenAttributeConditionImpl) {
BeginHyphenAttributeConditionImpl oneOfAttrCondition = (BeginHyphenAttributeConditionImpl) sacCondition;
SelectorCondition selectorCondition = new SelectorCondition(
oneOfAttrCondition.getLocalName(),
oneOfAttrCondition.getValue(),
SelectorConditionType.VALUE_START_WITH_DASH_SEPARATED);
atomicElementSelector.addCondition(selectorCondition);
} else if (sacCondition instanceof CaretCondition) {
CaretCondition oneOfAttrCondition = (CaretCondition) sacCondition;
SelectorCondition selectorCondition = new SelectorCondition(
oneOfAttrCondition.getLocalName(),
oneOfAttrCondition.getValue(),
SelectorConditionType.VALUE_STARTS_WITH);
atomicElementSelector.addCondition(selectorCondition);
} else if (sacCondition instanceof ContainsCondition) {
ContainsCondition oneOfAttrCondition = (ContainsCondition) sacCondition;
SelectorCondition selectorCondition = new SelectorCondition(
oneOfAttrCondition.getLocalName(),
oneOfAttrCondition.getValue(),
SelectorConditionType.VALUE_CONTAINS);
atomicElementSelector.addCondition(selectorCondition);
} else if (sacCondition instanceof EndsWithCondition) {
EndsWithCondition oneOfAttrCondition = (EndsWithCondition) sacCondition;
SelectorCondition selectorCondition = new SelectorCondition(
oneOfAttrCondition.getLocalName(),
oneOfAttrCondition.getValue(),
SelectorConditionType.VALUE_ENDS_WITH);
atomicElementSelector.addCondition(selectorCondition);
} else if (sacCondition instanceof NegativeConditionImpl) {
NegativeConditionImpl condition = (NegativeConditionImpl) sacCondition;
SelectorList l = condition.getSelectorList();
Locator loc = condition.getLocator();
Selector s = getSelector(l, loc);
// Selector "s" shoule be a simple selector, based on W3C http://www.w3.org/TR/css3-selectors/
if ((s instanceof SimpleSelector)) {
atomicElementSelector.addPseudoClass(new NegationPseudoClass((BaseSelector)s));
} else {
LOGGER.warn("The parameter of not() pseudo-element should be a simple CSS selector. ");
}
} else if (sacCondition instanceof FunctionPseudoClassCondition) {
FunctionPseudoClassCondition pcs = (FunctionPseudoClassCondition) sacCondition;
atomicElementSelector.addPseudoClass(new PseudoClass(pcs
.getLocalName(), pcs.getValue()));
} else if (sacCondition instanceof PseudoElementCondition) {
PseudoElementCondition spcc = (PseudoElementCondition) sacCondition;
atomicElementSelector.addPseudoElement(new PseudoElement(spcc
.getName()));
} else {
throw new Exception("Condition not supported: " + sacCondition);
}
}
/**
* This method gives a <code>List<ca.concordia.cssanalyser.cssmodel.declaration.DeclarationValue></code>
* From a given LexicalUnit value from SAC. <br />
* Note that in SAC, LexicalUnit is a linked list of values for a CSS property
* @param value
*/
private List<DeclarationValue> getAllValues(String propertyName, LexicalUnit value) throws Exception {
List<DeclarationValue> accumulator = new ArrayList<>();
if (value != null) {
do {
DeclarationValue decValue = getValue(propertyName, value);
if (value != null)
accumulator.add(decValue);
value = value.getNextLexicalUnit();
} while (value != null);
}
return accumulator;
}
/**
* This method mainly returns {@link DeclarationValue} or {@link DeclarationEquivalentValue},
* based on the given SAC value and SAC property
* @param value
*/
private DeclarationValue getValue(String propertyName, LexicalUnit value) throws Exception {
if (value == null)
return null;
switch (value.getLexicalUnitType()) {
case LexicalUnit.SAC_ATTR:
/*
* attr(). The W3C CSS3 specification says that they may
* drop this kind of value but we still support it
* http://www.w3.org/TR/2013/CR-css3-values-20130730/
*/
return DeclarationValueFactory.getDeclarationValue(propertyName, "attr(" + value.getStringValue() + ")", ValueType.ATTR);
case LexicalUnit.SAC_IDENT:
/*
* Different types of values may be in this group, like
* color values, etc.
*/
return DeclarationValueFactory.getDeclarationValue(propertyName, value.getStringValue(), ValueType.IDENT);
case LexicalUnit.SAC_STRING_VALUE:
// Values coming between ' and " are modeled in this way in SAC
return DeclarationValueFactory.getDeclarationValue(propertyName, "'" + value.getStringValue() + "'", ValueType.STRING);
// All color could be converted to RGBA
case LexicalUnitImpl.HEX_COLOR:
// Three or six-digit hex value
String realVal = "#" + value.getStringValue().toLowerCase();
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.COLOR);
case LexicalUnit.SAC_RGBCOLOR:
return getColorValue(propertyName, "rgb", value);
case LexicalUnitImpl.RGBA_COLOR:
return getColorValue(propertyName, "rgba", value);
case LexicalUnitImpl.HSL_COLOR:
return getColorValue(propertyName, "hsl", value);
case LexicalUnitImpl.HSLA_COLOR:
return getColorValue(propertyName, "hsla", value);
case LexicalUnit.SAC_INTEGER:
return DeclarationValueFactory.getDeclarationValue(propertyName, String.valueOf(value.getIntegerValue()), ValueType.INTEGER);
case LexicalUnit.SAC_REAL:
return DeclarationValueFactory.getDeclarationValue(propertyName, DeclarationValueFactory.formatDouble(value.getFloatValue()), ValueType.REAL);
// Length values may be convertible to each other
case LexicalUnit.SAC_PICA:
return DeclarationValueFactory.getFontValue(propertyName, value.getFloatValue(), "pc");
case LexicalUnit.SAC_POINT:
return DeclarationValueFactory.getFontValue(propertyName, value.getFloatValue(), "pt");
case LexicalUnit.SAC_INCH:
return DeclarationValueFactory.getFontValue(propertyName, value.getFloatValue(), "in");
case LexicalUnit.SAC_CENTIMETER:
return DeclarationValueFactory.getFontValue(propertyName, value.getFloatValue(), "cm");
case LexicalUnit.SAC_MILLIMETER:
return DeclarationValueFactory.getFontValue(propertyName, value.getFloatValue(), "mm");
case LexicalUnit.SAC_PIXEL:
return DeclarationValueFactory.getFontValue(propertyName, value.getFloatValue(), "px");
// We convert all angle values to degree.
case LexicalUnit.SAC_GRADIAN:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "grad";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.ANGLE);
case LexicalUnit.SAC_RADIAN:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "rad";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.ANGLE);
case LexicalUnitImpl.TURN:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "turn";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.ANGLE);
case LexicalUnit.SAC_DEGREE:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "deg";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.ANGLE);
case LexicalUnit.SAC_KILOHERTZ:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "khz";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.FREQUENCY);
case LexicalUnit.SAC_HERTZ:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "hz";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.FREQUENCY);
// s and ms are convertible to each other
case LexicalUnit.SAC_SECOND:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "s";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.TIME);
case LexicalUnit.SAC_MILLISECOND:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "ms";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.TIME);
// EM and % are somehow the same.
case LexicalUnit.SAC_EM:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "em";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.LENGTH);
case LexicalUnitImpl.REM:
// 1rem = 100% of the parent's font. SO we don't add
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "rem";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.PERCENTAGE);
case LexicalUnit.SAC_PERCENTAGE:
realVal = DeclarationValueFactory.formatDouble(value.getFloatValue()) + "%";
return DeclarationValueFactory.getDeclarationValue(propertyName, realVal, ValueType.PERCENTAGE);
case LexicalUnit.SAC_EX:
/*
* EX is calculated in a different way across different browsers
* (IE-not known in which version-: 1ex = 0.5em, while not other browsers)
*/
return DeclarationValueFactory.getDeclarationValue(propertyName, DeclarationValueFactory.formatDouble(value.getFloatValue()) + "ex", ValueType.LENGTH);
case LexicalUnit.SAC_DIMENSION:
//Unknown dimension :)
return DeclarationValueFactory.getDeclarationValue(propertyName,
DeclarationValueFactory.formatDouble(value.getFloatValue()) + value.getDimensionUnitText().toLowerCase(), ValueType.DIMENSION);
case LexicalUnit.SAC_URI:
realVal = "url('" + value.getStringValue() + "')";
return DeclarationValueFactory.getDeclarationValue(propertyName,realVal, ValueType.URL);
case LexicalUnit.SAC_OPERATOR_COMMA:
return DeclarationValueFactory.getDeclarationValue(propertyName,",", ValueType.SEPARATOR);
case LexicalUnit.SAC_COUNTER_FUNCTION:
case LexicalUnit.SAC_COUNTERS_FUNCTION:
case LexicalUnit.SAC_FUNCTION:
return DeclarationValueFactory.getDeclarationValue(propertyName, value.getFunctionName() + "(" + addSeparators(getAllValues(value.getFunctionName(), value.getParameters()), " ") + ")", ValueType.FUNCTION);
case LexicalUnit.SAC_INHERIT:
return DeclarationValueFactory.getDeclarationValue(propertyName,"inherit", ValueType.INHERIT);
case LexicalUnit.SAC_OPERATOR_EXP:
return DeclarationValueFactory.getDeclarationValue(propertyName,"^", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_GE:
return DeclarationValueFactory.getDeclarationValue(propertyName,">=", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_GT:
return DeclarationValueFactory.getDeclarationValue(propertyName,">", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_LE:
return DeclarationValueFactory.getDeclarationValue(propertyName,"<=", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_LT:
return DeclarationValueFactory.getDeclarationValue(propertyName,"<", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_MINUS:
return DeclarationValueFactory.getDeclarationValue(propertyName,"-", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_MOD:
return DeclarationValueFactory.getDeclarationValue(propertyName,"%", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_MULTIPLY:
return DeclarationValueFactory.getDeclarationValue(propertyName,"*", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_PLUS:
return DeclarationValueFactory.getDeclarationValue(propertyName,"+", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_SLASH:
return DeclarationValueFactory.getDeclarationValue(propertyName,"/", ValueType.OPERATOR);
case LexicalUnit.SAC_OPERATOR_TILDE:
return DeclarationValueFactory.getDeclarationValue(propertyName,"~", ValueType.OPERATOR);
case LexicalUnit.SAC_RECT_FUNCTION: {
return DeclarationValueFactory.getDeclarationValue(propertyName, "rect(" + addSeparators(getAllValues("rect", value.getParameters()), " ") + ")", ValueType.FUNCTION);
}
case LexicalUnit.SAC_SUB_EXPRESSION:
// Never happens cause ca.concordia.cssanalyser.parser does not support it?
case LexicalUnit.SAC_UNICODERANGE:
// Cannot be expressed in CSS2
/* One of the old versions of CSS3 working drafts pointed to background: (10px 10px) which was dropped at some point.
* So I dropped it as well
*/
//case LexicalUnitImpl.PARAN:
// return "(" + addSeparators(getAllValues(value.getParameters()), " ") + ")" ;
}
throw new RuntimeException("Unhandled LexicalUnit type " + value.getLexicalUnitType());
}
private DeclarationValue getColorValue(String propertyName, String colorFunction, LexicalUnit value) {
try {
String val = colorFunction + "(" + addSeparators(getAllValues(colorFunction, value.getParameters()), ", ") + ")";
return DeclarationValueFactory.getDeclarationValue(propertyName, val, ValueType.COLOR);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Adds separators between a list of values and returns the string
* containing those values separated with those separators
* @param listOfStrings
* @param separator
* @return
*/
private String addSeparators(List<DeclarationValue> listOfStrings, String separator) {
String toReturn = "";
for (DeclarationValue dv : listOfStrings)
if (!separator.trim().equals(dv.toString().trim()))
toReturn += dv + separator;
return toReturn.substring(0, toReturn.length() - separator.length());
}
/**
* Returns the number of visited selector in the stylesheet
* @return
*/
public int getNumberOfVisitedSelectors() {
return numberOfVisitedElements;
}
}