harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mloe...@apache.org
Subject svn commit: r427121 [8/29] - in /incubator/harmony/enhanced/classlib/trunk/modules/swing: make/ src/main/java/common/javax/swing/ src/main/java/common/javax/swing/text/ src/main/java/common/javax/swing/text/html/ src/main/java/common/javax/swing/text/h...
Date Mon, 31 Jul 2006 14:08:55 GMT
Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/NoFramesTagView.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/NoFramesTagView.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/NoFramesTagView.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/NoFramesTagView.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,67 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Vadim L. Bogdanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+import java.awt.Shape;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Position.Bias;
+
+import org.apache.harmony.awt.text.TextUtils;
+
+class NoFramesTagView extends BlockView {
+    public NoFramesTagView(final Element elem) {
+        super(elem, Y_AXIS);
+    }
+
+    public float getMinimumSpan(final int axis) {
+        return isTextComponentEditable() ? super.getMinimumSpan(axis) : 0f;
+    }
+
+    public float getPreferredSpan(final int axis) {
+        return isTextComponentEditable() ? super.getPreferredSpan(axis) : 0f;
+    }
+
+    public float getMaximumSpan(final int axis) {
+        return isTextComponentEditable() ? super.getMaximumSpan(axis) : 0f;
+    }
+
+    public Shape modelToView(final int pos, final Shape shape,
+                             final Bias bias) throws BadLocationException {
+        return isTextComponentEditable()
+            ? super.modelToView(pos, shape, bias)
+            : TextUtils.modelToIconOrComponentView(this, pos, shape, bias);
+    }
+
+    public int viewToModel(final float x,
+                           final float y,
+                           final Shape shape,
+                           final Bias[] biasReturn) {
+        return isTextComponentEditable()
+            ? super.viewToModel(x, y, shape, biasReturn)
+            : getStartOffset();
+    }
+
+    private boolean isTextComponentEditable() {
+        return ((JTextComponent)getContainer()).isEditable();
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ObjectView.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ObjectView.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ObjectView.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ObjectView.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,36 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexander T. Simbirtsev
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+import java.awt.Component;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+
+public class ObjectView extends ComponentView {
+    public ObjectView(final Element elem) {
+        super(elem);
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    protected Component createComponent() {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Option.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Option.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Option.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Option.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+import javax.swing.text.AttributeSet;
+
+public class Option {
+    private final AttributeSet attr;
+    private String label;
+    private boolean selected;
+
+    public Option(final AttributeSet attr) {
+        this.attr = attr.copyAttributes();
+        selected = this.attr.isDefined(HTML.Attribute.SELECTED);
+    }
+
+    public AttributeSet getAttributes() {
+        return attr;
+    }
+
+    public String getLabel() {
+        return label != null ? label : (String)getAttributes().getAttribute(HTML.Attribute.LABEL);
+    }
+
+    public String getValue() {
+        final String value = (String)getAttributes().getAttribute(HTML.Attribute.VALUE);
+        return value != null ? value : getLabel();
+    }
+
+    public boolean isSelected() {
+        return selected;
+    }
+
+    public void setLabel(final String label) {
+        this.label = label;
+    }
+
+    protected void setSelection(final boolean state) {
+        selected = state;
+    }
+
+    public String toString() {
+        return label;
+    }
+}
\ No newline at end of file

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ParagraphView.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ParagraphView.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ParagraphView.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/ParagraphView.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,193 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SizeRequirements;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.View;
+import javax.swing.text.html.StyleSheet.BoxPainter;
+
+public class ParagraphView extends javax.swing.text.ParagraphView {
+    private AttributeSet attrs;
+    private BoxPainter boxPainter;
+    private float xAlign;
+    private CSS.Length width;
+    private int effectiveWidth;
+
+    public ParagraphView(final Element elem) {
+        super(elem);
+    }
+
+    public float getMinimumSpan(final int axis) {
+        if (!isVisible()) {
+            return 0;
+        }
+        return super.getMinimumSpan(axis);
+    }
+
+    public float getPreferredSpan(final int axis) {
+        if (!isVisible()) {
+            return 0;
+        }
+        return super.getPreferredSpan(axis);
+    }
+
+    public float getMaximumSpan(final int axis) {
+        if (!isVisible()) {
+            return 0;
+        }
+        return super.getMaximumSpan(axis);
+    }
+
+    public AttributeSet getAttributes() {
+        return attrs;
+    }
+
+    public float getAlignment(final int axis) {
+        if (axis == X_AXIS) {
+            return xAlign;
+        }
+        return super.getAlignment(axis);
+    }
+
+    public void setParent(final View parent) {
+        super.setParent(parent);
+        if (parent != null) {
+            setPropertiesFromAttributes();
+        }
+    }
+
+    public boolean isVisible() {
+        final int count = getLayoutViewCount();
+        boolean result = false;
+        for (int i = 0; i < count && !result; i++) {
+            View child = getLayoutView(i);
+            result = child.getElement().getAttributes()
+                          .getAttribute(HTML.Attribute.IMPLIED_NEW_LINE) == null
+                     && child.isVisible();
+        }
+        return result;
+    }
+
+    public void setSize(final float width, final float height) {
+        if (effectiveWidth != calculateEffectiveWidth()) {
+            preferenceChanged(this, true, true);
+        }
+        super.setSize(width, height);
+    }
+
+    public void paint(final Graphics g, final Shape a) {
+        Rectangle rc = a.getBounds();
+        boxPainter.paint(g, rc.x, rc.y, rc.width, rc.height, this);
+
+        super.paint(g, a);
+    }
+
+    protected SizeRequirements
+        calculateMinorAxisRequirements(final int axis,
+                                       final SizeRequirements r) {
+        SizeRequirements result = super.calculateMinorAxisRequirements(axis, r);
+        result.minimum = getMinimumSpan();
+        effectiveWidth = calculateEffectiveWidth();
+        if (effectiveWidth > result.minimum) {
+            result.minimum   = effectiveWidth;
+            result.preferred = result.minimum;
+            result.maximum   = result.minimum;
+        }
+        return result;
+    }
+
+//    protected SizeRequirements
+//        calculateMajorAxisRequirements(final int axis,
+//                                       final SizeRequirements sr) {
+//
+//        SizeRequirements result = super.calculateMajorAxisRequirements(axis,
+//                                                                       sr);
+//        result.alignment = getAlign();
+//        return result;
+//    }
+
+    protected StyleSheet getStyleSheet() {
+        return ((HTMLDocument)getDocument()).getStyleSheet();
+    }
+
+    protected void setPropertiesFromAttributes() {
+        attrs = getStyleSheet().getViewAttributes(this);
+        super.setPropertiesFromAttributes();
+        boxPainter = getStyleSheet().getBoxPainter(getAttributes());
+        boxPainter.setView(this);
+        setInsets((short)boxPainter.getInset(TOP, this),
+                  (short)boxPainter.getInset(LEFT, this),
+                  (short)boxPainter.getInset(BOTTOM, this),
+                  (short)boxPainter.getInset(RIGHT, this));
+
+        xAlign = getAlign();
+        width = (CSS.Length)getAttributes().getAttribute(CSS.Attribute.WIDTH);
+    }
+
+    private int calculateEffectiveWidth() {
+        return width != null ? effectiveWidth = width.intValue(this) : 0;
+    }
+
+    private int getMinimumSpan() {
+        int result = 0;
+        final int count = getLayoutViewCount();
+        for (int i = 0; i < count; i++) {
+            View child = getLayoutView(i);
+            if (child instanceof InlineView) {
+                result = Math.max(result,
+                                  ((InlineView)child).getLongestWordSpan());
+            } else {
+                result = Math.max(result, (int)child.getMinimumSpan(X_AXIS));
+            }
+        }
+        return result;
+    }
+
+    private float getAlign() {
+        final View parent = getParent();
+        if (parent == null) {
+            return 0.0f;
+        }
+
+        CSS.TextAlign ta =
+            (CSS.TextAlign)parent.getAttributes()
+                           .getAttribute(CSS.Attribute.TEXT_ALIGN);
+        int textAlign = ta != null ? ((Integer)ta.fromCSS()).intValue()
+                                   : StyleConstants.ALIGN_LEFT;
+        switch (textAlign) {
+        case StyleConstants.ALIGN_LEFT:
+            return 0.0f;
+        case StyleConstants.ALIGN_CENTER:
+            return 0.5f;
+        case StyleConstants.ALIGN_RIGHT:
+            return 1.0f;
+        default:
+            return 0.0f;
+        }
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Selector.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Selector.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Selector.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Selector.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+final class Selector {
+    final SimpleSelector[] simpleSelectors;
+    final Specificity specificity;
+
+    Selector(final String complexSelector) {
+        String[] selectors = complexSelector.split("\\s+");
+        simpleSelectors = new SimpleSelector[selectors.length];
+        for (int i = 0; i < selectors.length; i++) {
+            simpleSelectors[i] = new SimpleSelector(selectors[i]);
+        }
+        specificity = new Specificity(this);
+    }
+
+    public String toString() {
+        final StringBuffer result = new StringBuffer();
+        result.append(simpleSelectors[0]);
+        for (int i = 1; i < simpleSelectors.length; i++) {
+            result.append(' ').append(simpleSelectors[i]);
+        }
+        return result.toString();
+    }
+
+    boolean applies(final Selector styleSelector) {
+        int ssIndex = styleSelector.simpleSelectors.length - 1;
+        int index = simpleSelectors.length - 1;
+
+        boolean result = false;
+        for (; ssIndex >= 0; ssIndex--) {
+            SimpleSelector simple = styleSelector.simpleSelectors[ssIndex];
+            result = false;
+            for (; index >= 0 && !result; index--) {
+                SimpleSelector ss = simpleSelectors[index];
+                if (simple.matches(ss.tag, ss.id, ss.clazz)) {
+                    result = true;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    SimpleSelector getLastSelector() {
+        return simpleSelectors[simpleSelectors.length - 1];
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SelectorMatcher.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SelectorMatcher.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SelectorMatcher.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SelectorMatcher.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,178 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+
+class SelectorMatcher {
+    static List findMatching(final Enumeration ruleNames,
+                             final Element element) {
+        List matched = new ArrayList();
+
+        SimpleSelector ruleLast;
+
+        while (ruleNames.hasMoreElements()) {
+            final String ruleName = (String)ruleNames.nextElement();
+            Selector rule = new Selector(ruleName);
+
+            int rIndex = rule.simpleSelectors.length - 1;
+            ruleLast = rule.simpleSelectors[rIndex];
+            if (ruleLast.matches(getTagName(element),
+                                 getID(element),
+                                 getClass(element))) {
+                boolean result = true;
+                Element current = element;
+                for (rIndex--; rIndex >= 0 && result && current != null;
+                     rIndex--) {
+
+                    ruleLast = rule.simpleSelectors[rIndex];
+                    current = current.getParentElement();
+                    while (current != null) {
+                        if (ruleLast.matches(getTagName(current),
+                                             getID(current),
+                                             getClass(current))) {
+                            break;
+                        }
+                        current = current.getParentElement();
+                    }
+                    result = current != null;
+                }
+
+                if (result) {
+                    matched.add(rule);
+                }
+            }
+        }
+        Collections.sort(matched, SpecificityComparator.compator);
+        return matched;
+    }
+
+    static List findMatching(final Enumeration ruleNames,
+                             final String sel) {
+        final List matched = new ArrayList();
+        final Selector selector = new Selector(sel);
+
+        SimpleSelector ruleLast;
+
+        while (ruleNames.hasMoreElements()) {
+            final String ruleName = (String)ruleNames.nextElement();
+            Selector rule = new Selector(ruleName);
+
+            int sIndex = selector.simpleSelectors.length - 1;
+            SimpleSelector last = selector.simpleSelectors[sIndex];
+
+            int rIndex = rule.simpleSelectors.length - 1;
+            ruleLast = rule.simpleSelectors[rIndex];
+            if (ruleLast.matches(last.tag,
+                                 last.id,
+                                 last.clazz)) {
+                boolean result = true;
+                for (rIndex--; rIndex >= 0 && result; rIndex--) {
+                    ruleLast = rule.simpleSelectors[rIndex];
+                    result = false;
+                    while (sIndex > 0 && !result) {
+                        SimpleSelector current =
+                            selector.simpleSelectors[--sIndex];
+                        result = ruleLast.matches(current.tag,
+                                                  current.id,
+                                                  current.clazz);
+                    }
+                }
+
+                if (result) {
+                    matched.add(rule);
+                }
+            }
+        }
+        Collections.sort(matched, SpecificityComparator.compator);
+        return matched;
+    }
+
+    static String getID(final Element element) {
+        return getID(getTag(element), element);
+    }
+
+    static String getID(final HTML.Tag tag, final Element element) {
+        if (element.isLeaf()) {
+            return getID((AttributeSet)element.getAttributes()
+                                       .getAttribute(tag));
+        }
+        return getID(element.getAttributes());
+    }
+
+    static String getID(final AttributeSet attr) {
+        return attr != null ? (String)attr.getAttribute(HTML.Attribute.ID)
+                            : null;
+    }
+
+
+    static String getClass(final Element element) {
+        return (String)element.getAttributes().getAttribute(HTML.Attribute.CLASS);
+    }
+
+    static String getClass(final HTML.Tag tag, final Element element) {
+        if (element.isLeaf()) {
+            return getClass((AttributeSet)element.getAttributes()
+                                          .getAttribute(tag));
+        }
+        return getClass(element.getAttributes());
+    }
+
+    static String getClass(final AttributeSet attr) {
+        return attr != null ? (String)attr.getAttribute(HTML.Attribute.CLASS)
+                            : null;
+    }
+
+
+    static HTML.Tag getTag(final Element element) {
+        return getTag(element.getAttributes());
+    }
+
+    static HTML.Tag getTag(final AttributeSet attr) {
+        Object name = attr.getAttribute(StyleConstants.NameAttribute);
+        if (name instanceof HTML.Tag && name != HTML.Tag.CONTENT) {
+            return (HTML.Tag)name;
+        }
+
+        Enumeration keys = attr.getAttributeNames();
+        while (keys.hasMoreElements()) {
+            Object key = keys.nextElement();
+            if (key instanceof HTML.Tag) {
+                return (HTML.Tag)key;
+            }
+        }
+        return null;
+    }
+
+    static String getTagName(final Element element) {
+        return getTag(element).toString();
+    }
+
+    static String getTagName(final AttributeSet attr) {
+        return getTag(attr).toString();
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SimpleSelector.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SimpleSelector.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SimpleSelector.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SimpleSelector.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,138 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+final class SimpleSelector {
+    final String tag;
+    final String id;
+    final String clazz;
+    final String pseudo;
+
+    SimpleSelector(final String selector) {
+        tag    = getTagName(selector);
+        id     = getID(selector);
+        clazz  = getClass(selector);
+        pseudo = getPseudo(selector);
+    }
+
+    public String toString() {
+        final StringBuffer result = new StringBuffer();
+        if (tag != null) {
+            result.append(tag);
+        }
+        if (id != null) {
+            result.append('#').append(id);
+        }
+        if (clazz != null) {
+            result.append('.').append(clazz);
+        }
+        if (pseudo != null) {
+            result.append(':').append(pseudo);
+        }
+        return result.toString();
+    }
+
+    static String getTagName(final String selector) {
+        String tag = selector.split("#|\\.|:")[0];
+        return tag.length() > 0 ? tag.toLowerCase() : null;
+    }
+
+    static String getID(final String selector) {
+        int hashIndex = selector.indexOf('#');
+        if (hashIndex < 0) {
+            return null;
+        }
+
+        return selector.substring(hashIndex + 1).split("\\.|:")[0];
+    }
+
+    static String getClass(final String selector) {
+        int dotIndex = selector.indexOf('.');
+        if (dotIndex < 0) {
+            return null;
+        }
+        return selector.substring(dotIndex + 1).split(":")[0];
+    }
+
+    static String getPseudo(final String selector) {
+        int colonIndex = selector.indexOf(':');
+        if (colonIndex < 0) {
+            return null;
+        }
+        return selector.substring(colonIndex + 1)/*.split(":")[0]*/;
+    }
+
+    public boolean matches(final SimpleSelector another) {
+        return matches(another.tag, another.id, another.clazz);
+    }
+
+    public boolean matches(final String eName, final String eID, final String eClass) {
+        if (id != null) {
+            if (eID == null) {
+                return false;
+            }
+            if (!id.equals(eID)) {
+                return false;
+            }
+        }
+
+        if (clazz != null) {
+            if (eClass == null) {
+                return false;
+            }
+            if (!clazz.equals(eClass)) {
+                return false;
+            }
+        }
+
+        if (tag != null) {
+            if (eName == null) {
+                return false;
+            }
+            if (!tag.equals(eName)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public boolean applies(final SimpleSelector another) {
+        return applies(another.tag, another.id, another.clazz);
+    }
+
+    public boolean applies(final String eName,
+                           final String eID,
+                           final String eClass) {
+        if (id != null && eID != null && !id.equals(eID)) {
+            return false;
+        }
+
+        if (clazz != null && eClass != null && !clazz.equals(eClass)) {
+            return false;
+        }
+
+        if (tag != null && eName != null && !tag.equals(eName)) {
+            return false;
+        }
+
+        return true;
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Specificity.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Specificity.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Specificity.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/Specificity.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,65 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+final class Specificity implements Comparable {
+    final int tags;
+    final int ids;
+    final int classes;
+
+    Specificity(final Selector selector) {
+        int tmpTags    = 0;
+        int tmpIDs     = 0;
+        int tmpClasses = 0;
+
+        for (int i = 0; i < selector.simpleSelectors.length; i++) {
+            if (selector.simpleSelectors[i].tag != null) {
+                ++tmpTags;
+            }
+            if (selector.simpleSelectors[i].id != null) {
+                ++tmpIDs;
+            }
+            if (selector.simpleSelectors[i].clazz != null) {
+                ++tmpClasses;
+            }
+        }
+
+        tags    = tmpTags;
+        ids     = tmpIDs;
+        classes = tmpClasses;
+    }
+
+    public int compareTo(final Object object) {
+        Specificity another = (Specificity)object;
+        int result = ids - another.ids;
+        if (result != 0) {
+            return result;
+        }
+        result = classes - another.classes;
+        if (result != 0) {
+            return result;
+        }
+        return tags - another.tags;
+    }
+
+    public String toString() {
+        return "" + ids + classes + tags;
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SpecificityComparator.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SpecificityComparator.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SpecificityComparator.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/SpecificityComparator.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+ */
+package javax.swing.text.html;
+
+import java.util.Comparator;
+
+final class SpecificityComparator implements Comparator {
+    public static final SpecificityComparator compator =
+        new SpecificityComparator();
+
+    private SpecificityComparator() {
+    }
+
+    public int compare(final Selector arg0, final Selector arg1) {
+        return -arg0.specificity.compareTo(arg1.specificity);
+    }
+
+    public int compare(final Object arg0, final Object arg1) {
+        return compare((Selector)arg0, (Selector)arg1);
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/StyleSheet.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/StyleSheet.java?rev=427121&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/StyleSheet.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/html/StyleSheet.java Mon Jul 31 07:08:47 2006
@@ -0,0 +1,1288 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexey A. Ivanov
+ * @version $Revision$
+*/
+package javax.swing.text.html;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Stroke;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import javax.swing.SwingUtilities;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.BoxView;
+import javax.swing.text.Element;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+import javax.swing.text.View;
+import javax.swing.text.html.CSS.Attribute;
+import javax.swing.text.html.CSS.BorderColor;
+import javax.swing.text.html.CSS.BorderStyle;
+import javax.swing.text.html.CSS.ColorProperty;
+import javax.swing.text.html.CSS.PropertyValueConverter;
+import javax.swing.text.html.CSS.ShorthandPropertyExpander;
+import javax.swing.text.html.CSS.TextDecoration;
+import javax.swing.text.html.CSS.ViewUpdater;
+
+import org.apache.harmony.x.swing.Utilities;
+import org.apache.harmony.x.swing.text.html.cssparser.CSSParser;
+import org.apache.harmony.x.swing.text.html.cssparser.ParseException;
+import org.apache.harmony.x.swing.text.html.cssparser.metamodel.Property;
+import org.apache.harmony.x.swing.text.html.cssparser.metamodel.RuleSet;
+import org.apache.harmony.x.swing.text.html.cssparser.metamodel.Sheet;
+
+/**
+ * Implementation of this class is based on <a href="http://www.w3.org/TR/CSS1">CSS1</a>.
+ */
+public class StyleSheet extends StyleContext {
+
+    public static class BoxPainter implements Serializable {
+        private static final CSS.Attribute[] MARGIN_KEYS = new CSS.Attribute[] {
+            CSS.Attribute.MARGIN_TOP,    CSS.Attribute.MARGIN_RIGHT,
+            CSS.Attribute.MARGIN_BOTTOM, CSS.Attribute.MARGIN_LEFT
+        };
+        private static final CSS.Attribute[] PADDING_KEYS = new CSS.Attribute[] {
+            CSS.Attribute.PADDING_TOP,    CSS.Attribute.PADDING_RIGHT,
+            CSS.Attribute.PADDING_BOTTOM, CSS.Attribute.PADDING_LEFT
+        };
+        private static final CSS.Attribute[] BORDER_WIDTH_KEYS =
+            new CSS.Attribute[] {
+                CSS.Attribute.BORDER_TOP_WIDTH,
+                CSS.Attribute.BORDER_RIGHT_WIDTH,
+                CSS.Attribute.BORDER_BOTTOM_WIDTH,
+                CSS.Attribute.BORDER_LEFT_WIDTH
+            };
+
+        private View view;
+        private final AttributeSet attr;
+        private final StyleSheet styleSheet;
+
+        private final float[] margin = new float[4];
+        private final float[] borderWidth = new float[4];
+
+        private CSS.BorderStyle borderStyle;
+        private CSS.BorderColor borderColor;
+        private CSS.ColorProperty backgroundColor;
+        private CSS.ImageValue backgroundImage;
+        private CSS.BackgroundRepeat backgroundRepeat;
+        private Color foreground;
+        private ViewUpdater updater;
+        private boolean isTableBoxPainter;
+
+        private BoxPainter(final AttributeSet attr,
+                           final StyleSheet styleSheet) {
+            this.attr = attr;
+            this.styleSheet = styleSheet;
+        }
+
+        public float getInset(final int side, final View v) {
+            final int sideIndex = getSideIndex(side);
+            CSS.Length length =
+                (CSS.Length)v.getAttributes()
+                            .getAttribute(PADDING_KEYS[sideIndex]);
+            return margin[sideIndex]
+                   + (length != null ? length.floatValue(v) : 0)
+                   + getBorderSideWidth(sideIndex, v);
+        }
+
+        public void paint(final Graphics g, final float x, final float y,
+                          final float w, final float h, final View v) {
+            Color oldColor = g.getColor();
+
+            updateProperties();
+
+            if (!(g instanceof Graphics2D)) {
+                System.err.println("Graphics is not instance of Graphics2D");
+            }
+            Graphics2D g2d = (Graphics2D)g;
+
+            int xx = (int)x;
+            int yy = (int)y;
+            int ww = (int)w;
+            int hh = (int)h;
+            if (isTableBoxPainter) {
+                int captionHeight = ((TableTagView)view).getCaptionHeight();
+                yy += captionHeight;
+                hh -= captionHeight;
+            }
+            xx += margin[CSS.LEFT_SIDE];
+            yy += margin[CSS.TOP_SIDE];
+            ww -= (margin[CSS.LEFT_SIDE] + margin[CSS.RIGHT_SIDE]);
+            hh -= (margin[CSS.TOP_SIDE] + margin[CSS.BOTTOM_SIDE]);
+
+
+            if (backgroundImage != null
+                && backgroundImage != CSS.ImageValue.NONE) {
+
+                backgroundImage.loadImage(styleSheet.getBase());
+                final Image image = backgroundImage.getImage();
+                if (image != null) {
+                    paintBackgroundImage(image, g, xx, yy, ww, hh);
+                } else {
+                    if (updater == null) {
+                        updater = new ViewUpdater() {
+                            public void updateView() {
+                                Rectangle rc;
+                                JTextComponent tc =
+                                    (JTextComponent)view.getContainer();
+                                if (tc != null) {
+                                    try {
+                                        rc = tc.modelToView(view
+                                                            .getStartOffset());
+                                    } catch (BadLocationException e) {
+                                        return;
+                                    }
+                                    tc.repaint(rc.x, rc.y,
+                                               ((BoxView)view).getWidth(),
+                                               ((BoxView)view).getHeight());
+                                }
+                            }
+                        };
+                    }
+                    backgroundImage.addListener(updater);
+                }
+            } else if (backgroundColor != null
+                       && backgroundColor.getColor() != null) {
+                g.setColor(backgroundColor.getColor());
+                g.fillRect(xx, yy, ww, hh);
+            }
+
+
+            if (borderStyle != null) {
+                Color bc;
+                Stroke saveStroke = g2d.getStroke();
+                Stroke bs;
+
+                if (shouldDrawSide(CSS.BOTTOM_SIDE)) {
+                    bc = getSideColor(CSS.BOTTOM_SIDE);
+                    bs = getSideStroke(CSS.BOTTOM_SIDE);
+                    g2d.setColor(bc);
+                    g2d.setStroke(bs);
+                    g2d.drawLine(xx, yy + hh - 1, xx + ww - 1, yy + hh - 1);
+                }
+                if (shouldDrawSide(CSS.LEFT_SIDE)) {
+                    bc = getSideColor(CSS.LEFT_SIDE);
+                    bs = getSideStroke(CSS.LEFT_SIDE);
+                    g2d.setColor(bc);
+                    g2d.setStroke(bs);
+                    g2d.drawLine(xx, yy, xx, yy + hh - 1);
+                }
+                if (shouldDrawSide(CSS.TOP_SIDE)) {
+                    bc = getSideColor(CSS.TOP_SIDE);
+                    bs = getSideStroke(CSS.TOP_SIDE);
+                    g2d.setColor(bc);
+                    g2d.setStroke(bs);
+                    g2d.drawLine(xx, yy, xx + ww - 1, yy);
+                }
+                if (shouldDrawSide(CSS.RIGHT_SIDE)) {
+                    bc = getSideColor(CSS.RIGHT_SIDE);
+                    bs = getSideStroke(CSS.RIGHT_SIDE);
+                    g2d.setColor(bc);
+                    g2d.setStroke(bs);
+                    g2d.drawLine(xx + ww - 1, yy, xx + ww - 1, yy + hh - 1);
+                }
+
+                g2d.setStroke(saveStroke);
+            }
+
+            g.setColor(oldColor);
+            foreground = null;
+        }
+
+        final void setView(final View view) {
+            this.view = view;
+            isTableBoxPainter = view instanceof TableTagView;
+            updateMargin();
+        }
+
+        float getTopMargin() {
+            return margin[CSS.TOP_SIDE];
+        }
+
+        float getRightMargin() {
+            return margin[CSS.RIGHT_SIDE];
+        }
+
+        float getBottomMargin() {
+            return margin[CSS.BOTTOM_SIDE];
+        }
+
+        float getLeftMargin() {
+            return margin[CSS.LEFT_SIDE];
+        }
+
+        private static float getBorderSideWidth(final int side,
+                                                final View view,
+                                                final AttributeSet attrs) {
+            CSS.Length length =
+                (CSS.Length)attrs.getAttribute(BORDER_WIDTH_KEYS[side]);
+            return length != null
+                   ? length.floatValue(view)
+                   : CSS.BorderWidthValue.factory.floatValue();
+        }
+
+        private float getBorderSideWidth(final int side, final View view) {
+            final AttributeSet viewAttr = view.getAttributes();
+            CSS.BorderStyle borderStyle =
+                (BorderStyle)viewAttr.getAttribute(CSS.Attribute.BORDER_STYLE);
+            if (borderStyle == null
+                || borderStyle.getSideStyle(side).getIndex()
+                   == CSS.BorderStyleValue.NONE) {
+
+                return 0;
+            }
+
+            return getBorderSideWidth(side, view, viewAttr);
+        }
+
+        private Color getSideColor(final int i) {
+            Color result = null;
+            if (borderColor != null) {
+                result = (Color)borderColor.getSideColor(i).fromCSS();
+            }
+
+            if (result == null) {
+                if (foreground == null) {
+                    ColorProperty cp =
+                        (ColorProperty)attr.getAttribute(CSS.Attribute.COLOR);
+                    foreground = cp != null ? cp.getColor() : Color.BLACK;
+                }
+                result = foreground;
+            }
+            return result;
+        }
+
+        private int getSideIndex(final int side) {
+            switch (side) {
+            case SwingUtilities.TOP:
+                return CSS.TOP_SIDE;
+
+            case SwingUtilities.RIGHT:
+                return CSS.RIGHT_SIDE;
+
+            case SwingUtilities.BOTTOM:
+                return CSS.BOTTOM_SIDE;
+
+            case SwingUtilities.LEFT:
+                return CSS.LEFT_SIDE;
+
+            default:
+                throw new IllegalArgumentException("Invalid side " + side);
+            }
+        }
+
+        private Stroke getSideStroke(final int side) {
+            return new BasicStroke(borderWidth[side]);
+        }
+
+        private boolean shouldDrawSide(final int side) {
+            return borderStyle.getSideStyle(side).getIndex() != 0
+                   && borderWidth[side] > 0;
+        }
+
+        private void paintBackgroundImage(final Image image, final Graphics g,
+                                          final int x, final int y,
+                                          final int w, final int h) {
+            if (image == null) {
+                return;
+            }
+
+            final int imageWidth = backgroundImage.getWidth();
+            final int imageHeight = backgroundImage.getHeight();
+
+            final Image offscreen = view.getContainer().createVolatileImage(w, h);
+            final Graphics offG = offscreen.getGraphics();
+
+             if (backgroundColor != null
+                 && backgroundColor.getColor() != null) {
+
+                 offG.setColor(backgroundColor.getColor());
+                 offG.fillRect(x, y, w, h);
+             }
+
+            final int repeat = backgroundRepeat != null
+                               ? backgroundRepeat.getIndex() : 0;
+            switch (repeat) {
+            default:
+            case CSS.BackgroundRepeat.REPEAT:
+                for (int ix = 0; ix < w; ix += imageWidth) {
+                    for (int iy = 0; iy < h; iy += imageHeight) {
+                        offG.drawImage(image, ix, iy, null);
+                    }
+                }
+                break;
+
+            case CSS.BackgroundRepeat.REPEAT_X:
+                for (int ix = 0; ix < w; ix += imageWidth) {
+                    offG.drawImage(image, ix, 0, null);
+                }
+                break;
+
+            case CSS.BackgroundRepeat.REPEAT_Y:
+                for (int iy = 0; iy < h; iy += imageHeight) {
+                    offG.drawImage(image, 0, iy, null);
+                }
+                break;
+
+            case CSS.BackgroundRepeat.NO_REPEAT:
+                offG.drawImage(image, 0, 0, null);
+                break;
+            }
+
+            g.drawImage(offscreen, x, y, null);
+
+            offG.dispose();
+            offscreen.flush();
+        }
+
+        private void updateMargin() {
+            for (int i = 0; i < margin.length; i++) {
+                CSS.Length length =
+                    (CSS.Length)attr.getAttribute(MARGIN_KEYS[i]);
+                margin[i] = length != null ? length.floatValue(view) : 0;
+            }
+        }
+
+        private void updateBorderWidth() {
+            for (int i = 0; i < borderWidth.length; i++) {
+                borderWidth[i] = getBorderSideWidth(i, view, attr);
+            }
+        }
+
+        private void updateProperties() {
+            updateMargin();
+
+            borderStyle =
+                (BorderStyle)attr.getAttribute(CSS.Attribute.BORDER_STYLE);
+            if (borderStyle != null) {
+                borderColor =
+                    (BorderColor)attr.getAttribute(CSS.Attribute.BORDER_COLOR);
+                updateBorderWidth();
+            }
+
+            backgroundImage =
+                (CSS.ImageValue)attr.getAttribute(CSS.Attribute
+                                                       .BACKGROUND_IMAGE);
+            backgroundRepeat =
+                backgroundImage == null
+                ? null
+                : (CSS.BackgroundRepeat)attr.getAttribute(CSS.Attribute
+                                                          .BACKGROUND_REPEAT);
+            backgroundColor =
+                (CSS.ColorProperty)attr.getAttribute(CSS.Attribute
+                                                     .BACKGROUND_COLOR);
+        }
+    }
+
+    public static class ListPainter implements Serializable {
+        private static final float DECORATOR_MARGIN = 5;
+        private static final String DISC = "\u25CF";
+        private static final String CIRCLE = "\u25CB";
+        private static final String SQUARE = "\u25A0";
+        //        private final AttributeSet attr;
+//        private final CSS.ListStyleType listStyle;
+//        private final CSS.ListStyleImage listImage;
+
+
+        private ListPainter(final AttributeSet attr) {
+//            this.attr = attr;
+//            listStyle =
+//                (CSS.ListStyleType)attr.getAttribute(Attribute.LIST_STYLE_TYPE);
+            // TODO ListPainter: handle listImage
+//            attr.getAttribute(Attribute.LIST_STYLE_IMAGE);
+        }
+
+        public void paint(final Graphics g, final float x, final float y,
+                          final float w, final float h,
+                          final View v, final int item) {
+            final View child = v.getView(item);
+            if (!(child instanceof BlockView)) {
+                return;
+            }
+
+            final AttributeSet attr = child.getAttributes();
+            final StyleSheet ss = ((BlockView)child).getStyleSheet();
+            Font font = ss.getFont(attr);
+            final Color color = ss.getForeground(attr);
+            final CSS.ListStyleType listStyle =
+                (CSS.ListStyleType)attr.getAttribute(Attribute.LIST_STYLE_TYPE);
+
+            String decorator = null;
+
+            int index;
+            if (listStyle == null) {
+                final String name = v.getElement().getName();
+                if (HTML.Tag.OL.toString().equals(name)) {
+                    index = CSS.ListStyleType.LIST_STYLE_DECIMAL;
+                } else if (HTML.Tag.UL.toString().equals(name)) {
+                    index = CSS.ListStyleType.LIST_STYLE_DISC;
+                } else {
+                    index = CSS.ListStyleType.LIST_STYLE_NONE;
+                }
+            } else {
+                index = listStyle.getIndex();
+            }
+
+            switch (index) {
+            case CSS.ListStyleType.LIST_STYLE_DISC:
+                decorator = DISC;
+                font = font.deriveFont(font.getSize2D() * 0.7f);
+                break;
+
+            case CSS.ListStyleType.LIST_STYLE_CIRCLE:
+                decorator = CIRCLE;
+                font = font.deriveFont(font.getSize2D() * 0.7f);
+                break;
+
+            case CSS.ListStyleType.LIST_STYLE_SQUARE:
+                decorator = SQUARE;
+                font = font.deriveFont(font.getSize2D() * 0.7f);
+                break;
+
+
+            case CSS.ListStyleType.LIST_STYLE_DECIMAL:
+                decorator = Integer.toString(item + 1) + ".";
+                break;
+
+
+            case CSS.ListStyleType.LIST_STYLE_LOWER_ROMAN:
+                decorator = Integer.toString(item + 1) + "r.";
+                break;
+            case CSS.ListStyleType.LIST_STYLE_UPPER_ROMAN:
+                decorator = Integer.toString(item + 1) + "R.";
+                break;
+
+            case CSS.ListStyleType.LIST_STYLE_LOWER_ALPHA:
+                decorator = (char)('a' + item) + ".";
+                break;
+            case CSS.ListStyleType.LIST_STYLE_UPPER_ALPHA:
+                decorator = (char)('A' + item) + ".";
+                break;
+
+            case CSS.ListStyleType.LIST_STYLE_NONE:
+            default:
+            }
+
+            if (decorator == null) {
+                return;
+            }
+
+            Color oldColor = g.getColor();
+            Font oldFont = g.getFont();
+
+            g.setColor(color);
+            g.setFont(font);
+            FontMetrics metrics = g.getFontMetrics(font);
+            int width = metrics.stringWidth(decorator);
+
+            Rectangle pAlloc = new Rectangle((int)x, (int)y, (int)w, (int)h);
+            pAlloc = (Rectangle)child.getChildAllocation(0, pAlloc);
+
+            g.drawString(decorator,
+                         (int)(x - width - DECORATOR_MARGIN),
+                         (int)(pAlloc.y
+                               + pAlloc.height * child.getView(0)
+                                                 .getAlignment(View.Y_AXIS)
+                               + metrics.getHeight() / 2f
+                               - metrics.getDescent()));
+
+            g.setFont(oldFont);
+            g.setColor(oldColor);
+        }
+    }
+
+    final class SmallConverterSet extends SmallAttributeSet {
+        public SmallConverterSet(final AttributeSet attrs) {
+            super(attrs);
+        }
+
+        public SmallConverterSet(final Object[] attrs) {
+            super(attrs);
+        }
+
+        public Object getAttribute(final Object key) {
+            Object cssKey = CSS.mapToCSS(key);
+            Object result = super.getAttribute(cssKey != null ? cssKey : key);
+            if (!(cssKey instanceof Attribute)) {
+                if (key == StyleConstants.Underline
+                    || key == StyleConstants.StrikeThrough) {
+
+                    return getTextDecoration(this, key);
+                }
+                return result;
+            }
+            if (result == null) {
+                return super.getAttribute(key);
+            }
+
+            return ((PropertyValueConverter)result).fromCSS();
+        }
+
+        public boolean isDefined(final Object key) {
+            if (key == StyleConstants.Underline
+                || key == StyleConstants.StrikeThrough) {
+
+                return super.isDefined(Attribute.TEXT_DECORATION);
+            }
+            Object cssKey = CSS.mapToCSS(key);
+            return super.isDefined(cssKey != null ? cssKey : key);
+        }
+    }
+
+    final class LargeConverterSet extends SimpleAttributeSet {
+
+        LargeConverterSet(final AttributeSet source) {
+            super(source);
+        }
+
+        public Object getAttribute(final Object key) {
+            Object cssKey = CSS.mapToCSS(key);
+            Object result = super.getAttribute(cssKey != null ? cssKey : key);
+            if (!(cssKey instanceof Attribute)) {
+                if (key == StyleConstants.Underline
+                    || key == StyleConstants.StrikeThrough) {
+
+                    return getTextDecoration(this, key);
+                }
+                return result;
+            }
+            if (result == null) {
+                return super.getAttribute(key);
+            }
+
+            return ((PropertyValueConverter)result).fromCSS();
+        }
+
+        public boolean isDefined(final Object key) {
+            if (key == StyleConstants.Underline
+                || key == StyleConstants.StrikeThrough) {
+
+                return super.isDefined(Attribute.TEXT_DECORATION);
+            }
+            Object cssKey = CSS.mapToCSS(key);
+            return super.isDefined(cssKey != null ? cssKey : key);
+        }
+    }
+
+    private final class ResultStyleHashMap extends HashMap {
+        public CascadedStyle get(final String key) {
+            return (CascadedStyle)super.get(key);
+        }
+
+        public void put(final Style resStyle) {
+            super.put(resStyle.getName(), resStyle);
+        }
+    }
+
+    private final class NameConverterEnumeration implements Enumeration {
+        private final List attrKeys = new LinkedList();
+        private final Iterator it;
+
+        private final boolean underline;
+        private final boolean lineThrough;
+
+        NameConverterEnumeration(final AttributeSet toModify,
+                                 final AttributeSet attrSet) {
+            final Enumeration keys = attrSet.getAttributeNames();
+            boolean ul = false;
+            boolean lt = false;
+            while (keys.hasMoreElements()) {
+                Object key = keys.nextElement();
+                Object value = attrSet.getAttribute(key);
+                if (key == StyleConstants.Underline) {
+                    ul = ((Boolean)value).booleanValue();
+                } else if (key == StyleConstants.StrikeThrough) {
+                    lt = ((Boolean)value).booleanValue();
+                } else if (toModify.containsAttribute(key, value)) {
+                    attrKeys.add(key);
+                }
+            }
+
+            it = attrKeys.iterator();
+
+            underline = ul;
+            lineThrough = lt;
+        }
+
+        NameConverterEnumeration(final Enumeration names) {
+            boolean ul = false;
+            boolean lt = false;
+            while (names.hasMoreElements()) {
+                Object key = names.nextElement();
+                if (key == StyleConstants.Underline) {
+                    ul = true;
+                } else if (key == StyleConstants.StrikeThrough) {
+                    lt = true;
+                } else {
+                    attrKeys.add(key);
+                }
+            }
+
+            it = attrKeys.iterator();
+
+            underline = ul;
+            lineThrough = lt;
+        }
+
+        public boolean hasMoreElements() {
+            return it.hasNext();
+        }
+
+        public Object nextElement() {
+            Object key = it.next();
+            Object cssKey = CSS.mapToCSS(key);
+            return cssKey != null ? cssKey : key;
+        }
+
+        boolean isUnderline() {
+            return underline;
+        }
+
+        boolean isLineThrough() {
+            return lineThrough;
+        }
+    }
+
+    private static final Pattern relativePattern =
+        Pattern.compile("(?:\\+|-)\\d+");
+
+    private static final int DEFAULT_BASE_FONT_SIZE = 4;
+
+    private static final Map HTML_ATTRIBUTE_TO_CSS = new HashMap();
+
+    private URL base;
+    private int baseFontSize = DEFAULT_BASE_FONT_SIZE;
+
+    private CSSParser parser;
+
+    private ResultStyleHashMap resultStyles = new ResultStyleHashMap();
+    private List styleSheets = new LinkedList();
+
+    static {
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.ALIGN,
+                                  CSS.Attribute.TEXT_ALIGN);
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.BACKGROUND,
+                                  CSS.Attribute.BACKGROUND_IMAGE);
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.BGCOLOR,
+                                  CSS.Attribute.BACKGROUND_COLOR);
+//        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.BORDER,
+//                                  CSS.Attribute.BORDER);
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.TEXT,
+                                  CSS.Attribute.COLOR);
+
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.COLOR,
+                                  CSS.Attribute.COLOR);
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.FACE,
+                                  CSS.Attribute.FONT_FAMILY);
+
+//        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.HALIGN,
+//                                  CSS.Attribute.TEXT_ALIGN);
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.HEIGHT,
+                                  CSS.Attribute.HEIGHT);
+
+//        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.NOWRAP,
+//                                  CSS.Attribute.WHITE_SPACE);
+
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.VALIGN,
+                                  CSS.Attribute.VERTICAL_ALIGN);
+
+        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.WIDTH,
+                                  CSS.Attribute.WIDTH);
+
+//        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.LINK,
+//                                  CSS.Attribute.COLOR);
+//        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.ALINK,
+//                                  CSS.Attribute.COLOR);
+//        HTML_ATTRIBUTE_TO_CSS.put(HTML.Attribute.VLINK,
+//                                  CSS.Attribute.COLOR);
+    }
+
+    public static int getIndexOfSize(final float size) {
+        return CSS.FontSize.sizeValueIndex((int)size) + 1;
+    }
+
+    public AttributeSet addAttribute(final AttributeSet old, final Object key,
+                                     final Object value) {
+        Attribute cssKey = (Attribute)CSS.mapToCSSForced(key);
+        if (cssKey == null || cssKey.getConverter() == null) {
+            if (key == StyleConstants.Underline
+                || key == StyleConstants.StrikeThrough) {
+
+                return super.addAttribute(old, CSS.Attribute.TEXT_DECORATION,
+                                          createTextDecoration(old, key, value));
+            }
+            return super.addAttribute(old, key, value);
+        }
+        return super.addAttribute(old, cssKey,
+                                  value instanceof PropertyValueConverter
+                                  ? value : cssKey.getConverter().toCSS(value));
+    }
+
+    public AttributeSet addAttributes(final AttributeSet old,
+                                      final AttributeSet attr) {
+        MutableAttributeSet converted = new SimpleAttributeSet(old);
+        Enumeration attrKeys = attr.getAttributeNames();
+        while (attrKeys.hasMoreElements()) {
+            Object key = attrKeys.nextElement();
+            Object value = attr.getAttribute(key);
+            Attribute cssKey = (Attribute)CSS.mapToCSSForced(key);
+            if (cssKey == null) {
+                if (key == StyleConstants.Underline
+                    || key == StyleConstants.StrikeThrough) {
+
+                    value = createTextDecoration(converted, key, value);
+                    key = CSS.Attribute.TEXT_DECORATION;
+                }
+                converted.addAttribute(key, value);
+            } else {
+                if (!(value instanceof CSS.PropertyValueConverter)) {
+                    value = cssKey.getConverter().toCSS(value);
+                }
+                if (value != null) {
+                    converted.addAttribute(cssKey, value);
+                }
+            }
+        }
+        return super.addAttributes(getEmptySet(), converted);
+    }
+
+    public AttributeSet removeAttribute(final AttributeSet old,
+                                        final Object key) {
+        if (key == StyleConstants.Underline
+            || key == StyleConstants.StrikeThrough) {
+
+            TextDecoration td =
+                (TextDecoration)old.getAttribute(Attribute.TEXT_DECORATION);
+            td = (TextDecoration)td.clone();
+            if (key == StyleConstants.Underline && td.isUnderline()) {
+                td.setUnderline(false);
+            }
+            if (key == StyleConstants.StrikeThrough && td.isLineThrough()) {
+                td.setLineThrough(false);
+            }
+            if (td.isNone()) {
+                return super.removeAttribute(old, Attribute.TEXT_DECORATION);
+            }
+            return super.addAttribute(old, Attribute.TEXT_DECORATION, td);
+        }
+
+        Attribute cssKey = (Attribute)CSS.mapToCSSForced(key);
+        if (cssKey == null) {
+            return super.removeAttribute(old, key);
+        }
+        return super.removeAttribute(old, cssKey);
+    }
+
+    public AttributeSet removeAttributes(final AttributeSet old,
+                                         final AttributeSet rem) {
+        return removeAttributes(old, new NameConverterEnumeration(old, rem));
+    }
+
+    public AttributeSet removeAttributes(final AttributeSet old,
+                                         final Enumeration names) {
+        return removeAttributes(old, new NameConverterEnumeration(names));
+    }
+
+    public void addCSSAttribute(final MutableAttributeSet attr,
+                                final CSS.Attribute key, final String value) {
+        if (key == null || Utilities.isEmptyString(value)) {
+            return;
+        }
+        ShorthandPropertyExpander spe = key.getExpander();
+        if (spe != null) {
+            spe.parseAndExpandProperty(attr, value);
+        } else {
+            Object cssValue = key.getConverter().toCSS(value);
+            if (cssValue != null) {
+                attr.addAttribute(key, cssValue);
+            }
+        }
+    }
+
+    public boolean addCSSAttributeFromHTML(final MutableAttributeSet attr,
+                                           final CSS.Attribute key,
+                                           final String value) {
+
+        final int count = attr.getAttributeCount();
+        final Object attrValue = attr.getAttribute(key);
+        if (key == CSS.Attribute.BACKGROUND_IMAGE) {
+            addCSSAttribute(attr, key, "url(" + value + ")");
+        } else {
+            addCSSAttribute(attr, key, value);
+        }
+        return count != attr.getAttributeCount()
+               || attrValue != attr.getAttribute(key);
+    }
+
+    public void addRule(final String rule) {
+        if (Utilities.isEmptyString(rule)) {
+            return;
+        }
+        initCSSParser(new StringReader(rule));
+        parseSheet(false);
+    }
+
+    public void addStyleSheet(final StyleSheet ss) {
+        if (!styleSheets.contains(ss)) {
+            styleSheets.add(0, ss);
+            addStyleSheetToCascadedStyles(ss);
+        }
+    }
+
+    protected MutableAttributeSet
+        createLargeAttributeSet(final AttributeSet attr) {
+
+        return new LargeConverterSet(attr);
+    }
+
+    protected SmallAttributeSet
+        createSmallAttributeSet(final AttributeSet attr) {
+
+        return new SmallConverterSet(attr);
+    }
+
+    public BoxPainter getBoxPainter(final AttributeSet attr) {
+        return new BoxPainter(attr, this);
+    }
+
+    public AttributeSet getDeclaration(final String decl) {
+        if (Utilities.isEmptyString(decl)) {
+            return new SimpleAttributeSet();
+        }
+
+        initCSSParser(new StringReader("htmlTag {" + decl + "}"));
+        RuleSet rs = null;
+        try {
+            rs = parser.parseRuleSet();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        MutableAttributeSet attrs = new SimpleAttributeSet();
+        Iterator pi = rs.getProperties();
+        while (pi.hasNext()) {
+            Property property = (Property)pi.next();
+            addCSSAttribute(attrs, CSS.getAttribute(property.getName()),
+                            property.getValue());
+        }
+
+        return attrs;
+    }
+
+    public Font getFont(final AttributeSet attr) {
+        Object value;
+
+        value = getCSSProperty(attr, Attribute.FONT_FAMILY);
+        final String family = value != null ? (String)value
+                                            : CSS.FontFamily.DEFAULT;
+
+        value = attr.getAttribute(Attribute.FONT_SIZE);
+        final int size = value != null
+                         ? ((CSS.Length)value).intValue(attr)
+                         : CSS.FontSize.getDefaultValue().intValue();
+
+        value = getCSSProperty(attr, Attribute.FONT_WEIGHT);
+        final boolean bold = value != null ? ((Boolean)value).booleanValue()
+                                           : false;
+
+        value = getCSSProperty(attr, Attribute.FONT_STYLE);
+        boolean italic = value != null ? ((Boolean)value).booleanValue()
+                                       : false;
+
+        int style = Font.PLAIN;
+        if (bold) {
+            style |= Font.BOLD;
+        }
+        if (italic) {
+            style |= Font.ITALIC;
+        }
+        return getFont(family, style, size);
+    }
+
+    public Color getForeground(final AttributeSet attr) {
+        Object fore = getCSSProperty(attr, Attribute.COLOR);
+        return fore != null ? (Color)fore
+                            : super.getForeground(getEmptySet());
+    }
+
+    public Color getBackground(final AttributeSet attr) {
+        Object back = getCSSProperty(attr, Attribute.BACKGROUND_COLOR);
+        return back != null ? (Color)back : null;
+    }
+
+    public ListPainter getListPainter(final AttributeSet attr) {
+        return new ListPainter(attr);
+    }
+
+    public Style getRule(final String selector) {
+        return getCascadedStyle(new Selector(selector).toString());
+    }
+
+    public Style getRule(final HTML.Tag tag, final Element element) {
+        return getCascadedStyle(CascadedStyle.getElementTreeSelector(element));
+    }
+
+    public StyleSheet[] getStyleSheets() {
+        return styleSheets.size() > 0
+               ? (StyleSheet[])styleSheets
+                               .toArray(new StyleSheet[styleSheets.size()])
+               : null;
+    }
+
+    public AttributeSet getViewAttributes(final View v) {
+        return new ViewAttributeSet(this, v);
+    }
+
+    public void importStyleSheet(final URL url) {
+        // TODO importStyleSheet: use the URL specified to resolve references
+        if (url == null) {
+            return;
+        }
+
+        try {
+            initCSSParser(url.openStream());
+        } catch (IOException e) {
+            e.printStackTrace();
+            return;
+        }
+        parseSheet(true);
+    }
+
+    public void loadRules(final Reader in, final URL ref) throws IOException {
+        // TODO loadRules: use the URL specified to resolve references
+        initCSSParser(in);
+        parseSheet(false);
+    }
+
+    public void removeStyle(final String name) {
+        super.removeStyle(name);
+        if (name != null) {
+            removeStyleFromCascadedStyles(name);
+        }
+    }
+
+    public void removeStyleSheet(final StyleSheet ss) {
+        if (styleSheets.remove(ss)) {
+            removeStyleSheetFromCascadedStyles(ss);
+        }
+    }
+
+    public void setBase(final URL base) {
+        this.base = base;
+    }
+
+    public URL getBase() {
+        return base;
+    }
+
+    public void setBaseFontSize(final int index) {
+        baseFontSize = Utilities.range(index, 1, 7);
+    }
+
+    public void setBaseFontSize(final String size) {
+        setBaseFontSize(getRelativeIndex(size));
+    }
+
+    public float getPointSize(final int index) {
+        return CSS.FontSize.SIZE_TABLE[Utilities.range(index - 1,
+                                                       0, 6)].intValue();
+    }
+
+    public float getPointSize(final String size) {
+        return getPointSize(getRelativeIndex(size));
+    }
+
+    public Color stringToColor(final String colorNameOrHex) {
+        return CSS.ColorProperty.stringToColor(colorNameOrHex);
+    }
+
+    public AttributeSet translateHTMLToCSS(final AttributeSet htmlAttrSet) {
+        final Style result = addStyle(null, null);
+//        if (((Element)htmlAttrSet).isLeaf()) {
+//            return result;
+//        }
+
+        final Enumeration keys = htmlAttrSet.getAttributeNames();
+        while (keys.hasMoreElements()) {
+            Object key = keys.nextElement();
+            Object value = htmlAttrSet.getAttribute(key);
+            if (key instanceof CSS.Attribute) {
+                result.addAttribute(key, value);
+            } else {
+                Object cssKey = HTML_ATTRIBUTE_TO_CSS.get(key);
+                if (cssKey != null
+                    && ((Attribute)cssKey).getConverter() != null) {
+
+                    if ((key == HTML.Attribute.HEIGHT
+                         || key == HTML.Attribute.WIDTH)
+                        && value instanceof String
+                        && !((String)value).endsWith("%")) {
+
+                        value = ((Attribute)cssKey).getConverter()
+                                .toCSS((String)value + /*"px"*/ "pt");
+                    } else if (key == HTML.Attribute.BACKGROUND) {
+                        value = ((Attribute)cssKey).getConverter()
+                                .toCSS("url(" + value + ")");
+                    } else {
+                        value = ((Attribute)cssKey).getConverter().toCSS(value);
+                    }
+
+                    if (value != null) {
+                        result.addAttribute(cssKey, value);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    final Boolean getTextDecoration(final AttributeSet attr,
+                                    final Object key) {
+        TextDecoration value =
+            (TextDecoration)attr.getAttribute(Attribute.TEXT_DECORATION);
+        if (value == null) {
+            return null;
+        }
+        if (key == StyleConstants.Underline) {
+            return Boolean.valueOf(value.isUnderline());
+        }
+        if (key == StyleConstants.StrikeThrough) {
+            return Boolean.valueOf(value.isLineThrough());
+        }
+        return null;
+    }
+
+    private Object createTextDecoration(final AttributeSet old,
+                                        final Object key, final Object value) {
+        if (value instanceof String) {
+            return Attribute.TEXT_DECORATION.getConverter().toCSS(value);
+        }
+        TextDecoration oldValue =
+            (TextDecoration)old.getAttribute(Attribute.TEXT_DECORATION);
+        TextDecoration result = oldValue == null
+                                ? new TextDecoration()
+                                : (TextDecoration)oldValue.clone();
+        if (key == StyleConstants.Underline) {
+            result.setUnderline(((Boolean)value).booleanValue());
+        }
+        if (key == StyleConstants.StrikeThrough) {
+            result.setLineThrough(((Boolean)value).booleanValue());
+        }
+        return result;
+    }
+
+    private Object getCSSProperty(final AttributeSet attr,
+                                  final CSS.Attribute key) {
+        Object value = attr.getAttribute(key);
+        if (value != null) {
+            return ((PropertyValueConverter)value).fromCSS();
+        }
+        return null;
+    }
+
+    private int getRelativeIndex(final String size) {
+        if (!relativePattern.matcher(size).matches()) {
+            return Integer.parseInt(size);
+        }
+
+        int index = Integer.parseInt(size.substring(1));
+        if (size.charAt(0) == '-') {
+            index = -index;
+        }
+        return baseFontSize + index;
+    }
+
+    private void initCSSParser(final Reader reader) {
+        if (parser == null) {
+            parser = new CSSParser(reader);
+        } else {
+            parser.ReInit(reader);
+        }
+    }
+
+    private void initCSSParser(final InputStream stream) {
+        if (parser == null) {
+            parser = new CSSParser(stream);
+        } else {
+            parser.ReInit(stream);
+        }
+    }
+
+    private void parseSheet(final boolean asResolver) {
+//        throw new UnsupportedOperationException("CSS parser required!");
+        Sheet ss = null;
+        try {
+            ss = parser.parse();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        addImportedStyleSheets(ss.getImportsIterator(), asResolver);
+        addParsedSheet(ss.getRuleSetIterator(), asResolver);
+    }
+
+    private void addImportedStyleSheets(final Iterator it,
+                                        final boolean asResolver) {
+        while (it.hasNext()) {
+            importStyleSheet(HTML.resolveURL(extractURL((String)it.next()),
+                                             getBase()));
+        }
+    }
+
+    private void addParsedSheet(final Iterator it, final boolean asResolver) {
+        while (it.hasNext()) {
+            RuleSet rs = (RuleSet)it.next();
+            MutableAttributeSet attrs = new SimpleAttributeSet();
+            Iterator pi = rs.getProperties();
+            while (pi.hasNext()) {
+                Property property = (Property)pi.next();
+                addCSSAttribute(attrs, CSS.getAttribute(property.getName()),
+                                property.getValue());
+            }
+            if (attrs.getAttributeCount() == 0) {
+                continue;
+            }
+
+            Iterator si = rs.getSelectors();
+            while (si.hasNext()) {
+                String selector = new Selector((String)si.next()).toString();
+                Style rr = getStyle(selector);
+                if (rr == null) {
+                    rr = addStyle(selector, null);
+                    addStyleToCascadedStyles(selector);
+                }
+                if (asResolver) {
+                    final AttributeSet resolver = rr.getResolveParent();
+                    final MutableAttributeSet importedAttrs =
+                        resolver instanceof MutableAttributeSet
+                        ? (MutableAttributeSet)resolver
+                        : addStyle(null, null);
+                    importedAttrs.addAttributes(attrs);
+                    rr.setResolveParent(importedAttrs);
+                } else {
+                    rr.addAttributes(attrs);
+                }
+            }
+        }
+    }
+
+    private void addStyleToCascadedStyles(final String styleName) {
+        final Iterator it = resultStyles.values().iterator();
+        while (it.hasNext()) {
+            CascadedStyle rs = (CascadedStyle)it.next();
+            rs.addStyle(styleName);
+        }
+    }
+
+    private void removeStyleFromCascadedStyles(final String styleName) {
+        final Iterator it = resultStyles.values().iterator();
+        while (it.hasNext()) {
+            CascadedStyle rs = (CascadedStyle)it.next();
+            rs.removeStyle(styleName);
+        }
+    }
+
+    private void addStyleSheetToCascadedStyles(final StyleSheet styleSheet) {
+        final Iterator it = resultStyles.values().iterator();
+        while (it.hasNext()) {
+            CascadedStyle rs = (CascadedStyle)it.next();
+            rs.addStyleSheet(styleSheet);
+        }
+    }
+
+    private void removeStyleSheetFromCascadedStyles(final StyleSheet styleSheet) {
+        final Iterator it = resultStyles.values().iterator();
+        while (it.hasNext()) {
+            CascadedStyle rs = (CascadedStyle)it.next();
+            rs.removeStyleSheet(styleSheet);
+        }
+    }
+
+    private Style getCascadedStyle(final String selector) {
+        Style result = resultStyles.get(selector);
+        if (result != null) {
+            return result;
+        }
+        result = new CascadedStyle(this, selector,
+                                   SelectorMatcher.findMatching(getStyleNames(),
+                                                                selector),
+                                   styleSheets.iterator());
+       resultStyles.put(result);
+       return result;
+    }
+
+    private AttributeSet removeAttributes(final AttributeSet toModify,
+                                          final NameConverterEnumeration keys) {
+        if (!keys.isUnderline() && !keys.isLineThrough()) {
+            return super.removeAttributes(toModify, keys);
+        }
+
+        final MutableAttributeSet result = new SimpleAttributeSet(toModify);
+        result.removeAttributes(keys);
+        TextDecoration td =
+            (TextDecoration)result.getAttribute(Attribute.TEXT_DECORATION);
+        td = (TextDecoration)td.clone();
+
+        if (keys.isUnderline() && td.isUnderline()) {
+            td.setUnderline(false);
+        }
+        if (keys.isLineThrough() && td.isLineThrough()) {
+            td.setLineThrough(false);
+        }
+        if (td.isNone()) {
+            result.removeAttribute(Attribute.TEXT_DECORATION);
+        } else {
+            result.addAttribute(Attribute.TEXT_DECORATION, td);
+        }
+        return super.addAttributes(getEmptySet(), result);
+    }
+
+    private String extractURL(final String importPath) {
+        String result = importPath;
+        if (result.startsWith("url(") && result.endsWith(")")) {
+            result = result.substring(4, result.length() - 1);
+        }
+        char c = result.charAt(0);
+        if (c == '\'' || c == '"') {
+            result = result.substring(1, result.length() - 1);
+        }
+        return result;
+    }
+}



Mime
View raw message