diff options
author | Roman Kennke <roman@kennke.org> | 2006-11-09 16:31:30 +0000 |
---|---|---|
committer | Roman Kennke <roman@kennke.org> | 2006-11-09 16:31:30 +0000 |
commit | 5456c3fe1d4cc61ef4264d3cb1aa804272d38bb5 (patch) | |
tree | e66f730388a3b1d9f0175abc0efeee3a325a6040 /gnu | |
parent | e38b7787ddcc8d6fed61f7bc7a7f95bcbfe20ab8 (diff) | |
download | classpath-5456c3fe1d4cc61ef4264d3cb1aa804272d38bb5.tar.gz |
2006-11-09 Roman Kennke <kennke@aicas.com>
* gnu/javax/swing/text/html/css/CSSParser.java
(parseRuleset): Use new Selector class.
(parseValue): Parse multiple anys, not only one.
(main): Allow stylesheet be specified on the command line.
Use new Selector class.
* gnu/javax/swing/text/html/css/CSSParserCallback.java
(startStatement): Use Selector class.
* gnu/javax/swing/text/html/css/CSSScanner.java
(readName): Actually read a character in the loop to avoid
endless loop.
* gnu/javax/swing/text/html/css/Length.java
(getValue): Only multiply when we have a percentage value.
* gnu/javax/swing/text/html/css/Selector.java:
New class. Provides handling of CSS selectors.
* javax/swing/text/html/StyleSheet.java
(CSSStyle.PREC_AUTHOR_IMPORTANT): New constant field.
(CSSStyle.PREC_AUTHOR_NORMAL): New constant field.
(CSSStyle.PREC_NORM): New constant field.
(CSSStyle.PREC_UA): New constant field.
(CSSStyle.PREC_USER_IMPORTANT): New constant field.
(CSSStyle.precedence): New field.
(CSSStyle.priority): Removed.
(CSSStyle.selector): New field.
(CSSStyle.CSSStyle(int,Selector)): Initialize with Selector
and precendence.
(CSSStyle.compareTo): Adjusted to use the precedence and
specificity of the selector.
(CSSStyleSheetParserCallback.precedence): New field.
(CSSStyleSheetParserCallback.selector): Removed.
(CSSStyleSheetParserCallback.style): New field.
(CSSStyleSheetParserCallback.CSSStyleSheetParserCallback):
Initialize with precedence.
(CSSStyleSheetParserCallback.declaration): Don't look up
existing rule, simply create new one.
(CSSStyleSheetParserCallback.endStatement): Append style
to stylesheet.
(CSSStyleSheetParserCallback.startStatement): Use new Selector
class.
(css): Changed to be ArrayList.
(addRule): Create parser with author-normal precendence.
(getRule): Fixed implementation.
(loadRules): Create parser with UA precendence.
(resolveStyle): Use Selector class for resolving and matching
stylesheet rules.
(translateHTMLToCSS): Added mappings for a couple of HTML
attributes.
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/javax/swing/text/html/css/CSSParser.java | 23 | ||||
-rw-r--r-- | gnu/javax/swing/text/html/css/CSSParserCallback.java | 2 | ||||
-rw-r--r-- | gnu/javax/swing/text/html/css/CSSScanner.java | 1 | ||||
-rw-r--r-- | gnu/javax/swing/text/html/css/Length.java | 7 | ||||
-rw-r--r-- | gnu/javax/swing/text/html/css/Selector.java | 233 |
5 files changed, 258 insertions, 8 deletions
diff --git a/gnu/javax/swing/text/html/css/CSSParser.java b/gnu/javax/swing/text/html/css/CSSParser.java index 190c93eb4..0d68457a3 100644 --- a/gnu/javax/swing/text/html/css/CSSParser.java +++ b/gnu/javax/swing/text/html/css/CSSParser.java @@ -39,6 +39,8 @@ exception statement from your version. */ package gnu.javax.swing.text.html.css; import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -156,7 +158,7 @@ public class CSSParser { StringBuilder selector = new StringBuilder(); parseSelector(selector); - callback.startStatement(selector.toString()); + callback.startStatement(new Selector(selector.toString())); // Read any number of whitespace. int token; do @@ -296,7 +298,9 @@ public class CSSParser throws IOException { // FIXME: Handle block and ATKEYWORD. - return parseAny(s); + boolean success = parseAny(s); + while (parseAny(s)); + return success; } /** @@ -439,13 +443,22 @@ public class CSSParser { try { - String name = "/javax/swing/text/html/default.css"; - InputStream in = CSSScanner.class.getResourceAsStream(name); + InputStream in; + if (args.length > 0) + { + File file = new File(args[0]); + in = new FileInputStream(file); + } + else + { + String name = "/javax/swing/text/html/default.css"; + in = CSSScanner.class.getResourceAsStream(name); + } BufferedInputStream bin = new BufferedInputStream(in); InputStreamReader r = new InputStreamReader(bin); CSSParserCallback cb = new CSSParserCallback() { - public void startStatement(String selector) + public void startStatement(Selector selector) { System.out.println("startStatement: " + selector); } diff --git a/gnu/javax/swing/text/html/css/CSSParserCallback.java b/gnu/javax/swing/text/html/css/CSSParserCallback.java index 60dc5488a..b62baddfc 100644 --- a/gnu/javax/swing/text/html/css/CSSParserCallback.java +++ b/gnu/javax/swing/text/html/css/CSSParserCallback.java @@ -62,7 +62,7 @@ public interface CSSParserCallback * * @param selector the selector of the statement. */ - void startStatement(String selector); + void startStatement(Selector selector); /** * Signals the end of a statement. diff --git a/gnu/javax/swing/text/html/css/CSSScanner.java b/gnu/javax/swing/text/html/css/CSSScanner.java index a402b9522..9cc6209a5 100644 --- a/gnu/javax/swing/text/html/css/CSSScanner.java +++ b/gnu/javax/swing/text/html/css/CSSScanner.java @@ -509,6 +509,7 @@ class CSSScanner { parseBuffer[tokenEnd] = (char) ch; tokenEnd++; + ch = read(); } // Push back last read character since it doesn't belong to the IDENT. diff --git a/gnu/javax/swing/text/html/css/Length.java b/gnu/javax/swing/text/html/css/Length.java index 1c0e0b2a1..11338d9f6 100644 --- a/gnu/javax/swing/text/html/css/Length.java +++ b/gnu/javax/swing/text/html/css/Length.java @@ -108,9 +108,12 @@ public class Length * * @return the absolute span */ - public float getValue(float span) + public float getValue(float available) { - return span * floatValue; + float span = floatValue; + if (isPercentage) + span *= available; + return span; } /** diff --git a/gnu/javax/swing/text/html/css/Selector.java b/gnu/javax/swing/text/html/css/Selector.java new file mode 100644 index 000000000..75f2d46c6 --- /dev/null +++ b/gnu/javax/swing/text/html/css/Selector.java @@ -0,0 +1,233 @@ +/* Selector.java -- A CSS selector + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.util.StringTokenizer; + +/** + * A CSS selector. This provides methods to interpret a selector and + * query matches with an actual HTML element tree. + */ +public class Selector +{ + + /** + * The actual selector. The selector tokens are stored backwards, that + * is the last token first. This makes matching easier. + */ + private String[] selector; + + private String[] elements; + private String[] ids; + private String[] classes; + + /** + * The specificity of the selector. + */ + private int specificity; + + /** + * An implicit selector has true here. This is the case for CSS rules that + * are attached to HTML elements directly via style="<CSS rule>". + */ + private boolean implicit; + + /** + * Creates a new Selector instance for the specified selector string. + * + * @param sel the selector + */ + public Selector(String sel) + { + StringTokenizer selectorTokens = new StringTokenizer(sel, " "); + selector = new String[selectorTokens.countTokens()]; + for (int i = selector.length - 1; selectorTokens.hasMoreTokens(); i--) + { + selector[i] = selectorTokens.nextToken(); + } + calculateSpecificity(); + } + + /** + * Determines if this selector matches the element path specified in the + * arguments. The arguments hold the element names as well as class + * and id attibutes of the HTML element to be queried. The first item + * in the array is the deepest element and the last on the highest up (for + * instance, the html tag). + * + * @param tags + * @param classes + * @param ids + * + * @return <code>true</code> when this selector matches the element path, + * <code>false</code> otherwise + */ + public boolean matches(String[] tags, String[] pathClasses, String[] pathIds) + { + // TODO: This implements class, id and descendent matching. These are + // the most commonly used selector matchers in CSS together with HTML. + // However, the CSS spec defines a couple of more sophisticated matches + // which should be implemented. + // http://www.w3.org/TR/CSS21/selector.html + + // All parts of the selector must match at some point. + boolean match = false; + int numTags = tags.length; + int numSel = selector.length; + if (numSel <= numTags) + { + match = true; + int tagIndex = 0; + for (int j = 0; j < numSel && match; j++) + { + boolean tagMatch = false; + for (; tagIndex < numTags && tagMatch == false; tagIndex++) + { + String tag = elements[j]; + String clazz = classes[j]; + String id = ids[j]; + tagMatch = tag.equals("") || tag.equals("*") + || tag.equals(tags[tagIndex]); + tagMatch = tagMatch && (clazz.equals("*") + || clazz.equals(pathClasses[tagIndex])); + tagMatch = tagMatch && (id.equals("*") + || id.equals(pathIds[tagIndex])); + // For the last element in the selector we must not look + // further. + if (j == 0) + break; + } + // If we don't come out here with a matching tag, then we're + // not matching at all. + match = tagMatch; + } + } + return match; + } + + /** + * Returns the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + * + * @return the specificity of the selector + */ + public int getSpecificity() + { + return specificity; + } + + /** + * Returns a string representation of the selector. This tries to reconstruct + * the original selector as closely as possible. + * + * @return a string representation of the selector + */ + public String toString() + { + StringBuilder b = new StringBuilder(); + for (int i = selector.length - 1; i >= 0; i--) + { + b.append(selector[i]); + if (i > 0) + b.append(' '); + } + return b.toString(); + } + + /** + * Calculates the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + */ + private void calculateSpecificity() + { + int a = implicit ? 1 : 0; + int b = 0; + int c = 0; + int d = 0; + int numSel = selector.length; + elements = new String[numSel]; + ids = new String[numSel]; + classes = new String[numSel]; + for (int i = 0; i < numSel; i++) + { + String sel = selector[i]; + int clazzIndex = sel.indexOf('.'); + int idIndex = sel.indexOf('#'); + String clazz; + if (clazzIndex == -1) + { + clazz = "*"; + clazzIndex = sel.length(); + } + else + { + c++; + clazz = sel.substring(clazzIndex + 1, + idIndex > 0 ? Math.min(idIndex, sel.length()) + : sel.length()); + } + String id; + if (idIndex == -1) + { + id = "*"; + idIndex = sel.length(); + } + else + { + b++; + id = sel.substring(idIndex + 1, + clazzIndex > 0 ? Math.min(idIndex, sel.length()) + : sel.length()); + } + String tag = sel.substring(0, + Math.min(Math.min(clazzIndex, idIndex), + sel.length())); + if (! tag.equals("") && ! tag.equals("*")) + d++; + + elements[i] = tag; + ids[i] = id; + classes[i] = clazz; + } + // An order of 20 should be enough for everybody. + specificity = a * 20 ^ 3 + b * 20 ^ 2 + c * 20 + d; + } +} |