public static boolean mediaMatches(String mediaListStr, MediaType rendererMediaType) throws SAXException { CSSTextScanner scan = new CSSTextScanner(mediaListStr); scan.skipWhitespace(); List<MediaType> mediaList = parseMediaList(scan); if (!scan.empty()) throw new SAXException("Invalid @media type list"); return mediaMatches(mediaList, rendererMediaType); }
// Skip an unsupported at-rule: "ignore everything up to and including the next semicolon or // block". private void skipAtRule(CSSTextScanner scan) { int depth = 0; while (!scan.empty()) { int ch = scan.nextChar(); if (ch == ';' && depth == 0) return; if (ch == '{') depth++; else if (ch == '}' && depth > 0) { if (--depth == 0) return; } } }
/* * Used by SVGParser to parse the "class" attribute. */ protected static List<String> parseClassAttribute(String val) throws SAXException { CSSTextScanner scan = new CSSTextScanner(val); List<String> classNameList = null; while (!scan.empty()) { String className = scan.nextIdentifier(); if (className == null) throw new SAXException("Invalid value for \"class\" attribute: " + val); if (classNameList == null) classNameList = new ArrayList<String>(); classNameList.add(className); scan.skipWhitespace(); } return classNameList; }
private static List<MediaType> parseMediaList(CSSTextScanner scan) throws SAXException { ArrayList<MediaType> typeList = new ArrayList<MediaType>(); while (!scan.empty()) { String type = scan.nextToken(','); try { typeList.add(MediaType.valueOf(type)); } catch (IllegalArgumentException e) { throw new SAXException("Invalid @media type list"); } // If there is a comma, keep looping, otherwise break if (!scan.skipCommaWhitespace()) break; } return typeList; }
private boolean parseRule(Ruleset ruleset, CSSTextScanner scan) throws SAXException { List<Selector> selectors = parseSelectorGroup(scan); if (selectors != null && !selectors.isEmpty()) { if (!scan.consume('{')) throw new SAXException("Malformed rule block in <style> element: missing '{'"); scan.skipWhitespace(); SVG.Style ruleStyle = parseDeclarations(scan); scan.skipWhitespace(); for (Selector selector : selectors) { ruleset.add(new Rule(selector, ruleStyle)); } return true; } else { return false; } }
private Ruleset parseRuleset(CSSTextScanner scan) throws SAXException { Ruleset ruleset = new Ruleset(); while (!scan.empty()) { if (scan.consume("<!--")) continue; if (scan.consume("-->")) continue; if (scan.consume('@')) { parseAtRule(ruleset, scan); continue; } if (parseRule(ruleset, scan)) continue; // Nothing recognisable found. Could be end of rule set. Return. break; } return ruleset; }
/* * Parse a selector group (eg. E, F, G). In many/most cases there will be only one entry. */ private List<Selector> parseSelectorGroup(CSSTextScanner scan) throws SAXException { if (scan.empty()) return null; ArrayList<Selector> selectorGroup = new ArrayList<Selector>(1); Selector selector = new Selector(); while (!scan.empty()) { if (scan.nextSimpleSelector(selector)) { // If there is a comma, keep looping, otherwise break if (!scan.skipCommaWhitespace()) continue; // if not a comma, go back and check for next part of selector selectorGroup.add(selector); selector = new Selector(); } else break; } if (!selector.isEmpty()) selectorGroup.add(selector); return selectorGroup; }
private void parseAtRule(Ruleset ruleset, CSSTextScanner scan) throws SAXException { String atKeyword = scan.nextIdentifier(); scan.skipWhitespace(); if (atKeyword == null) throw new SAXException("Invalid '@' rule in <style> element"); if (!inMediaRule && atKeyword.equals("media")) { List<MediaType> mediaList = parseMediaList(scan); if (!scan.consume('{')) throw new SAXException("Invalid @media rule: missing rule set"); scan.skipWhitespace(); if (mediaMatches(mediaList, rendererMediaType)) { inMediaRule = true; ruleset.addAll(parseRuleset(scan)); inMediaRule = false; } else { parseRuleset(scan); // parse and ignore accompanying ruleset } if (!scan.consume('}')) throw new SAXException("Invalid @media rule: expected '}' at end of rule set"); // } else if (atKeyword.equals("charset")) { // } else if (atKeyword.equals("import")) { } else { // Unknown/unsupported at-rule warn("Ignoring @%s rule", atKeyword); skipAtRule(scan); } scan.skipWhitespace(); }
// Parse a list of private SVG.Style parseDeclarations(CSSTextScanner scan) throws SAXException { SVG.Style ruleStyle = new SVG.Style(); while (true) { String propertyName = scan.nextIdentifier(); scan.skipWhitespace(); if (!scan.consume(':')) break; // Syntax error. Stop processing CSS rules. scan.skipWhitespace(); String propertyValue = scan.nextPropertyValue(); if (propertyValue == null) break; // Syntax error // Check for !important flag. scan.skipWhitespace(); if (scan.consume('!')) { scan.skipWhitespace(); if (!scan.consume("important")) { throw new SAXException("Malformed rule set in <style> element: found unexpected '!'"); } // We don't do anything with these. We just ignore them. scan.skipWhitespace(); } scan.consume(';'); SVGParser.processStyleProperty(ruleStyle, propertyName, propertyValue); scan.skipWhitespace(); if (scan.consume('}')) return ruleStyle; if (scan.empty()) break; } throw new SAXException("Malformed rule set in <style> element"); }
public Ruleset parse(String sheet) throws SAXException { CSSTextScanner scan = new CSSTextScanner(sheet); scan.skipWhitespace(); return parseRuleset(scan); }