diff options
Diffstat (limited to 'libjava/classpath/gnu/javax/swing/text/html/css')
13 files changed, 2701 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java new file mode 100644 index 000000000..3ccd38491 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java @@ -0,0 +1,64 @@ +/* BorderStyle.java -- Utility for dealing with border styles + 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; + +/** + * Utility class for handling border styles. + */ +public class BorderStyle +{ + + /** + * Determines if a given value makes up a valid border style value. + * + * @param value the value to check + * + * @return <code>true</code> when this is a valid border style, + * <code>false</code> otherwise + */ + public static boolean isValidStyle(String value) + { + return value.equals("none") || value.equals("hidden") + || value.equals("dotted") || value.equals("dashed") + || value.equals("solid") || value.equals("double") + || value.equals("groove") || value.equals("ridge") + || value.equals("inset") || value.equals("outset"); + + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java new file mode 100644 index 000000000..ae64c2110 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java @@ -0,0 +1,78 @@ +/* BorderWidth.java -- A CSS metric for border widths + 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; + +/** + * A special CSS metric for border widths. It basically understands everything + * as Length, and in addition to that provides a mapping for the border-width's + * thin, medium and think values. + */ +public class BorderWidth + extends Length +{ + + /** + * Creates a new BorderWidth instance. + * + * @param val the CSS value to be interpreted + */ + public BorderWidth(String val) + { + super(val); + if (val.equals("thin")) + floatValue = 1.F; + else if (val.equals("medium")) + floatValue = 2.F; + else if (val.equals("thick")) + floatValue = 3.F; + } + + /** + * Checks if the specified value makes up a valid border-width value. + * + * @param value the value to check + * + * @return <code>true</code> if the value is a valid border-width + */ + public static boolean isValid(String value) + { + return value.equals("thin") || value.equals("medium") + || value.equals("thick") || Length.isValid(value); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java new file mode 100644 index 000000000..ea4b94ae0 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java @@ -0,0 +1,170 @@ +/* CSSColor.java -- Converts CSS color values + 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.awt.Color; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + +/** + * Converts CSS color values into AWT Color values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CSSColor +{ + + private static final HashMap COLOR_MAP; + static + { + COLOR_MAP = new HashMap(); + COLOR_MAP.put("maroon", "#800000"); + COLOR_MAP.put("red", "#ff0000"); + COLOR_MAP.put("orange", "#ffa500"); + COLOR_MAP.put("yellow", "#ffff00"); + COLOR_MAP.put("olive", "#808000"); + COLOR_MAP.put("purple", "#800080"); + COLOR_MAP.put("fuchsia", "#ff00ff"); + COLOR_MAP.put("white", "#ffffff"); + COLOR_MAP.put("lime", "#00ff00"); + COLOR_MAP.put("green", "#008000"); + COLOR_MAP.put("navy", "#000080"); + COLOR_MAP.put("blue", "#0000ff"); + COLOR_MAP.put("aqua", "#00ffff"); + COLOR_MAP.put("teal", "#008080"); + COLOR_MAP.put("black", "#000000"); + COLOR_MAP.put("silver", "#c0c0c0"); + COLOR_MAP.put("gray", "#808080"); + } + + /** + * The CSS value. + */ + private String value; + + /** + * The converted color. + */ + private Color color; + + /** + * Creates a new instance. + * + * @param val the CSS value + */ + public CSSColor(String val) + { + value = val; + color = convertValue(value); + } + + /** + * Converts a CSS color value to an AWT color. + * + * @param value the CSS color value + * + * @return the converted color value + */ + public static Color convertValue(String value) + { + Color color; + String val1 = value.toLowerCase(); + if (val1.charAt(0) != '#') + val1 = (String) COLOR_MAP.get(val1); + if (val1 != null) + { + String hexVal = val1.substring(1).trim(); + try + { + int rgb = Integer.parseInt(hexVal, 16); + color = new Color(rgb); + } + catch (NumberFormatException ex) + { + color = Color.BLACK; + } + } + else + color = null; + return color; + } + + /** + * Returns the converted color. + * + * @return the converted color + */ + public Color getValue() + { + return color; + } + + public String toString() + { + return value; + } + + /** + * Returns <code>true</code> if the specified value is a valid color value, + * <code>false</code> otherwise. + * + * @param val the value to check + * + * @return <code>true</code> if the specified value is a valid color value, + * <code>false</code> otherwise + */ + public static boolean isValidColor(String val) + { + boolean ret = false; + if (val.charAt(0) == '#') + ret = true; + else + { + Set colors = COLOR_MAP.keySet(); + for (Iterator i = colors.iterator(); i.hasNext() && ret == false;) + { + String color = (String) i.next(); + if (color.equalsIgnoreCase(val)) + ret = true; + } + } + return ret; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java new file mode 100644 index 000000000..13968e4d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java @@ -0,0 +1,60 @@ +/* CSSLexicalException.java -- Indicates a failure in the lexical analyser + 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.io.IOException; + +/** + * Indicates a failure in the lexical analyser of the CSS parser. + */ +public class CSSLexicalException + extends IOException +{ + + public CSSLexicalException() + { + super(); + } + + public CSSLexicalException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java new file mode 100644 index 000000000..4be315e37 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java @@ -0,0 +1,503 @@ +/* CSSParser.java -- A parser for CSS stylesheets + 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.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.StringTokenizer; + +/** + * A parser for CSS stylesheets. + * + * This parser is based on the simple CSS grammar describe in + * + * http://www.w3.org/TR/CSS21/syndata.html . + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe use more restrictive grammar: +// http://www.w3.org/TR/CSS21/grammar.html#q1 +public class CSSParser +{ + + /** + * The scanner used to read the input streams into more usable tokens. + */ + private CSSScanner scanner; + + /** + * The parser callback. + */ + private CSSParserCallback callback; + + /** + * One lookahead token. + */ + private int lookahead; + + /** + * The parse error. + */ + private String error; + + /** + * Creates a new CSSParser that parses the specified input. + * + * @param in the source to parse + */ + public CSSParser(Reader in, CSSParserCallback cb) + { + scanner = new CSSScanner(in); + callback = cb; + lookahead = -1; + } + + /** + * Parses the input source specified in the constructor. + * + * @throws IOException if an IO or parse error occurs + */ + public void parse() + throws IOException + { + boolean success = parseStylesheet(); + if (! success) + { + throw new CSSParserException(error); + } + } + + /** + * Parses a stylesheet. + * + * @return <code>true</code> if the stylesheet could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseStylesheet() + throws IOException + { + int token = peekToken(); + while (token != CSSScanner.EOF && (token == CSSScanner.CDC + || token == CSSScanner.CDO || token == CSSScanner.S + || parseStatement())) + { + if (token == CSSScanner.CDC || token == CSSScanner.CDO + || token == CSSScanner.S) + readToken(); + token = peekToken(); + } + // Last token must be EOF for valid stylesheets, I'd think. + return token == CSSScanner.EOF; + } + + /** + * Parses a CSS statement. + * @return <code>true</code> if the stylesheet could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseStatement() + throws IOException + { + return parseRuleset() || parseAtRule(); + } + + /** + * Parses a CSS rule set. + * + * @return <code>true</code> if the ruleset could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseRuleset() + throws IOException + { + StringBuilder selector = new StringBuilder(); + parseSelector(selector); + StringTokenizer selSplitter = + new StringTokenizer(selector.toString(), ","); + Selector[] sels = new Selector[selSplitter.countTokens()]; + for (int i = 0; selSplitter.hasMoreTokens(); i++) + { + String sel = selSplitter.nextToken().trim(); + sels[i] = new Selector(sel); + } + callback.startStatement(sels); + // Read any number of whitespace. + int token; + do + { + token = readToken(); + } while (token == CSSScanner.S); + boolean ret = true; + + if (token == CSSScanner.CURLY_LEFT) + { + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + // Maybe read declaration. + boolean decl = parseDeclaration(); + token = peekToken(); + while (token == CSSScanner.SEMICOLON) + { + readToken(); // Read the semicolon. + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + // Maybe read declaration. + parseDeclaration(); + token = peekToken(); + } + if (token != CSSScanner.CURLY_RIGHT) + { + error = "Expected right curly brace"; + ret = false; + } + else + { + readToken(); + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + callback.endStatement(); + } + } + else + { + ret = false; + error = "Expected left curly brace"; + } + return ret; + } + + /** + * Parses a CSS declaration. + * + * @return <code>true</code> if the ruleset could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseDeclaration() + throws IOException + { + // Maybe fetch one DELIM. + int token = readToken(); + if (token == CSSScanner.DELIM) + token = readToken(); + + boolean ret = true; + + // Parse property + String property = null; + if (token == CSSScanner.IDENT) + { + property = new String(scanner.parseBuffer, 0, scanner.tokenEnd); + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + + // Read ':'. + if (token == CSSScanner.DELIM && scanner.parseBuffer[0] == ':') + { + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + StringBuilder value = new StringBuilder(); + if (parseValue(value)) + { + callback.declaration(property, value.toString().trim()); + } + else + { + ret = false; + error = "Error while reading the property value"; + } + } + else + { + ret = false; + error = "Expected colon to separate property and value"; + } + + } + else + { + lookahead = token; + ret = false; + error = "Expected IDENT token for property"; + } + return ret; + } + + /** + * Parses a property value. + * + * @param s the string builder to read the value into + * + * @return <code>true</code> if the ruleset could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseValue(StringBuilder s) + throws IOException + { + // FIXME: Handle block and ATKEYWORD. + boolean success = parseAny(s); + while (parseAny(s)) + ; + + return success; + } + + /** + * Parses a selector. + * + * @param sel the string buffer to put the selector into + * + * @return <code>true</code> if the ruleset could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseSelector(StringBuilder sel) + throws IOException + { + // At least one any needs to be parsed. + boolean ret = parseAny(sel); + if (ret) + { + while (parseAny(sel)) + ; + } + return ret; + } + + /** + * Parses the any rule. If s is not null, then the contents of the + * tokens is appended verbatim. + * + * @param s the string builder to append to + * + * @return <code>true</code> if the ruleset could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseAny(StringBuilder s) + throws IOException + { + int token = peekToken(); + boolean ret = false; + if (token == CSSScanner.IDENT || token == CSSScanner.NUMBER + || token == CSSScanner.PERCENTAGE || token == CSSScanner.DIMENSION + || token == CSSScanner.STRING || token == CSSScanner.DELIM + || token == CSSScanner.URI || token == CSSScanner.HASH + || token == CSSScanner.UNICODE_RANGE || token == CSSScanner.INCLUDES + || token == CSSScanner.DASHMATCH) + { + if (s != null) + s.append(scanner.parseBuffer, 0, scanner.tokenEnd); + readToken(); + ret = true; + } + else if (token == CSSScanner.FUNCTION) + System.err.println("Implement parseAny for FUNCTION"); + else if (token == CSSScanner.PAREN_LEFT) + System.err.println("Implement parseAny for ("); + else if (token == CSSScanner.BRACE_LEFT) + System.err.println("Implement parseAny for ["); + + // Parse any following whitespace too. + token = peekToken(); + while (token == CSSScanner.S) + { + if (s != null) + s.append(scanner.parseBuffer, 0, scanner.tokenEnd); + readToken(); + token = peekToken(); + } + return ret; + } + + /** + * Parses a CSS at-rule. + * + * @return <code>true</code> if the at-rule could be parsed successfully, + * <code>false</code> otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseAtRule() + throws IOException + { + // FIXME: Implement. + return false; + } + + /** + * Reads the next token, and skips the comments. + * + * @return the next non-comment token + */ + private int readToken() + throws IOException + { + int token; + if (lookahead == -1) + { + do + { + token = scanner.nextToken(); + } while (token == CSSScanner.COMMENT); + } + else + { + token = lookahead; + lookahead = -1; + } + return token; + } + + /** + * Returns the next token to be read, without really reading it. The next + * call to readToken() will return the same token again. + * + * @return the next token to be read, without really reading it + */ + private int peekToken() + throws IOException + { + int token; + if (lookahead == -1) + { + do + { + token = scanner.nextToken(); + } while (token == CSSScanner.COMMENT); + lookahead = token; + } + else + token = lookahead; + return token; + } + + /** + * For testing, we read in the default.css in javax/swing/text/html + * + * @param args + */ + public static void main(String[] args) + { + try + { + 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(Selector[] selector) + { + System.out.print("startStatement: "); + for (int i = 0; i < selector.length; i++) + { + System.out.print(selector[i]); + if (i < selector.length - 1) + System.out.print(','); + else + System.out.println(); + } + } + public void endStatement() + { + System.out.println("endStatement"); + } + public void declaration(String property, String value) + { + System.out.println("declaration: " + property + ", " + value); + } + }; + CSSParser p = new CSSParser(r, cb); + p.parse(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java new file mode 100644 index 000000000..f49ffa232 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java @@ -0,0 +1,81 @@ +/* CSSParserCallback.java -- Callback for parsing CSS + 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; + +/** + * Defines the callback that is used by the CSSParser to notify the + * backend of the parsing process. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public interface CSSParserCallback +{ + + /** + * Signals the beginning of a statement. + * + * A CSS statement is build up like follows: + * <pre> + * <selector> { + * ... declarations... + * } + * </pre> + * + * After startStatement(), the callback will receive zero to n callbacks + * to declaration, followed by an endStatement() call. + * + * @param selector the selector of the statement. + */ + void startStatement(Selector[] selector); + + /** + * Signals the end of a statement. + */ + void endStatement(); + + /** + * Signals the parsing of one declaration, which defines a mapping + * from a property to a value. + * + * @param property the property + * @param value the value + */ + void declaration(String property, String value); + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java new file mode 100644 index 000000000..2328d5398 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java @@ -0,0 +1,62 @@ +/* CSSParserException.java -- The CSS parser exception + 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.io.IOException; + +/** + * This exception is raised when the CSS parser hits a syntax error. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CSSParserException + extends IOException +{ + + /** + * Creates a new CSSParserException. + * + * @param message the exception message + */ + public CSSParserException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java new file mode 100644 index 000000000..37d544641 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java @@ -0,0 +1,718 @@ +/* CSSScanner.java -- A parser for CSS stylesheets + 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.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +/** + * A tokenizer for CSS stylesheets. This is based on the scanner definition + * from: + * + * http://www.w3.org/TR/CSS21/syndata.html#tokenization + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe implement more restrictive scanner: +// http://www.w3.org/TR/CSS21/grammar.html#q2 +class CSSScanner +{ + + // The tokens. This list is taken from: + // http://www.w3.org/TR/CSS21/syndata.html#tokenization + static final int IDENT = 1; + static final int ATKEYWORD = 2; + static final int STRING = 3; + static final int INVALID = 4; + static final int HASH = 5; + static final int NUMBER = 6; + static final int PERCENTAGE = 7; + static final int DIMENSION = 8; + static final int URI = 9; + static final int UNICODE_RANGE = 10; + static final int CDO = 11; + static final int CDC = 12; + static final int SEMICOLON = 13; + static final int CURLY_LEFT = 14; + static final int CURLY_RIGHT = 15; + static final int PAREN_LEFT = 16; + static final int PAREN_RIGHT = 17; + static final int BRACE_LEFT = 16; + static final int BRACE_RIGHT = 17; + static final int S = 18; + static final int COMMENT = 19; + static final int FUNCTION = 20; + static final int INCLUDES = 21; + static final int DASHMATCH = 22; + static final int DELIM = 23; + + // Additional tokens defined for convenience. + static final int EOF = -1; + + /** + * The input source. + */ + private Reader in; + + /** + * The parse buffer. + */ + char[] parseBuffer; + + /** + * The end index in the parseBuffer of the current token. + */ + int tokenEnd; + + /** + * The lookahead 'buffer'. + */ + private int[] lookahead; + + CSSScanner(Reader r) + { + lookahead = new int[2]; + lookahead[0] = -1; + lookahead[1] = -1; + parseBuffer = new char[2048]; + in = r; + } + + /** + * Fetches the next token. The actual character data is in the parseBuffer + * afterwards with the tokenStart at index 0 and the tokenEnd field + * pointing to the end of the token. + * + * @return the next token + */ + int nextToken() + throws IOException + { + tokenEnd = 0; + int token = -1; + int next = read(); + if (next != -1) + { + switch (next) + { + case ';': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = SEMICOLON; + break; + case '{': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = CURLY_LEFT; + break; + case '}': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = CURLY_RIGHT; + break; + case '(': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = PAREN_LEFT; + break; + case ')': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = PAREN_RIGHT; + break; + case '[': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = BRACE_LEFT; + break; + case ']': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = BRACE_RIGHT; + break; + case '@': + parseBuffer[0] = (char) next; + tokenEnd = 1; + readIdent(); + token = ATKEYWORD; + break; + case '#': + parseBuffer[0] = (char) next; + tokenEnd = 1; + readName(); + token = HASH; + break; + case '\'': + case '"': + lookahead[0] = next; + readString(); + token = STRING; + break; + case ' ': + case '\t': + case '\r': + case '\n': + case '\f': + lookahead[0] = next; + readWhitespace(); + token = S; + break; + // FIXME: Detecting an URI involves several characters lookahead. +// case 'u': +// lookahead[0] = ch; +// readURI(); +// token = URI; +// break; + case '<': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + parseBuffer[2] = (char) read(); + parseBuffer[3] = (char) read(); + if (parseBuffer[1] == '!' && parseBuffer[2] == '-' + && parseBuffer[3] == '-') + { + token = CDO; + tokenEnd = 4; + } + else + throw new CSSLexicalException("expected CDO token"); + break; + case '/': + lookahead[0] = next; + readComment(); + token = COMMENT; + break; + case '~': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + if (parseBuffer[1] == '=') + token = INCLUDES; + else + throw new CSSLexicalException("expected INCLUDES token"); + break; + case '|': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + if (parseBuffer[1] == '=') + token = DASHMATCH; + else + throw new CSSLexicalException("expected DASHMATCH token"); + break; + case '-': + int ch2 = read(); + if (ch2 == '-') + { + int ch3 = read(); + if (ch3 == '>') + { + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) ch2; + parseBuffer[2] = (char) ch3; + tokenEnd = 3; + token = CDC; + } + else + throw new CSSLexicalException("expected CDC token"); + } + else + { + lookahead[0] = next; + lookahead[1] = ch2; + readIdent(); + int ch3 = read(); + if (ch3 == -1 || ch3 != '(') + { + lookahead[0] = ch3; + token = IDENT; + } + else + { + parseBuffer[tokenEnd] = (char) ch3; + tokenEnd++; + token = FUNCTION; + } + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + lookahead[0] = next; + readNum(); + int ch3 = read(); + if (ch3 == '%') + { + parseBuffer[tokenEnd] = (char) ch3; + tokenEnd++; + token = PERCENTAGE; + } + else if (ch3 == -1 || (! (ch3 == '_' + || (ch3 >= 'a' && ch3 <= 'z') + || (ch3 >= 'A' && ch3 <= 'Z') + || ch3 == '\\' || ch3 > 177))) + { + lookahead[0] = ch3; + token = NUMBER; + } + else + { + lookahead[0] = ch3; + readIdent(); + token = DIMENSION; + } + break; + default: + // Handle IDENT that don't begin with '-'. + if (next == '_' || (next >= 'a' && next <= 'z') + || (next >= 'A' && next <= 'Z') || next == '\\' || next > 177) + { + lookahead[0] = next; + readIdent(); + int ch4 = read(); + if (ch4 == -1 || ch4 != '(') + { + lookahead[0] = ch4; + token = IDENT; + } + else + { + parseBuffer[tokenEnd] = (char) ch4; + tokenEnd++; + token = FUNCTION; + } + } + else + { + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = DELIM; + } + break; + } + } + return token; + } + + String currentTokenString() + { + return new String(parseBuffer, 0, tokenEnd); + } + + /** + * Reads one character from the input stream or from the lookahead + * buffer, if it contains one character. + * + * @return the next character + * + * @throws IOException if problems occur on the input source + */ + private int read() + throws IOException + { + int ret; + if (lookahead[0] != -1) + { + ret = lookahead[0]; + lookahead[0] = -1; + } + else if (lookahead[1] != -1) + { + ret = lookahead[1]; + lookahead[1] = -1; + } + else + { + ret = in.read(); + } + return ret; + } + + /** + * Reads and identifier. + * + * @throws IOException if something goes wrong in the input source or if + * the lexical analyser fails to read an identifier + */ + private void readIdent() + throws IOException + { + int ch1 = read(); + // Read possibly leading '-'. + if (ch1 == '-') + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + ch1 = read(); + } + // What follows must be '_' or a-z or A-Z or nonascii (>177) or an + // escape. + if (ch1 == '_' || (ch1 >= 'a' && ch1 <= 'z') + || (ch1 >= 'A' && ch1 <= 'Z') || ch1 > 177) + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + } + else if (ch1 == '\\') + { + // Try to read an escape. + lookahead[0] = ch1; + readEscape(); + } + else + throw new CSSLexicalException("First character of identifier incorrect"); + + // Read any number of [_a-zA-Z0-9-] chars. + int ch = read(); + while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + + // Push back last read character since it doesn't belong to the IDENT. + lookahead[0] = ch; + } + + /** + * Reads an escape. + * + * @throws IOException if something goes wrong in the input source or if + * the lexical analyser fails to read an escape + */ + private void readEscape() + throws IOException + { + int ch = read(); + if (ch != -1 && ch == '\\') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) + { + // Read unicode escape. + // Zero to five 0-9a-f chars can follow. + int hexcount = 0; + ch = read(); + while (((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) + && hexcount < 5) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + hexcount++; + ch = read(); + } + // Now we can have a \r\n or any whitespace character following. + if (ch == '\r') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if (ch == '\n') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + { + lookahead[0] = ch; + } + } + else if (ch == ' ' || ch == '\n' || ch == '\f' || ch == '\t') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + { + lookahead[0] = ch; + } + } + else if (ch != '\n' && ch != '\r' && ch != '\f') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Can't read escape"); + } + else + throw new CSSLexicalException("Escape must start with '\\'"); + + } + + private void readName() + throws IOException + { + // Read first name character. + int ch = read(); + if (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Invalid name"); + + // Read any number (at least one) of [_a-zA-Z0-9-] chars. + ch = read(); + while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + + // Push back last read character since it doesn't belong to the IDENT. + lookahead[0] = ch; + } + + /** + * Reads in a string. + * + * @throws IOException + */ + private void readString() + throws IOException + { + int ch1 = read(); + if (ch1 != -1 && (ch1 == '\'' || ch1 == '\"')) + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + + // Read any number of chars until we hit another chc1 char. + // Reject newlines, except if prefixed with \. + int ch = read(); + while (ch != -1 && ch != ch1) + { + // Every non-newline and non-\ char should be ok. + if (ch != '\n' && ch != '\r' && ch != '\f' && ch != '\\') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + // Ok when followed by newline or as part of escape. + else if (ch == '\\') + { + int ch2 = read(); + if (ch2 == '\n' || ch2 == '\r') + { + parseBuffer[tokenEnd] = (char) ch; + parseBuffer[tokenEnd + 1] = (char) ch2; + tokenEnd += 2; + } + else + { + // Try to parse an escape. + lookahead[0] = ch; + lookahead[1] = ch2; + readEscape(); + } + } + else + throw new CSSLexicalException("Invalid string"); + + ch = read(); + } + if (ch != -1) + { + // Push the final char on the buffer. + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Unterminated string"); + } + else + throw new CSSLexicalException("Invalid string"); + } + + /** + * Reads a chunk of whitespace. + * + * @throws IOException + */ + private void readWhitespace() + throws IOException + { + int ch = read(); + while (ch != -1 && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' + || ch == '\f')) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + // Push back last character read. + lookahead[0] = ch; + + } + + private void readURI() + throws IOException + { + // FIXME: Implement. + } + + /** + * Reads a comment block. + * + * @throws IOException + */ + private void readComment() + throws IOException + { + // First we need a / and a * + int ch = read(); + if (ch != -1 && ch == '/') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if (ch != -1 && ch == '*') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + boolean finished = false; + int lastChar = ch; + ch = read(); + while (! finished && ch != -1) + { + if (lastChar == '*' && ch == '/') + finished = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + lastChar = ch; + ch = read(); + } + } + } + if (ch == -1) + throw new CSSLexicalException("Unterminated comment"); + + // Push back last character read. + lookahead[0] = ch; + } + + /** + * Reads a number. + * + * @throws IOException + */ + private void readNum() + throws IOException + { + boolean hadDot = false; + // First char must be number or . + int ch = read(); + if (ch != -1 && ((ch >= '0' && ch <= '9') || ch == '.')) + { + if (ch == '.') + hadDot = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + // Now read in any number of digits afterwards, and maybe one dot, + // if we hadn't one already. + ch = read(); + while (ch != -1 && ((ch >= '0' && ch <= '9') + || (ch == '.' && ! hadDot))) + { + if (ch == '.') + hadDot = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + } + else + throw new CSSLexicalException("Invalid number"); + + // Check if we haven't accidentally finished with a dot. + if (parseBuffer[tokenEnd - 1] == '.') + throw new CSSLexicalException("Invalid number"); + + // Push back last character read. + lookahead[0] = ch; + } + + /** + * For testing, we read in the default.css in javax/swing/text/html + * + * @param args + */ + public static void main(String[] args) + { + try + { + String name = "/javax/swing/text/html/default.css"; + InputStream in = CSSScanner.class.getResourceAsStream(name); + BufferedInputStream bin = new BufferedInputStream(in); + InputStreamReader r = new InputStreamReader(bin); + CSSScanner s = new CSSScanner(r); + int token; + do + { + token = s.nextToken(); + System.out.println("token: " + token + ": " + + s.currentTokenString()); + } while (token != -1); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java new file mode 100644 index 000000000..203eadc40 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java @@ -0,0 +1,273 @@ +/* FontSize.java -- Converts CSS font size values into real values + 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; + +/** + * Converts CSS font-size values into real (point) values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontSize +{ + + /** + * The CSS value. + */ + private String value; + + /** + * The actual font size. + */ + private int size; + + /** + * The index of one of the standard sizes that this font size maps to. + * This is -1 if this fontsize doesn't map to one of the standard sizes. + * + * @see #SCALE + */ + private int sizeIndex; + + /** + * True when this font size is relative. + */ + private boolean isRelative; + + /** + * The default size for 'medium' absolute size. The other absolute sizes + * are calculated from this. + */ + public static final int DEFAULT_FONT_SIZE = 12; + + /** + * The scaling factors relative to the medium size. Medium is at index 2. + */ + private static final double[] SCALE = {0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8 }; + + /** + * Creates a new FontSize for the specified value. + * + * @param val the value to convert + */ + public FontSize(String val) + { + value = val; + sizeIndex = -1; + isRelative = false; + size = mapValue(); + } + + /** + * Returns the font size value. + * + * @return the font size value + */ + public int getValue(int p) + { + if (isRelative) + mapRelative(p); + return size; + } + + public int getValue() + { + assert ! isRelative; + return size; + } + + /** + * Returns the converted real value in point. + * + * @return the converted real value in point + */ + private int mapValue() + { + int intVal; + if (value.contains("pt")) + intVal = mapPoints(); + else if (value.contains("px")) + intVal = mapPixels(); + else if (value.contains("em") || value.contains("%") + || value.contains("larger") || value.contains("smaller")) + { + intVal = -1; + isRelative = true; + } + else + intVal = mapAbsolute(); + return intVal; + } + + /** + * Maps point values ('XXXpt'). + * + * @return the real font size + */ + private int mapPoints() + { + int end = value.indexOf("pt"); + String number = value.substring(0, end); + int intVal = (int) Double.parseDouble(number); + return intVal; + } + + /** + * Maps pixel values ('XXXpx'). + * + * @return the real font size + */ + private int mapPixels() + { + int end = value.indexOf("px"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + int intVal = (int) Double.parseDouble(number); + return intVal; + } + catch (NumberFormatException ex) + { + return DEFAULT_FONT_SIZE; + } + } + + private int mapPercent(int par) + { + int end = value.indexOf("%"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + int intVal = (int) Double.parseDouble(number); + return intVal * par / 100; + } + catch (NumberFormatException ex) + { + System.err.println("couldn't map value: '" + value + "'"); + return DEFAULT_FONT_SIZE; + } + } + + private int mapEM(int par) + { + int end = value.indexOf("em"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + float factor = Float.parseFloat(number); + // FIXME: Should be relative to the parent element's size. + return (int) (factor * par); + } + catch (NumberFormatException ex) + { + return DEFAULT_FONT_SIZE; + } + } + + private int mapSmaller(int par) + { + return (int) (par * 0.9); + } + + private int mapLarger(int par) + { + return (int) (par * 0.9); + } + + /** + * Maps absolute font-size values. + * + * @return the real value + */ + private int mapAbsolute() + { + int index; + if (value.equals("xx-small") || value.equals("x-small")) + index = 0; + else if (value.equals("small")) + index = 1; + else if (value.equals("medium")) + index = 2; + else if (value.equals("large")) + index = 3; + else if (value.equals("x-large")) + index = 4; + else if (value.equals("xx-large")) + index = 5; + else + index = 2; + double scale = SCALE[index]; + // FIXME: Scale the real medium size of the document, rather than the + // constant here. + int intVal = (int) (scale * DEFAULT_FONT_SIZE); + sizeIndex = index; + return intVal; + } + + /** + * Returns the string representation. + */ + public String toString() + { + return value; + } + + private int mapRelative(int par) + { + if (value.indexOf('%') != -1) + size = mapPercent(par); + else if (value.indexOf("em") != -1) + size = mapEM(par); + else if (value.indexOf("larger") != -1) + size = mapLarger(par); + else if (value.indexOf("smaller") != -1) + size = mapSmaller(par); + return size; + } + + public boolean isRelative() + { + return isRelative; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java new file mode 100644 index 000000000..e52893193 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java @@ -0,0 +1,80 @@ +/* FontStyle.java -- Converts font-size CSS values + 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.awt.Font; + +/** + * Converts font-size CSS values to a form to be used by {@link java.awt.Font}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontStyle +{ + + /** + * The real value. + */ + private String value; + + /** + * Creates a new instance. + * + * @param val the CSS value + */ + public FontStyle(String val) + { + value = val; + } + + /** + * Returns the converted value. + * + * @return the converted value + */ + public int getValue() + { + int intVal; + if (value.equals("italic") || value.equals("oblique")) + intVal = Font.ITALIC; + else + intVal = Font.PLAIN; + return intVal; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java new file mode 100644 index 000000000..d338c6f55 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java @@ -0,0 +1,84 @@ +/* FontWeight.java -- Converts font-weight values + 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.awt.Font; + +/** + * Converts font-weight CSS values to the constants defined for + * {@link java.awt.Font} + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontWeight +{ + + /** + * The value to convert. + */ + private String value; + + /** + * Creates a new instance. + * + * @param val the value to convert + */ + public FontWeight(String val) + { + value = val; + } + + /** + * Returns the converted value. + * + * @return the converted value + */ + public int getValue() + { + int intVal; + if (value.equals("normal")) + intVal = Font.PLAIN; + else if (value.equals("bold")) + intVal = Font.BOLD; + else + // FIXME: Implement finer-grained weights. + intVal = Font.PLAIN; + return intVal; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Length.java b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java new file mode 100644 index 000000000..06fa36e3d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java @@ -0,0 +1,283 @@ +/* Length.java -- Converts CSS length values + 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; + +/** + * Converts CSS length values to usable length values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class Length +{ + + /** + * The original value. + */ + private String value; + + /** + * The converted value. + */ + protected float floatValue; + + /** + * Indicates when the value is a percentage value. + */ + private boolean isPercentage; + + /** + * Indicates a length value that is relative to the font size (em). + */ + private boolean isFontEMRelative; + + /** + * Indicates a length value that is relative to the font size (ex). + */ + private boolean isFontEXRelative; + + /** + * The EM base size. + */ + private float emBase; + + /** + * The EX base size. + */ + private float exBase; + + /** + * Creates a new length converter instance. + * + * @param val the CSS value + */ + public Length(String val) + { + isFontEMRelative = false; + isFontEXRelative = false; + isPercentage = false; + value = val; + int i = value.indexOf("px"); + int percent = value.indexOf("%"); + int em = value.indexOf("em"); + int ex = value.indexOf("ex"); + try + { + floatValue = 0.0F; + if (i != -1) + { + String sub = value.substring(0, i); + floatValue = Float.parseFloat(sub); + } + else if (percent != -1) + { + isPercentage = true; + String sub = value.substring(0, percent); + floatValue = Float.parseFloat(sub) / 100; + } + else if (em != -1) + { + isFontEMRelative = true; + String sub = value.substring(0, em); + floatValue = Float.parseFloat(sub); + } + else if (ex != -1) + { + isFontEXRelative = true; + String sub = value.substring(0, ex); + floatValue = Float.parseFloat(sub); + } + else + { + floatValue = Float.parseFloat(value); + } + } + catch (NumberFormatException exc) + { + // Don't let such small problems interrupt CSS parsing. + System.err.println("couldn't parse: " + val); + } + } + + /** + * Returns the value converted to pixels. + * + * @return the value converted to pixels + */ + public float getValue() + { + return floatValue; + } + + /** + * Returns the absolute span for the case when this length value is + * a relative value. + * + * @param base the base span + * + * @return the absolute span + */ + public float getValue(float base) + { + float span = floatValue; + if (isPercentage) + span *= base; + else if (isFontEMRelative) + span *= emBase; + else if (isFontEXRelative) + span *= exBase; + return span; + } + + /** + * Sets the font relative EM base. + * + * @param base the font relative EM base + */ + public void setEMBase(float base) + { + emBase = base; + } + + /** + * Sets the font relative EX base. + * + * @param base the font relative EX base + */ + public void setEXBase(float base) + { + exBase = base; + } + + /** + * Sets the font relative base values. + * + * @param emBase the EM base + * @param exBase the EX base + */ + public void setFontBases(float emBase, float exBase) + { + setEMBase(emBase); + setEXBase(exBase); + } + + /** + * Returns true when this length value is an em font relative value. In + * order to get correct results, you need the exBase property set up + * correctly. + * + * @return true when this length value is an ex font relative value + */ + public boolean isFontEMRelative() + { + return isFontEMRelative; + } + + /** + * Returns true when this length value is an ex font relative value. In + * order to get correct results, you need the emBase property set up + * correctly. + * + * @return true when this length value is an ex font relative value + */ + public boolean isFontEXRelative() + { + return isFontEXRelative; + } + + /** + * Returns <code>true</code> when the length value is a percentage + * value, <code>false</code> otherwise. + * + * @return <code>true</code> when the length value is a percentage + * value, <code>false</code> otherwise + */ + public boolean isPercentage() + { + return isPercentage; + } + + /** + * Checks if the specified value makes up a valid length value. + * + * @param value the value to check + * + * @return <code>true</code> if the value is a valid length + */ + public static boolean isValid(String value) + { + boolean isValid = true; + int px = value.indexOf("px"); + int em = value.indexOf("em"); + int ex = value.indexOf("ex"); + int pc = value.indexOf('%'); + try + { + if (px != -1) + { + Integer.parseInt(value.substring(0, px)); + } + else if (em != -1) + { + Integer.parseInt(value.substring(0, em)); + } + else if (ex != -1) + { + Integer.parseInt(value.substring(0, ex)); + } + else if (pc != -1) + { + Integer.parseInt(value.substring(0, ex)); + } + else + { + Integer.parseInt(value); + } + } + catch (NumberFormatException nfe) + { + isValid = false; + } + return isValid; + } + + public String toString() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java new file mode 100644 index 000000000..97e582194 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java @@ -0,0 +1,245 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +import java.util.List; +import java.util.Map; +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 + * + * @return <code>true</code> when this selector matches the element path, + * <code>false</code> otherwise + */ + public boolean matches(String[] tags, List<Map<String,String>> attributes) + { + // 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++) + { + Object pathClass = attributes.get(tagIndex).get("class"); + // Try pseudo class too. + Object pseudoClass = attributes.get(tagIndex).get("_pseudo"); + Object dynClass = attributes.get(tagIndex).get("_dynamic"); + Object pathId = attributes.get(tagIndex).get("id"); + 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(dynClass) + || clazz.equals(pseudoClass) + || clazz.equals(pathClass)); + tagMatch = tagMatch && (id.equals("*") + || id.equals(pathId)); + // 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() + { + CPStringBuilder b = new CPStringBuilder(); + 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('.'); + // Try pseudo class too. + if (clazzIndex == -1) + 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(clazzIndex, 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; + } +} |