/** * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onebusaway.presentation.impl.resources; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.css.sac.CSSException; import org.w3c.css.sac.InputSource; import org.w3c.css.sac.LexicalUnit; import org.w3c.css.sac.Parser; import org.w3c.css.sac.SACMediaList; import org.w3c.css.sac.Selector; import org.w3c.css.sac.SelectorList; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.resources.client.ResourcePrototype; import com.steadystate.css.parser.SACParserCSS2; import com.steadystate.css.sac.DocumentHandlerExt; /***************************************************************************** * Internal Classes ****************************************************************************/ class CssDocumentHandlerImpl implements DocumentHandlerExt { private static Logger _log = LoggerFactory.getLogger(CssDocumentHandlerImpl.class); private static final String AT_RULE_URL = "@url"; private static final String AT_RULE_SPRITE = "@sprite"; private Map<String, String> _substitutions = new HashMap<String, String>(); private StringBuilder _buffer = new StringBuilder(); private ClientBundleContext _context; private ClientBundleImpl _parentBundle; public CssDocumentHandlerImpl(ClientBundleContext context, ClientBundleImpl parentBundle) { _context = context; _parentBundle = parentBundle; } public String getResults() { return _buffer.toString(); } public void startDocument(InputSource source) throws CSSException { } public void endDocument(InputSource source) throws CSSException { } public void comment(String comment) throws CSSException { } public void startFontFace() throws CSSException { _log.debug("start font face"); } public void endFontFace() throws CSSException { _log.debug("end font face"); } public void importStyle(String uri, SACMediaList media, String defaultNamespaceUri) throws CSSException { } public void ignorableAtRule(String atRule) throws CSSException { if (atRule.startsWith(AT_RULE_SPRITE)) { String snippet = atRule.substring(AT_RULE_SPRITE.length()); snippet = snippet.trim(); parse(snippet); } else if (atRule.startsWith(AT_RULE_URL)) { String snippet = atRule.substring(AT_RULE_URL.length()); snippet = snippet.trim(); Pattern pattern = Pattern.compile("^(\\w+)\\s+(\\w+);$"); Matcher matcher = pattern.matcher(snippet); if (matcher.matches()) { String name = matcher.group(1); String resource = matcher.group(2); handleUrl(name, resource); } } } public void namespaceDeclaration(String arg0, String arg1) throws CSSException { } public void startMedia(SACMediaList media) throws CSSException { } public void endMedia(SACMediaList media) throws CSSException { } public void startPage(String name, String pseudoPage) throws CSSException { } public void endPage(String name, String pseudoPage) throws CSSException { } public void startSelector(SelectorList selectors) throws CSSException { for (int i = 0; i < selectors.getLength(); i++) { Selector selector = selectors.item(i); if (i > 0) _buffer.append(','); _buffer.append(selector.toString()); } _buffer.append("{"); } public void property(String name, LexicalUnit unit, boolean important) throws CSSException { if (name.equals("gwt-image")) { String v = unit.toString(); ResourcePrototype resource = _parentBundle.getResource(v); if (resource == null) { _log.warn("unknown resource: " + v); return; } if (!(resource instanceof ImageResource)) { _log.warn("expected ImageResource"); return; } ImageResource img = (ImageResource) resource; _buffer.append("background-image:url(" + img.getURL() + ");"); } else { _buffer.append(name); _buffer.append(':'); int index = 0; while (unit != null) { if (index > 0) _buffer.append(" "); String v = unit.toString(); v = substitute(v); _buffer.append(v); unit = unit.getNextLexicalUnit(); index++; } _buffer.append(';'); } } public void endSelector(SelectorList selectors) throws CSSException { _buffer.append('}').append('\n'); } public void charset(String characterEncoding) throws CSSException { } /*************************************************************************** * **************************************************************************/ private void handleUrl(String name, String value) { ResourcePrototype resource = _parentBundle.getResource(value); if (resource == null) throw new IllegalStateException("unknown resource name=" + name + " value: " + value); if (!(resource instanceof ResourceWithUrl)) throw new IllegalStateException( "resource is not instance of ResourceWithUrl: name=" + value + " value=" + resource); ResourceWithUrl data = (ResourceWithUrl) resource; String url = data.getUrl(); url = _context.addContext(url); _substitutions.put(name, "url(\"" + url + "\")"); } private String substitute(String id) { if (_substitutions.containsKey(id)) id = _substitutions.get(id); return id; } private void parse(String snippet) throws CSSException { try { BufferedReader reader = new BufferedReader(new StringReader(snippet)); InputSource source = new InputSource(reader); Parser p = new SACParserCSS2(); p.setDocumentHandler(this); p.parseStyleSheet(source); reader.close(); } catch (IOException ex) { throw new CSSException(ex); } } }