summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorRoman Kennke <roman@kennke.org>2006-11-09 16:31:30 +0000
committerRoman Kennke <roman@kennke.org>2006-11-09 16:31:30 +0000
commit5456c3fe1d4cc61ef4264d3cb1aa804272d38bb5 (patch)
treee66f730388a3b1d9f0175abc0efeee3a325a6040 /gnu
parente38b7787ddcc8d6fed61f7bc7a7f95bcbfe20ab8 (diff)
downloadclasspath-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.java23
-rw-r--r--gnu/javax/swing/text/html/css/CSSParserCallback.java2
-rw-r--r--gnu/javax/swing/text/html/css/CSSScanner.java1
-rw-r--r--gnu/javax/swing/text/html/css/Length.java7
-rw-r--r--gnu/javax/swing/text/html/css/Selector.java233
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;
+ }
+}