After looking into StyleSheets quite a bit, I found we needed a CSSParser. This is not a public class, so it has been hard to implement with almost no documentation. It is partially implemented so far. I am still working on it.
2005-12-19 Lillian Angel <[EMAIL PROTECTED]> * javax/swing/text/html/BlockView.java (getStyleSheet): Implemented. * javax/swing/text/html/CSSParser.java: New private class, partially implemented. * javax/swing/text/html/HTMLEditorKit.java (createDefaultDocument): Fixed to create HTMLDocument with default style sheet. (getStyleSheet): Fixed to initialize style sheet if null. * javax/swing/text/html/StyleSheet.java (CssParser): New private inner class, partially implemented.
Index: javax/swing/text/html/BlockView.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/BlockView.java,v retrieving revision 1.2 diff -u -r1.2 BlockView.java --- javax/swing/text/html/BlockView.java 15 Dec 2005 19:20:07 -0000 1.2 +++ javax/swing/text/html/BlockView.java 20 Dec 2005 15:53:32 -0000 @@ -294,7 +294,8 @@ */ protected StyleSheet getStyleSheet() { - // FIXME: Not implemented properly. - return new StyleSheet(); + StyleSheet styleSheet = new StyleSheet(); + styleSheet.importStyleSheet(getClass().getResource(HTMLEditorKit.DEFAULT_CSS)); + return styleSheet; } } Index: javax/swing/text/html/CSSParser.java =================================================================== RCS file: javax/swing/text/html/CSSParser.java diff -N javax/swing/text/html/CSSParser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ javax/swing/text/html/CSSParser.java 20 Dec 2005 15:53:32 -0000 @@ -0,0 +1,512 @@ +/* CSSParser.java -- + Copyright (C) 2005 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 javax.swing.text.html; + +import java.io.*; + +/** + * Parses a CSS document. This works by way of a delegate that implements the + * CSSParserCallback interface. The delegate is notified of the following + * events: + * - Import statement: handleImport + * - Selectors handleSelector. This is invoked for each string. For example if + * the Reader contained p, bar , a {}, the delegate would be notified 4 times, + * for 'p,' 'bar' ',' and 'a'. + * - When a rule starts, startRule + * - Properties in the rule via the handleProperty. This + * is invoked one per property/value key, eg font size: foo;, would cause the + * delegate to be notified once with a value of 'font size'. + * - Values in the rule via the handleValue, this is notified for the total value. + * - When a rule ends, endRule + * + * @author Lillian Angel ([EMAIL PROTECTED]) + */ +class CSSParser +{ + + /** + * Receives all information about the CSS document structure while parsing it. + * The methods are invoked by parser. + */ + static interface CSSParserCallback + { + /** + * Handles the import statment in the document. + * + * @param imp - the import string + */ + public abstract void handleImport(String imp); + + /** + * Called when the start of a rule is encountered. + */ + public abstract void startRule(); + + /** + * Called when the end of a rule is encountered. + */ + public abstract void endRule(); + + /** + * Handles the selector of a rule. + * + * @param selector - the selector in the rule + */ + public abstract void handleSelector(String selector); + + /** + * Handles the properties in the document. + * + * @param property - the property in the document. + */ + public abstract void handleProperty(String property); + + /** + * Handles the values in the document. + * + * @param value - the value to handle. + */ + public abstract void handleValue(String value); + + } + + /** + * The identifier of the rule. + */ + private static final int IDENTIFIER = 1; + + /** + * The open bracket. + */ + private static final int BRACKET_OPEN = 2; + + /** + * The close bracket. + */ + private static final int BRACKET_CLOSE = 3; + + /** + * The open brace. + */ + private static final int BRACE_OPEN = 4; + + /** + * The close brace. + */ + private static final int BRACE_CLOSE = 5; + + /** + * The open parentheses. + */ + private static final int PAREN_OPEN = 6; + + /** + * The close parentheses. + */ + private static final int PAREN_CLOSE = 7; + + /** + * The end of the document. + */ + private static final int END = -1; + + /** + * The character mapping in the document. + */ + private static final char[] charMapping = null; // FIXME + + /** + * Set to true if one character has been read ahead. + */ + private boolean didPushChar; + + /** + * The read ahead character. + */ + private int pushedChar; + + /** + * Temporary place to hold identifiers. + */ + private StringBuffer unitBuffer; + + /** + * Used to indicate blocks. + */ + private int[] unitStack; + + /** + * Number of valid blocks. + */ + private int stackCount; + + /** + * Holds the incoming CSS rules. + */ + private Reader reader; + + /** + * Set to true when the first non @ rule is encountered. + */ + private boolean encounteredRuleSet; + + /** + * The call back used to parse. + */ + private CSSParser.CSSParserCallback callback; + + /** + * nextToken() inserts the string here. + */ + private char[] tokenBuffer; + + /** + * Current number of chars in tokenBufferLength. + */ + private int tokenBufferLength; + + /** + * Set to true if any whitespace is read. + */ + private boolean readWS; + + /** + * Constructor + */ + CSSParser() + { + unitBuffer = new StringBuffer(); + } + + /** + * Appends a character to the token buffer. + * + * @param c - the character to append + */ + private void append(char c) + { + char[] temp = new char[tokenBufferLength + 1]; + if (tokenBuffer != null) + System.arraycopy(tokenBuffer, 0, temp, 0, tokenBufferLength); + temp[tokenBufferLength] = c; + tokenBufferLength++; + tokenBuffer = temp; + } + + /** + * Fetches the next token. + * + * @param c - the character to fetch. + * @return the location + * @throws IOException - any i/o error encountered while reading + */ + private int nextToken(char c) throws IOException + { + readWS = false; + int next = readWS(); + + switch (next) + { + case '\"': + // FIXME: Not Implemented + return IDENTIFIER; + case '\'': + // FIXME: Not Implemented + return IDENTIFIER; + case '(': + return PAREN_OPEN; + case ')': + return PAREN_CLOSE; + case '{': + return BRACE_OPEN; + case '}': + return BRACE_CLOSE; + case '[': + return BRACKET_OPEN; + case ']': + return BRACKET_CLOSE; + case -1: + return END; + default: + pushChar(next); + getIdentifier(c); + return IDENTIFIER; + } + } + + /** + * Reads a character from the stream. + * + * @return the number of characters read or -1 if end of stream is reached. + * @throws IOException - any i/o encountered while reading + */ + private int readChar() throws IOException + { + if (didPushChar) + { + didPushChar = false; + return pushedChar; + } + return reader.read(); + } + + /** + * Parses the the contents of the reader using the + * callback. + * + * @param reader - the reader to read from + * @param callback - the callback instance + * @param parsingDeclaration - true if parsing a declaration + * @throws IOException - any i/o error from the reader + */ + void parse(Reader reader, CSSParser.CSSParserCallback callback, + boolean parsingDeclaration) + throws IOException + { + this.reader = reader; + this.callback = callback; + // call getNextStatement + // FIXME: Not fully implemented + } + + /** + * Skips any white space, returning the character after the white space. + * + * @return the character after the whitespace + * @throws IOException - any i/o error from the reader + */ + private int readWS() throws IOException + { + int next = readChar(); + while (Character.isWhitespace((char) next)) + { + readWS = true; + int tempNext = readChar(); + if (tempNext == END) + return next; + next = tempNext; + } + + // Its all whitespace + return END; + } + + /** + * Gets the next statement, returning false if the end is reached. + * A statement is either an @ rule, or a ruleset. + * + * @return the next statement + * @throws IOException - any i/o error from the reader + */ + private boolean getNextStatement() throws IOException + { + // get next set and parseRuleSet + // FIXME: Not implemented + return false; + } + + /** + * Parses an @ rule, stopping at a matching brace pair, or ;. + * + * @throws IOException - any i/o error from the reader + */ + private void parseAtRule() throws IOException + { + // FIXME: Not Implemented + } + + /** + * Parses the next rule set, which is a selector followed by a declaration + * block. + * + * @throws IOException - any i/o error from the reader + */ + private void parseRuleSet() throws IOException + { + // call parseDeclarationBlock + // FIXME: Not Implemented + } + + /** + * Parses a set of selectors, returning false if the end of the stream is + * reached. + * + * @return false if the end of stream is reached + * @throws IOException - any i/o error from the reader + */ + private boolean parseSelectors() throws IOException + { + // FIXME: Not Implemented + return false; + } + + /** + * Parses a declaration block. Which a number of declarations followed by a + * })]. + * + * @throws IOException - any i/o error from the reader + */ + private void parseDeclarationBlock() throws IOException + { + // call parseDeclaration + // FIXME: Not Implemented + } + + /** + * Parses a single declaration, which is an identifier a : and another identifier. + * This returns the last token seen. + * + * @returns the last token + * @throws IOException - any i/o error from the reader + */ + private int parseDeclaration() throws IOException + { + // call handleValue + // FIXME: Not Implemented + return 0; + } + + /** + * Parses identifiers until c is encountered, returning the ending token, + * which will be IDENTIFIER if c is found. + * + * @param c - the stop character + * @param wantsBlocks - true if blocks are wanted + * @return the ending token + * @throws IOException - any i/o error from the reader + */ + private int parseIdentifiers(char c, boolean wantsBlocks) throws IOException + { + // FIXME: Not implemented + return 0; + } + + /** + * Parses till a matching block close is encountered. This is only appropriate + * to be called at the top level (no nesting). + * + * @param i - FIXME + * @throws IOException - any i/o error from the reader + */ + private void parseTillClosed(int i) throws IOException + { + // FIXME: Not Implemented + } + + /** + * Gets an identifier, returning true if the length of the string is greater + * than 0, stopping when c, whitespace, or one of {}()[] is hit. + * + * @param c - the stop character + * @return returns true if the length of the string > 0 + * @throws IOException - any i/o error from the reader + */ + private boolean getIdentifier(char c) throws IOException + { + // FIXME: Not Implemented + return false; + } + + /** + * Reads till c is encountered, escaping characters as necessary. + * + * @param c - the stop character + * @throws IOException - any i/o error from the reader + */ + private void readTill(char c) throws IOException + { + // FIXME: Not Implemented + } + + /** + * Parses a comment block. + * + * @throws IOException - any i/o error from the reader + */ + private void readComment() throws IOException + { + // FIXME: Not Implemented + } + + /** + * Called when a block start is encountered ({[. + * + * @param start of block + */ + private void startBlock(int start) + { + // FIXME: Not Implemented + } + + /** + * Called when an end block is encountered )]} + * + * @param end of block + */ + private void endBlock(int end) + { + // FIXME: Not Implemented + } + + /** + * Checks if currently in a block. + * + * @return true if currently in a block. + */ + private boolean inBlock() + { + // FIXME: Not Implemented + return false; + } + + /** + * Supports one character look ahead, this will throw if called twice in a row. + * + * @param c - the character to push. + * @throws IOException - if called twice in a row + */ + private void pushChar(int c) throws IOException + { + if (didPushChar) + throw new IOException("pushChar called twice."); + didPushChar = true; + pushedChar = c; + } +} + + Index: javax/swing/text/html/HTMLEditorKit.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLEditorKit.java,v retrieving revision 1.22 diff -u -r1.22 HTMLEditorKit.java --- javax/swing/text/html/HTMLEditorKit.java 19 Dec 2005 17:30:18 -0000 1.22 +++ javax/swing/text/html/HTMLEditorKit.java 20 Dec 2005 15:53:32 -0000 @@ -879,7 +879,7 @@ */ public Document createDefaultDocument() { - HTMLDocument document = new HTMLDocument(); + HTMLDocument document = new HTMLDocument(getStyleSheet()); document.setParser(getParser()); return document; } @@ -1152,7 +1152,10 @@ public StyleSheet getStyleSheet() { if (styleSheet == null) - styleSheet = new StyleSheet(); + { + styleSheet = new StyleSheet(); + styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); + } return styleSheet; } Index: javax/swing/text/html/StyleSheet.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/StyleSheet.java,v retrieving revision 1.3 diff -u -r1.3 StyleSheet.java --- javax/swing/text/html/StyleSheet.java 16 Dec 2005 21:35:06 -0000 1.3 +++ javax/swing/text/html/StyleSheet.java 20 Dec 2005 15:53:32 -0000 @@ -47,10 +47,13 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.Serializable; +import java.io.StringReader; +import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; +import java.util.Vector; import javax.swing.text.AttributeSet; import javax.swing.text.Element; @@ -137,6 +140,7 @@ */ public void addRule(String rule) { + // call cssparser.parse // FIXME: Not implemented. } @@ -168,6 +172,7 @@ public void loadRules(Reader in, URL ref) throws IOException { // FIXME: Not implemented. + // call parse } /** @@ -730,4 +735,204 @@ // FIXME: Not implemented. } } + + /** + * The parser callback for the CSSParser. + */ + class CssParser implements CSSParser.CSSParserCallback + { + /** + * A vector of all the selectors. + * Each element is an array of all the selector tokens + * in a single rule. + */ + Vector selectors; + + /** A vector of all the selector tokens in a rule. */ + Vector selectorTokens; + + /** Name of the current property. */ + String propertyName; + + /** The set of CSS declarations */ + MutableAttributeSet declaration; + + /** + * True if parsing a declaration, that is the Reader will not + * contain a selector. + */ + boolean parsingDeclaration; + + /** True if the attributes are coming from a linked/imported style. */ + boolean isLink; + + /** The base URL */ + URL base; + + /** The parser */ + CSSParser parser; + + /** + * Constructor + */ + CssParser() + { + selectors = new Vector(); + selectorTokens = new Vector(); + parser = new CSSParser(); + base = StyleSheet.this.base; + declaration = new SimpleAttributeSet(); + } + + /** + * Parses the passed in CSS declaration into an AttributeSet. + * + * @param s - the declaration + * @return the set of attributes containing the property and value. + */ + public AttributeSet parseDeclaration(String s) + { + try + { + return parseDeclaration(new StringReader(s)); + } + catch (IOException e) + { + // Do nothing here. + } + return null; + } + + /** + * Parses the passed in CSS declaration into an AttributeSet. + * + * @param r - the reader + * @return the attribute set + * @throws IOException from the reader + */ + public AttributeSet parseDeclaration(Reader r) throws IOException + { + parse(base, r, true, false); + return declaration; + } + + /** + * Parse the given CSS stream + * + * @param base - the url + * @param r - the reader + * @param parseDec - True if parsing a declaration + * @param isLink - True if parsing a link + */ + public void parse(URL base, Reader r, boolean parseDec, boolean isLink) throws IOException + { + parsingDeclaration = parseDec; + this.isLink = isLink; + this.base = base; + + // flush out all storage + propertyName = null; + selectors.clear(); + selectorTokens.clear(); + declaration.removeAttributes(declaration); + + parser.parse(r, this, parseDec); + } + + /** + * Invoked when a valid @import is encountered, + * will call importStyleSheet if a MalformedURLException + * is not thrown in creating the URL. + * + * @param s - the string after @import + */ + public void handleImport(String s) + { + if (s != null) + { + try + { + if (s.startsWith("url(") && s.endsWith(")")) + s = s.substring(4, s.length() - 1); + if (s.indexOf("\"") >= 0) + s = s.replaceAll("\"",""); + + URL url = new URL(s); + if (url == null && base != null) + url = new URL(base, s); + + importStyleSheet(url); + } + catch (MalformedURLException e) + { + // Do nothing here. + } + } + } + + /** + * A selector has been encountered. + * + * @param s - a selector (e.g. P or UL or even P,) + */ + public void handleSelector(String s) + { + if (s.endsWith(",")) + s = s.substring(0, s.length() - 1); + + selectorTokens.addElement(s); + addSelector(); + } + + /** + * Invoked when the start of a rule is encountered. + */ + public void startRule() + { + // FIXME: Not implemented + } + + /** + * Invoked when a property name is encountered. + * + * @param s - the property + */ + public void handleProperty(String s) + { + propertyName = s; + } + + /** + * Invoked when a property value is encountered. + * + * @param s - the value + */ + public void handleValue(String s) + { + // call addCSSAttribute + // FIXME: Not implemented + } + + /** + * Invoked when the end of a rule is encountered. + */ + public void endRule() + { + // FIXME: Not implemented + // add rules + } + + /** + * Adds the selector to the vector. + */ + private void addSelector() + { + Object[] selTokens = selectorTokens.toArray(); + int length = selTokens.length; + Object[] sel = new Object[length]; + System.arraycopy(selTokens, 0, sel, 0, length); + selectors.add(sel); + selectorTokens.clear(); + } + } }
_______________________________________________ Classpath-patches mailing list Classpath-patches@gnu.org http://lists.gnu.org/mailman/listinfo/classpath-patches