blob: fe1c5e9cecd546a2effaf7074d48f187b3b356a4 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.flex.compiler.internal.driver.js.flexjs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.flex.compiler.constants.IASLanguageConstants;
import org.apache.flex.compiler.css.ICSSDocument;
import org.apache.flex.compiler.css.ICSSMediaQueryCondition;
import org.apache.flex.compiler.css.ICSSProperty;
import org.apache.flex.compiler.css.ICSSPropertyValue;
import org.apache.flex.compiler.css.ICSSRule;
import org.apache.flex.compiler.css.ICSSSelector;
import org.apache.flex.compiler.css.ICSSSelectorCondition;
import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
import org.apache.flex.compiler.internal.css.*;
import org.apache.flex.compiler.internal.css.codegen.CSSCompilationSession;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
public class JSCSSCompilationSession extends CSSCompilationSession
{
private ArrayList<String> requires;
public String getEncodedCSS()
{
final ICSSDocument css = synthesisNormalizedCSS();
StringBuilder sb = new StringBuilder();
requires = new ArrayList<String>();
encodeCSS(css, sb);
if (sb.length() == 0)
return null;
sb.append("];\n");
for (String r : requires)
{
sb.append(JSGoogEmitterTokens.GOOG_REQUIRE.getToken() + "('" + formatQualifiedName(r) + "');\n");
}
return sb.toString();
}
public String emitCSS()
{
final ICSSDocument css = synthesisNormalizedCSS();
StringBuilder sb = new StringBuilder();
sb.append("/* Generated by Apache Flex Cross-Compiler */\n");
walkCSS(css, sb);
return sb.toString();
}
private String fontFaceToString(CSSFontFace fontFace)
{
final StringBuilder result = new StringBuilder();
result.append("@font-face {\n");
result.append(" ");
result.append("font-family: ");
result.append(fontFace.getFontFamily() + ";\n");
result.append(" ");
result.append("font-style: ");
result.append(fontFace.getFontStyle() + ";\n");
result.append(" ");
result.append("font-weight: ");
result.append(fontFace.getFontStyle() + ";\n");
result.append(" ");
ArrayList<ICSSPropertyValue> sources = fontFace.getSources();
for (ICSSPropertyValue src : sources)
{
result.append("src: ");
result.append(src.toString() + ";\n");
}
result.append("}\n");
return result.toString();
}
private String cssRuleToString(ICSSRule rule)
{
final StringBuilder result = new StringBuilder();
ImmutableList<ICSSMediaQueryCondition> mqList = rule.getMediaQueryConditions();
boolean hasMediaQuery = !mqList.isEmpty();
if (hasMediaQuery)
{
result.append("@media ");
result.append(Joiner.on(" and ").join(rule.getMediaQueryConditions()));
result.append(" {\n");
result.append(" ");
}
ImmutableList<ICSSSelector> selectors = rule.getSelectorGroup();
boolean firstOne = true;
for (ICSSSelector selector : selectors)
{
String s = selector.toString();
// add "." to type selectors that don't map cleanly
// to CSS type selectors to convert them to class
// selectors.
if (!s.startsWith(".") && !s.startsWith("*") && !s.startsWith("#"))
{
String condition = null;
int colon = s.indexOf(":");
if (colon != -1)
{
condition = s.substring(colon);
s = s.substring(0, colon);
}
if (!htmlElementNames.contains(s.toLowerCase()))
{
int pipe = s.indexOf("|");
if (pipe != -1)
s = s.substring(pipe + 1);
s = "." + s;
}
if (condition != null)
s = s + condition;
}
if (!firstOne)
result.append(",\n");
result.append(s);
}
result.append(" {\n");
for (final ICSSProperty prop : rule.getProperties())
{
if (!hasMediaQuery)
result.append(" ");
String propString = ((CSSProperty)prop).toCSSString();
// skip class references since the won't work in CSS
if (propString.contains("ClassReference"))
continue;
result.append(" ").append(propString).append("\n");
}
if (hasMediaQuery)
result.append(" }\n");
result.append("}\n");
return result.toString();
}
private void walkCSS(ICSSDocument css, StringBuilder sb)
{
for (CSSFontFace fontFace : fontFaces)
{
sb.append(fontFaceToString(fontFace));
}
if (fontFaces.size() > 0)
sb.append("\n\n");
ImmutableList<ICSSRule> rules = css.getRules();
for (ICSSRule rule : rules)
{
String s = cssRuleToString(rule);
if (s.startsWith("@media -flex-flash"))
continue;
if (s.startsWith(".global {"))
s = s.replace(".global {", "* {");
sb.append(s);
sb.append("\n\n");
}
}
private void encodeCSS(ICSSDocument css, StringBuilder sb)
{
ImmutableList<ICSSRule> rules = css.getRules();
boolean skipcomma = true;
for (ICSSRule rule : rules)
{
String s = encodeRule(rule);
if (s != null)
{
if (skipcomma)
skipcomma = false;
else
sb.append(",\n");
sb.append(s);
}
}
}
List<String> htmlElementNames = Arrays.asList(
"body",
"button",
"span"
);
private String encodeRule(ICSSRule rule)
{
final StringBuilder result = new StringBuilder();
ImmutableList<ICSSMediaQueryCondition> mqlist = rule.getMediaQueryConditions();
int n = mqlist.size();
if (n > 0)
{
if (mqlist.get(0).toString().equals("-flex-flash"))
return null;
result.append(n);
for (ICSSMediaQueryCondition mqcond : mqlist)
{
result.append(",\n");
result.append("\"" + mqcond.toString() + "\"");
}
}
else
result.append(n);
result.append(",\n");
ImmutableList<ICSSSelector> slist = rule.getSelectorGroup();
result.append(slist.size());
for (ICSSSelector sel : slist)
{
result.append(",\n");
String selName = this.resolvedSelectors.get(sel);
if (selName == null || selName.equals("null"))
result.append("\"" + sel.toString() + "\"");
else
{
selName = formatQualifiedName(selName);
ImmutableList<ICSSSelectorCondition> conds = sel.getConditions();
for (ICSSSelectorCondition cond : conds)
selName += cond.toString();
result.append("\"" + selName + "\"");
}
}
result.append(",\n");
result.append("function() {");
ImmutableList<ICSSProperty> plist = rule.getProperties();
boolean firstProp = true;
for (final ICSSProperty prop : plist)
{
if (!firstProp)
result.append(";\n");
firstProp = false;
result.append("this[\"" + prop.getName() + "\"] = ");
ICSSPropertyValue value = prop.getValue();
if (value instanceof CSSArrayPropertyValue)
{
ImmutableList<? extends ICSSPropertyValue> values = ((CSSArrayPropertyValue)value).getElements();
result.append("[");
boolean firstone = true;
for (ICSSPropertyValue val : values)
{
if (firstone)
firstone = false;
else
result.append(", ");
if (val instanceof CSSStringPropertyValue)
{
result.append("\"" + ((CSSStringPropertyValue)val).getValue() + "\"");
}
else if (val instanceof CSSColorPropertyValue)
{
result.append(new Integer(((CSSColorPropertyValue)val).getColorAsInt()));
}
else if (val instanceof CSSRgbColorPropertyValue)
{
result.append(new Integer(((CSSRgbColorPropertyValue)val).getColorAsInt()));
}
else if (value instanceof CSSRgbaColorPropertyValue)
{
//todo: handle alpha in the RGBA ?
result.append(new Integer(((CSSRgbaColorPropertyValue)value).getColorAsInt()));
}
else if (val instanceof CSSKeywordPropertyValue)
{
CSSKeywordPropertyValue keywordValue = (CSSKeywordPropertyValue)val;
String keywordString = keywordValue.getKeyword();
if (IASLanguageConstants.TRUE.equals(keywordString))
result.append("true");
else if (IASLanguageConstants.FALSE.equals(keywordString))
result.append("false");
else
result.append("\"" + ((CSSKeywordPropertyValue)val).getKeyword() + "\"");
}
else if (val instanceof CSSNumberPropertyValue)
{
result.append(new Double(((CSSNumberPropertyValue)val).getNumber().doubleValue()));
}
else if (val instanceof CSSURLAndFormatPropertyValue)
{
result.append("\"" + ((CSSURLAndFormatPropertyValue)val).toString() + "\"");
}
else
{
result.append("unexpected value type: " + val.toString());
}
}
result.append("]");
}
else if (value instanceof CSSStringPropertyValue)
{
result.append("\"" + ((CSSStringPropertyValue)value).getValue() + "\"");
}
else if (value instanceof CSSColorPropertyValue)
{
result.append(new Integer(((CSSColorPropertyValue)value).getColorAsInt()));
}
else if (value instanceof CSSRgbColorPropertyValue)
{
result.append(new Integer(((CSSRgbColorPropertyValue)value).getColorAsInt()));
}
else if (value instanceof CSSRgbaColorPropertyValue)
{
//todo: handle alpha in the RGBA ?
result.append(new Integer(((CSSRgbaColorPropertyValue)value).getColorAsInt()));
}
else if (value instanceof CSSKeywordPropertyValue)
{
CSSKeywordPropertyValue keywordValue = (CSSKeywordPropertyValue)value;
String keywordString = keywordValue.getKeyword();
if (IASLanguageConstants.TRUE.equals(keywordString))
result.append("true");
else if (IASLanguageConstants.FALSE.equals(keywordString))
result.append("false");
else
result.append("\"" + ((CSSKeywordPropertyValue)value).getKeyword() + "\"");
}
else if (value instanceof CSSNumberPropertyValue)
{
result.append(new Double(((CSSNumberPropertyValue)value).getNumber().doubleValue()));
}
else if (value instanceof CSSFunctionCallPropertyValue)
{
final CSSFunctionCallPropertyValue functionCall = (CSSFunctionCallPropertyValue)value;
if ("ClassReference".equals(functionCall.name))
{
final String className = CSSFunctionCallPropertyValue.getSingleArgumentFromRaw(functionCall.rawArguments);
if ("null".equals(className))
{
// ClassReference(null) resets the property's class reference.
result.append("null");
}
else
{
result.append(formatQualifiedName(className));
requires.add(className);
}
}
else if ("url".equals(functionCall.name))
{
final String urlString = CSSFunctionCallPropertyValue.getSingleArgumentFromRaw(functionCall.rawArguments);
result.append("\"" + urlString + "\"");
}
else if ("PropertyReference".equals(functionCall.name))
{
// TODO: implement me
}
else if ("Embed".equals(functionCall.name))
{
// TODO: implement me
/*
final ICompilerProblem e = new CSSCodeGenProblem(
new IllegalStateException("Unable to find compilation unit for " + functionCall));
problems.add(e);
*/
}
else
{
assert false : "CSS parser bug: unexpected function call property value: " + functionCall;
throw new IllegalStateException("Unexpected function call property value: " + functionCall);
}
}
}
result.append("}");
return result.toString();
}
@Override
protected boolean keepRule(ICSSRule newRule)
{
if (super.keepRule(newRule))
return true;
// include all rules not found in defaults.css
// theoretically, defaults.css rules were
// properly added in the super call.
String sp = newRule.getSourcePath();
if (!sp.contains("defaults.css"))
return true;
return false;
}
private String formatQualifiedName(String name)
{
/*
if (name.contains("goog.") || name.startsWith("Vector."))
return name;
if (name.startsWith("."))
{
return "." + name.substring(1).replaceAll("\\.", "_");
}
name = name.replaceAll("\\.", "_");
*/
return name;
}
}