libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / javax / swing / text / html / StyleSheet.java
blob08578c80fad6e92630b7f072756c59a744d93220
1 /* StyleSheet.java --
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text.html;
41 import gnu.javax.swing.text.html.css.BorderWidth;
42 import gnu.javax.swing.text.html.css.CSSColor;
43 import gnu.javax.swing.text.html.css.CSSParser;
44 import gnu.javax.swing.text.html.css.CSSParserCallback;
45 import gnu.javax.swing.text.html.css.FontSize;
46 import gnu.javax.swing.text.html.css.FontStyle;
47 import gnu.javax.swing.text.html.css.FontWeight;
48 import gnu.javax.swing.text.html.css.Length;
49 import gnu.javax.swing.text.html.css.Selector;
51 import java.awt.Color;
52 import java.awt.Font;
53 import java.awt.Graphics;
54 import java.awt.Rectangle;
55 import java.awt.Shape;
56 import java.awt.font.FontRenderContext;
57 import java.awt.geom.Rectangle2D;
58 import java.io.BufferedReader;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.io.InputStreamReader;
62 import java.io.Reader;
63 import java.io.Serializable;
64 import java.io.StringReader;
65 import java.net.URL;
66 import java.util.ArrayList;
67 import java.util.Collections;
68 import java.util.Enumeration;
69 import java.util.HashMap;
70 import java.util.Iterator;
71 import java.util.List;
72 import java.util.Map;
74 import javax.swing.border.Border;
75 import javax.swing.event.ChangeListener;
76 import javax.swing.text.AttributeSet;
77 import javax.swing.text.Element;
78 import javax.swing.text.MutableAttributeSet;
79 import javax.swing.text.SimpleAttributeSet;
80 import javax.swing.text.Style;
81 import javax.swing.text.StyleConstants;
82 import javax.swing.text.StyleContext;
83 import javax.swing.text.View;
86 /**
87 * This class adds support for defining the visual characteristics of HTML views
88 * being rendered. This enables views to be customized by a look-and-feel, mulitple
89 * views over the same model can be rendered differently. Each EditorPane has its
90 * own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit
91 * instances. An HTMLDocument can also have a StyleSheet, which holds specific CSS
92 * specs.
94 * In order for Views to store less state and therefore be more lightweight,
95 * the StyleSheet can act as a factory for painters that handle some of the
96 * rendering tasks. Since the StyleSheet may be used by views over multiple
97 * documents the HTML attributes don't effect the selector being used.
99 * The rules are stored as named styles, and other information is stored to
100 * translate the context of an element to a rule.
102 * @author Lillian Angel (langel@redhat.com)
104 public class StyleSheet extends StyleContext
108 * Parses CSS stylesheets using the parser in gnu/javax/swing/html/css.
110 * This is package private to avoid accessor methods.
112 class CSSStyleSheetParserCallback
113 implements CSSParserCallback
116 * The current styles.
118 private CSSStyle[] styles;
121 * The precedence of the stylesheet to be parsed.
123 private int precedence;
126 * Creates a new CSS parser. This parser parses a CSS stylesheet with
127 * the specified precedence.
129 * @param prec the precedence, according to the constants defined in
130 * CSSStyle
132 CSSStyleSheetParserCallback(int prec)
134 precedence = prec;
138 * Called at the beginning of a statement.
140 * @param sel the selector
142 public void startStatement(Selector[] sel)
144 styles = new CSSStyle[sel.length];
145 for (int i = 0; i < sel.length; i++)
146 styles[i] = new CSSStyle(precedence, sel[i]);
150 * Called at the end of a statement.
152 public void endStatement()
154 for (int i = 0; i < styles.length; i++)
155 css.add(styles[i]);
156 styles = null;
160 * Called when a declaration is parsed.
162 * @param property the property
163 * @param value the value
165 public void declaration(String property, String value)
167 CSS.Attribute cssAtt = CSS.getAttribute(property);
168 Object val = CSS.getValue(cssAtt, value);
169 for (int i = 0; i < styles.length; i++)
171 CSSStyle style = styles[i];
172 CSS.addInternal(style, cssAtt, value);
173 if (cssAtt != null)
174 style.addAttribute(cssAtt, val);
181 * Represents a style that is defined by a CSS rule.
183 private class CSSStyle
184 extends SimpleAttributeSet
185 implements Style, Comparable<CSSStyle>
188 static final int PREC_UA = 0;
189 static final int PREC_NORM = 100000;
190 static final int PREC_AUTHOR_NORMAL = 200000;
191 static final int PREC_AUTHOR_IMPORTANT = 300000;
192 static final int PREC_USER_IMPORTANT = 400000;
195 * The priority of this style when matching CSS selectors.
197 private int precedence;
200 * The selector for this rule.
202 * This is package private to avoid accessor methods.
204 Selector selector;
206 CSSStyle(int prec, Selector sel)
208 precedence = prec;
209 selector = sel;
212 public String getName()
214 // TODO: Implement this for correctness.
215 return null;
218 public void addChangeListener(ChangeListener listener)
220 // TODO: Implement this for correctness.
223 public void removeChangeListener(ChangeListener listener)
225 // TODO: Implement this for correctness.
229 * Sorts the rule according to the style's precedence and the
230 * selectors specificity.
232 public int compareTo(CSSStyle other)
234 return other.precedence + other.selector.getSpecificity()
235 - precedence - selector.getSpecificity();
240 /** The base URL */
241 URL base;
243 /** Base font size (int) */
244 int baseFontSize;
247 * The linked style sheets stored.
249 private ArrayList<StyleSheet> linked;
252 * Maps element names (selectors) to AttributSet (the corresponding style
253 * information).
255 ArrayList<CSSStyle> css = new ArrayList<CSSStyle>();
258 * Maps selectors to their resolved styles.
260 private HashMap<String,Style> resolvedStyles;
263 * Constructs a StyleSheet.
265 public StyleSheet()
267 super();
268 baseFontSize = 4; // Default font size from CSS
269 resolvedStyles = new HashMap<String,Style>();
273 * Gets the style used to render the given tag. The element represents the tag
274 * and can be used to determine the nesting, where the attributes will differ
275 * if there is nesting inside of elements.
277 * @param t - the tag to translate to visual attributes
278 * @param e - the element representing the tag
279 * @return the set of CSS attributes to use to render the tag.
281 public Style getRule(HTML.Tag t, Element e)
283 // Create list of the element and all of its parents, starting
284 // with the bottommost element.
285 ArrayList<Element> path = new ArrayList<Element>();
286 Element el;
287 AttributeSet atts;
288 for (el = e; el != null; el = el.getParentElement())
289 path.add(el);
291 // Create fully qualified selector.
292 StringBuilder selector = new StringBuilder();
293 int count = path.size();
294 // We append the actual element after this loop.
295 for (int i = count - 1; i > 0; i--)
297 el = path.get(i);
298 atts = el.getAttributes();
299 Object name = atts.getAttribute(StyleConstants.NameAttribute);
300 selector.append(name.toString());
301 if (atts.isDefined(HTML.Attribute.ID))
303 selector.append('#');
304 selector.append(atts.getAttribute(HTML.Attribute.ID));
306 if (atts.isDefined(HTML.Attribute.CLASS))
308 selector.append('.');
309 selector.append(atts.getAttribute(HTML.Attribute.CLASS));
311 if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
313 selector.append(':');
314 selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
316 if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
318 selector.append(':');
319 selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
321 selector.append(' ');
323 selector.append(t.toString());
324 el = path.get(0);
325 atts = el.getAttributes();
326 // For leaf elements, we have to fetch the tag specific attributes.
327 if (el.isLeaf())
329 Object o = atts.getAttribute(t);
330 if (o instanceof AttributeSet)
331 atts = (AttributeSet) o;
332 else
333 atts = null;
335 if (atts != null)
337 if (atts.isDefined(HTML.Attribute.ID))
339 selector.append('#');
340 selector.append(atts.getAttribute(HTML.Attribute.ID));
342 if (atts.isDefined(HTML.Attribute.CLASS))
344 selector.append('.');
345 selector.append(atts.getAttribute(HTML.Attribute.CLASS));
347 if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
349 selector.append(':');
350 selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
352 if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
354 selector.append(':');
355 selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
358 return getResolvedStyle(selector.toString(), path, t);
362 * Fetches a resolved style. If there is no resolved style for the
363 * specified selector, the resolve the style using
364 * {@link #resolveStyle(String, List, HTML.Tag)}.
366 * @param selector the selector for which to resolve the style
367 * @param path the Element path, used in the resolving algorithm
368 * @param tag the tag for which to resolve
370 * @return the resolved style
372 private Style getResolvedStyle(String selector, List path, HTML.Tag tag)
374 Style style = resolvedStyles.get(selector);
375 if (style == null)
376 style = resolveStyle(selector, path, tag);
377 return style;
381 * Resolves a style. This creates arrays that hold the tag names,
382 * class and id attributes and delegates the work to
383 * {@link #resolveStyle(String, String[], Map[])}.
385 * @param selector the selector
386 * @param path the Element path
387 * @param tag the tag
389 * @return the resolved style
391 private Style resolveStyle(String selector, List path, HTML.Tag tag)
393 int count = path.size();
394 String[] tags = new String[count];
395 Map[] attributes = new Map[count];
396 for (int i = 0; i < count; i++)
398 Element el = (Element) path.get(i);
399 AttributeSet atts = el.getAttributes();
400 if (i == 0 && el.isLeaf())
402 Object o = atts.getAttribute(tag);
403 if (o instanceof AttributeSet)
404 atts = (AttributeSet) o;
405 else
406 atts = null;
408 if (atts != null)
410 HTML.Tag t =
411 (HTML.Tag) atts.getAttribute(StyleConstants.NameAttribute);
412 if (t != null)
413 tags[i] = t.toString();
414 else
415 tags[i] = null;
416 attributes[i] = attributeSetToMap(atts);
418 else
420 tags[i] = null;
421 attributes[i] = null;
424 tags[0] = tag.toString();
425 return resolveStyle(selector, tags, attributes);
429 * Performs style resolving.
431 * @param selector the selector
432 * @param tags the tags
433 * @param attributes the attributes of the tags
435 * @return the resolved style
437 private Style resolveStyle(String selector, String[] tags, Map[] attributes)
439 // FIXME: This style resolver is not correct. But it works good enough for
440 // the default.css.
441 ArrayList<CSSStyle> styles = new ArrayList<CSSStyle>();
442 for (CSSStyle style : css)
444 if (style.selector.matches(tags, attributes))
445 styles.add(style);
448 // Add styles from linked stylesheets.
449 if (linked != null)
451 for (int i = linked.size() - 1; i >= 0; i--)
453 StyleSheet ss = linked.get(i);
454 for (int j = ss.css.size() - 1; j >= 0; j--)
456 CSSStyle style = ss.css.get(j);
457 if (style.selector.matches(tags, attributes))
458 styles.add(style);
463 // Sort selectors.
464 Collections.sort(styles);
465 Style[] styleArray = new Style[styles.size()];
466 styleArray = (Style[]) styles.toArray(styleArray);
467 Style resolved = new MultiStyle(selector,
468 (Style[]) styles.toArray(styleArray));
469 resolvedStyles.put(selector, resolved);
470 return resolved;
474 * Gets the rule that best matches the selector. selector is a space
475 * separated String of element names. The attributes of the returned
476 * Style will change as rules are added and removed.
478 * @param selector - the element names separated by spaces
479 * @return the set of CSS attributes to use to render
481 public Style getRule(String selector)
483 CSSStyle best = null;
484 for (Iterator i = css.iterator(); i.hasNext();)
486 CSSStyle style = (CSSStyle) i.next();
487 if (style.compareTo(best) < 0)
488 best = style;
490 return best;
494 * Adds a set of rules to the sheet. The rules are expected to be in valid
495 * CSS format. This is called as a result of parsing a <style> tag
497 * @param rule - the rule to add to the sheet
499 public void addRule(String rule)
501 CSSStyleSheetParserCallback cb =
502 new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
503 // FIXME: Handle ref.
504 StringReader in = new StringReader(rule);
505 CSSParser parser = new CSSParser(in, cb);
508 parser.parse();
510 catch (IOException ex)
512 // Shouldn't happen. And if, then don't let it bork the outside code.
514 // Clean up resolved styles cache so that the new styles are recognized
515 // on next stylesheet request.
516 resolvedStyles.clear();
520 * Translates a CSS declaration into an AttributeSet. This is called
521 * as a result of encountering an HTML style attribute.
523 * @param decl - the declaration to get
524 * @return the AttributeSet representing the declaration
526 public AttributeSet getDeclaration(String decl)
528 if (decl == null)
529 return SimpleAttributeSet.EMPTY;
530 // FIXME: Not implemented.
531 return null;
535 * Loads a set of rules that have been specified in terms of CSS grammar.
536 * If there are any conflicts with existing rules, the new rule is added.
538 * @param in - the stream to read the CSS grammar from.
539 * @param ref - the reference URL. It is the location of the stream, it may
540 * be null. All relative URLs specified in the stream will be based upon this
541 * parameter.
542 * @throws IOException - For any IO error while reading
544 public void loadRules(Reader in, URL ref)
545 throws IOException
547 CSSStyleSheetParserCallback cb =
548 new CSSStyleSheetParserCallback(CSSStyle.PREC_UA);
549 // FIXME: Handle ref.
550 CSSParser parser = new CSSParser(in, cb);
551 parser.parse();
555 * Gets a set of attributes to use in the view. This is a set of
556 * attributes that can be used for View.getAttributes
558 * @param v - the view to get the set for
559 * @return the AttributeSet to use in the view.
561 public AttributeSet getViewAttributes(View v)
563 return new ViewAttributeSet(v, this);
567 * Removes a style previously added.
569 * @param nm - the name of the style to remove
571 public void removeStyle(String nm)
573 // FIXME: Not implemented.
574 super.removeStyle(nm);
578 * Adds the rules from ss to those of the receiver. ss's rules will
579 * override the old rules. An added StyleSheet will never override the rules
580 * of the receiving style sheet.
582 * @param ss - the new StyleSheet.
584 public void addStyleSheet(StyleSheet ss)
586 if (linked == null)
587 linked = new ArrayList();
588 linked.add(ss);
592 * Removes ss from those of the receiver
594 * @param ss - the StyleSheet to remove.
596 public void removeStyleSheet(StyleSheet ss)
598 if (linked != null)
600 linked.remove(ss);
605 * Returns an array of the linked StyleSheets. May return null.
607 * @return - An array of the linked StyleSheets.
609 public StyleSheet[] getStyleSheets()
611 StyleSheet[] linkedSS;
612 if (linked != null)
614 linkedSS = new StyleSheet[linked.size()];
615 linkedSS = linked.toArray(linkedSS);
617 else
619 linkedSS = null;
621 return linkedSS;
625 * Imports a style sheet from the url. The rules are directly added to the
626 * receiver. This is usually called when a <link> tag is resolved in an
627 * HTML document.
629 * @param url the URL to import the StyleSheet from
631 public void importStyleSheet(URL url)
635 InputStream in = url.openStream();
636 Reader r = new BufferedReader(new InputStreamReader(in));
637 CSSStyleSheetParserCallback cb =
638 new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
639 CSSParser parser = new CSSParser(r, cb);
640 parser.parse();
642 catch (IOException ex)
644 // We can't do anything about it I guess.
649 * Sets the base url. All import statements that are relative, will be
650 * relative to base.
652 * @param base -
653 * the base URL.
655 public void setBase(URL base)
657 this.base = base;
661 * Gets the base url.
663 * @return - the base
665 public URL getBase()
667 return base;
671 * Adds a CSS attribute to the given set.
673 * @param attr - the attribute set
674 * @param key - the attribute to add
675 * @param value - the value of the key
677 public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key,
678 String value)
680 Object val = CSS.getValue(key, value);
681 CSS.addInternal(attr, key, value);
682 attr.addAttribute(key, val);
686 * Adds a CSS attribute to the given set.
687 * This method parses the value argument from HTML based on key.
688 * Returns true if it finds a valid value for the given key,
689 * and false otherwise.
691 * @param attr - the attribute set
692 * @param key - the attribute to add
693 * @param value - the value of the key
694 * @return true if a valid value was found.
696 public boolean addCSSAttributeFromHTML(MutableAttributeSet attr, CSS.Attribute key,
697 String value)
699 // FIXME: Need to parse value from HTML based on key.
700 attr.addAttribute(key, value);
701 return attr.containsAttribute(key, value);
705 * Converts a set of HTML attributes to an equivalent set of CSS attributes.
707 * @param htmlAttrSet - the set containing the HTML attributes.
708 * @return the set of CSS attributes
710 public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet)
712 AttributeSet cssAttr = htmlAttrSet.copyAttributes();
714 // The HTML align attribute maps directly to the CSS text-align attribute.
715 Object o = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
716 if (o != null)
717 cssAttr = addAttribute(cssAttr, CSS.Attribute.TEXT_ALIGN, o);
719 // The HTML width attribute maps directly to CSS width.
720 o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH);
721 if (o != null)
722 cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH,
723 new Length(o.toString()));
725 // The HTML height attribute maps directly to CSS height.
726 o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT);
727 if (o != null)
728 cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT,
729 new Length(o.toString()));
731 o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP);
732 if (o != null)
733 cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap");
735 // Map cellspacing attr of tables to CSS border-spacing.
736 o = htmlAttrSet.getAttribute(HTML.Attribute.CELLSPACING);
737 if (o != null)
738 cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_SPACING,
739 new Length(o.toString()));
741 // For table cells and headers, fetch the cellpadding value from the
742 // parent table and set it as CSS padding attribute.
743 HTML.Tag tag = (HTML.Tag)
744 htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
745 if ((tag == HTML.Tag.TD || tag == HTML.Tag.TH)
746 && htmlAttrSet instanceof Element)
748 Element el = (Element) htmlAttrSet;
749 AttributeSet tableAttrs = el.getParentElement().getParentElement()
750 .getAttributes();
751 o = tableAttrs.getAttribute(HTML.Attribute.CELLPADDING);
752 if (o != null)
754 Length l = new Length(o.toString());
755 cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_BOTTOM, l);
756 cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_LEFT, l);
757 cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_RIGHT, l);
758 cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_TOP, l);
760 o = tableAttrs.getAttribute(HTML.Attribute.BORDER);
761 cssAttr = translateBorder(cssAttr, o);
764 // Translate border attribute.
765 o = cssAttr.getAttribute(HTML.Attribute.BORDER);
766 cssAttr = translateBorder(cssAttr, o);
768 // TODO: Add more mappings.
769 return cssAttr;
773 * Translates a HTML border attribute to a corresponding set of CSS
774 * attributes.
776 * @param cssAttr the original set of CSS attributes to add to
777 * @param o the value of the border attribute
779 * @return the new set of CSS attributes
781 private AttributeSet translateBorder(AttributeSet cssAttr, Object o)
783 if (o != null)
785 BorderWidth l = new BorderWidth(o.toString());
786 if (l.getValue() > 0)
788 cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_WIDTH, l);
789 cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_STYLE,
790 "solid");
791 cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_COLOR,
792 new CSSColor("black"));
795 return cssAttr;
799 * Adds an attribute to the given set and returns a new set. This is implemented
800 * to convert StyleConstants attributes to CSS before forwarding them to the superclass.
801 * The StyleConstants attribute do not have corresponding CSS entry, the attribute
802 * is stored (but will likely not be used).
804 * @param old - the old set
805 * @param key - the non-null attribute key
806 * @param value - the attribute value
807 * @return the updated set
809 public AttributeSet addAttribute(AttributeSet old, Object key,
810 Object value)
812 // FIXME: Not implemented.
813 return super.addAttribute(old, key, value);
817 * Adds a set of attributes to the element. If any of these attributes are
818 * StyleConstants, they will be converted to CSS before forwarding to the
819 * superclass.
821 * @param old - the old set
822 * @param attr - the attributes to add
823 * @return the updated attribute set
825 public AttributeSet addAttributes(AttributeSet old, AttributeSet attr)
827 // FIXME: Not implemented.
828 return super.addAttributes(old, attr);
832 * Removes an attribute from the set. If the attribute is a
833 * StyleConstants, it will be converted to CSS before forwarding to the
834 * superclass.
836 * @param old - the old set
837 * @param key - the non-null attribute key
838 * @return the updated set
840 public AttributeSet removeAttribute(AttributeSet old, Object key)
842 // FIXME: Not implemented.
843 return super.removeAttribute(old, key);
847 * Removes an attribute from the set. If any of the attributes are
848 * StyleConstants, they will be converted to CSS before forwarding to the
849 * superclass.
851 * @param old - the old set
852 * @param attrs - the attributes to remove
853 * @return the updated set
855 public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs)
857 // FIXME: Not implemented.
858 return super.removeAttributes(old, attrs);
862 * Removes a set of attributes for the element. If any of the attributes is a
863 * StyleConstants, they will be converted to CSS before forwarding to the
864 * superclass.
866 * @param old - the old attribute set
867 * @param names - the attribute names
868 * @return the update attribute set
870 public AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names)
872 // FIXME: Not implemented.
873 return super.removeAttributes(old, names);
877 * Creates a compact set of attributes that might be shared. This is a hook
878 * for subclasses that want to change the behaviour of SmallAttributeSet.
880 * @param a - the set of attributes to be represented in the compact form.
881 * @return the set of attributes created
883 protected StyleContext.SmallAttributeSet createSmallAttributeSet(AttributeSet a)
885 return super.createSmallAttributeSet(a);
889 * Creates a large set of attributes. This set is not shared. This is a hook
890 * for subclasses that want to change the behaviour of the larger attribute
891 * storage format.
893 * @param a - the set of attributes to be represented in the larger form.
894 * @return the large set of attributes.
896 protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
898 return super.createLargeAttributeSet(a);
902 * Gets the font to use for the given set.
904 * @param a - the set to get the font for.
905 * @return the font for the set
907 public Font getFont(AttributeSet a)
909 int realSize = getFontSize(a);
911 // Decrement size for subscript and superscript.
912 Object valign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
913 if (valign != null)
915 String v = valign.toString();
916 if (v.contains("sup") || v.contains("sub"))
917 realSize -= 2;
920 // TODO: Convert font family.
921 String family = "SansSerif";
923 int style = Font.PLAIN;
924 FontWeight weight = (FontWeight) a.getAttribute(CSS.Attribute.FONT_WEIGHT);
925 if (weight != null)
926 style |= weight.getValue();
927 FontStyle fStyle = (FontStyle) a.getAttribute(CSS.Attribute.FONT_STYLE);
928 if (fStyle != null)
929 style |= fStyle.getValue();
930 return new Font(family, style, realSize);
934 * Determines the EM base value based on the specified attributes.
936 * @param atts the attibutes
938 * @return the EM base value
940 float getEMBase(AttributeSet atts)
942 Font font = getFont(atts);
943 FontRenderContext ctx = new FontRenderContext(null, false, false);
944 Rectangle2D bounds = font.getStringBounds("M", ctx);
945 return (float) bounds.getWidth();
949 * Determines the EX base value based on the specified attributes.
951 * @param atts the attibutes
953 * @return the EX base value
955 float getEXBase(AttributeSet atts)
957 Font font = getFont(atts);
958 FontRenderContext ctx = new FontRenderContext(null, false, false);
959 Rectangle2D bounds = font.getStringBounds("x", ctx);
960 return (float) bounds.getHeight();
964 * Resolves the fontsize for a given set of attributes.
966 * @param atts the attributes
968 * @return the resolved font size
970 private int getFontSize(AttributeSet atts)
972 int size = 12;
973 if (atts.isDefined(CSS.Attribute.FONT_SIZE))
975 FontSize fs = (FontSize) atts.getAttribute(CSS.Attribute.FONT_SIZE);
976 if (fs.isRelative())
978 int parSize = 12;
979 AttributeSet resolver = atts.getResolveParent();
980 if (resolver != null)
981 parSize = getFontSize(resolver);
982 size = fs.getValue(parSize);
984 else
986 size = fs.getValue();
989 else
991 AttributeSet resolver = atts.getResolveParent();
992 if (resolver != null)
993 size = getFontSize(resolver);
995 return size;
999 * Takes a set of attributes and turns it into a foreground
1000 * color specification. This is used to specify things like, brigher, more hue
1001 * etc.
1003 * @param a - the set to get the foreground color for
1004 * @return the foreground color for the set
1006 public Color getForeground(AttributeSet a)
1008 CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.COLOR);
1009 Color color = null;
1010 if (c != null)
1011 color = c.getValue();
1012 return color;
1016 * Takes a set of attributes and turns it into a background
1017 * color specification. This is used to specify things like, brigher, more hue
1018 * etc.
1020 * @param a - the set to get the background color for
1021 * @return the background color for the set
1023 public Color getBackground(AttributeSet a)
1025 CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.BACKGROUND_COLOR);
1026 Color color = null;
1027 if (c != null)
1028 color = c.getValue();
1029 return color;
1033 * Gets the box formatter to use for the given set of CSS attributes.
1035 * @param a - the given set
1036 * @return the box formatter
1038 public BoxPainter getBoxPainter(AttributeSet a)
1040 return new BoxPainter(a, this);
1044 * Gets the list formatter to use for the given set of CSS attributes.
1046 * @param a - the given set
1047 * @return the list formatter
1049 public ListPainter getListPainter(AttributeSet a)
1051 return new ListPainter(a, this);
1055 * Sets the base font size between 1 and 7.
1057 * @param sz - the new font size for the base.
1059 public void setBaseFontSize(int sz)
1061 if (sz <= 7 && sz >= 1)
1062 baseFontSize = sz;
1066 * Sets the base font size from the String. It can either identify
1067 * a specific font size (between 1 and 7) or identify a relative
1068 * font size such as +1 or -2.
1070 * @param size - the new font size as a String.
1072 public void setBaseFontSize(String size)
1074 size = size.trim();
1075 int temp = 0;
1078 if (size.length() == 2)
1080 int i = new Integer(size.substring(1)).intValue();
1081 if (size.startsWith("+"))
1082 temp = baseFontSize + i;
1083 else if (size.startsWith("-"))
1084 temp = baseFontSize - i;
1086 else if (size.length() == 1)
1087 temp = new Integer(size.substring(0)).intValue();
1089 if (temp <= 7 && temp >= 1)
1090 baseFontSize = temp;
1092 catch (NumberFormatException nfe)
1094 // Do nothing here
1099 * TODO
1101 * @param pt - TODO
1102 * @return TODO
1104 public static int getIndexOfSize(float pt)
1106 // FIXME: Not implemented.
1107 return 0;
1111 * Gets the point size, given a size index.
1113 * @param index - the size index
1114 * @return the point size.
1116 public float getPointSize(int index)
1118 // FIXME: Not implemented.
1119 return 0;
1123 * Given the string of the size, returns the point size value.
1125 * @param size - the string representation of the size.
1126 * @return - the point size value.
1128 public float getPointSize(String size)
1130 // FIXME: Not implemented.
1131 return 0;
1135 * Convert the color string represenation into java.awt.Color. The valid
1136 * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)".
1138 * @param colorName the color to convert.
1139 * @return the matching java.awt.color
1141 public Color stringToColor(String colorName)
1143 return CSSColor.convertValue(colorName);
1147 * This class carries out some of the duties of CSS formatting. This enables views
1148 * to present the CSS formatting while not knowing how the CSS values are cached.
1150 * This object is reponsible for the insets of a View and making sure
1151 * the background is maintained according to the CSS attributes.
1153 * @author Lillian Angel (langel@redhat.com)
1155 public static class BoxPainter extends Object implements Serializable
1159 * The left inset.
1161 private float leftInset;
1164 * The right inset.
1166 private float rightInset;
1169 * The top inset.
1171 private float topInset;
1174 * The bottom inset.
1176 private float bottomInset;
1179 * The border of the box.
1181 private Border border;
1183 private float leftPadding;
1184 private float rightPadding;
1185 private float topPadding;
1186 private float bottomPadding;
1189 * The background color.
1191 private Color background;
1194 * Package-private constructor.
1196 * @param as - AttributeSet for painter
1198 BoxPainter(AttributeSet as, StyleSheet ss)
1200 float emBase = ss.getEMBase(as);
1201 float exBase = ss.getEXBase(as);
1202 // Fetch margins.
1203 Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
1204 if (l != null)
1206 l.setFontBases(emBase, exBase);
1207 leftInset = l.getValue();
1209 l = (Length) as.getAttribute(CSS.Attribute.MARGIN_RIGHT);
1210 if (l != null)
1212 l.setFontBases(emBase, exBase);
1213 rightInset = l.getValue();
1215 l = (Length) as.getAttribute(CSS.Attribute.MARGIN_TOP);
1216 if (l != null)
1218 l.setFontBases(emBase, exBase);
1219 topInset = l.getValue();
1221 l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM);
1222 if (l != null)
1224 l.setFontBases(emBase, exBase);
1225 bottomInset = l.getValue();
1228 // Fetch padding.
1229 l = (Length) as.getAttribute(CSS.Attribute.PADDING_LEFT);
1230 if (l != null)
1232 l.setFontBases(emBase, exBase);
1233 leftPadding = l.getValue();
1235 l = (Length) as.getAttribute(CSS.Attribute.PADDING_RIGHT);
1236 if (l != null)
1238 l.setFontBases(emBase, exBase);
1239 rightPadding = l.getValue();
1241 l = (Length) as.getAttribute(CSS.Attribute.PADDING_TOP);
1242 if (l != null)
1244 l.setFontBases(emBase, exBase);
1245 topPadding = l.getValue();
1247 l = (Length) as.getAttribute(CSS.Attribute.PADDING_BOTTOM);
1248 if (l != null)
1250 l.setFontBases(emBase, exBase);
1251 bottomPadding = l.getValue();
1254 // Determine border.
1255 border = new CSSBorder(as, ss);
1257 // Determine background.
1258 background = ss.getBackground(as);
1264 * Gets the inset needed on a given side to account for the margin, border
1265 * and padding.
1267 * @param size - the size of the box to get the inset for. View.TOP, View.LEFT,
1268 * View.BOTTOM or View.RIGHT.
1269 * @param v - the view making the request. This is used to get the AttributeSet,
1270 * amd may be used to resolve percentage arguments.
1271 * @return the inset
1272 * @throws IllegalArgumentException - for an invalid direction.
1274 public float getInset(int size, View v)
1276 float inset;
1277 switch (size)
1279 case View.TOP:
1280 inset = topInset;
1281 if (border != null)
1282 inset += border.getBorderInsets(null).top;
1283 inset += topPadding;
1284 break;
1285 case View.BOTTOM:
1286 inset = bottomInset;
1287 if (border != null)
1288 inset += border.getBorderInsets(null).bottom;
1289 inset += bottomPadding;
1290 break;
1291 case View.LEFT:
1292 inset = leftInset;
1293 if (border != null)
1294 inset += border.getBorderInsets(null).left;
1295 inset += leftPadding;
1296 break;
1297 case View.RIGHT:
1298 inset = rightInset;
1299 if (border != null)
1300 inset += border.getBorderInsets(null).right;
1301 inset += rightPadding;
1302 break;
1303 default:
1304 inset = 0.0F;
1306 return inset;
1310 * Paints the CSS box according to the attributes given. This should
1311 * paint the border, padding and background.
1313 * @param g - the graphics configuration
1314 * @param x - the x coordinate
1315 * @param y - the y coordinate
1316 * @param w - the width of the allocated area
1317 * @param h - the height of the allocated area
1318 * @param v - the view making the request
1320 public void paint(Graphics g, float x, float y, float w, float h, View v)
1322 int inX = (int) (x + leftInset);
1323 int inY = (int) (y + topInset);
1324 int inW = (int) (w - leftInset - rightInset);
1325 int inH = (int) (h - topInset - bottomInset);
1326 if (background != null)
1328 g.setColor(background);
1329 g.fillRect(inX, inY, inW, inH);
1331 if (border != null)
1333 border.paintBorder(null, g, inX, inY, inW, inH);
1339 * This class carries out some of the CSS list formatting duties. Implementations
1340 * of this class enable views to present the CSS formatting while not knowing anything
1341 * about how the CSS values are being cached.
1343 * @author Lillian Angel (langel@redhat.com)
1345 public static class ListPainter implements Serializable
1349 * Attribute set for painter
1351 private AttributeSet attributes;
1354 * The associated style sheet.
1356 private StyleSheet styleSheet;
1359 * The bullet type.
1361 private String type;
1364 * Package-private constructor.
1366 * @param as - AttributeSet for painter
1368 ListPainter(AttributeSet as, StyleSheet ss)
1370 attributes = as;
1371 styleSheet = ss;
1372 type = (String) as.getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
1376 * Cached rectangle re-used in the paint method below.
1378 private final Rectangle tmpRect = new Rectangle();
1381 * Paints the CSS list decoration according to the attributes given.
1383 * @param g - the graphics configuration
1384 * @param x - the x coordinate
1385 * @param y - the y coordinate
1386 * @param w - the width of the allocated area
1387 * @param h - the height of the allocated area
1388 * @param v - the view making the request
1389 * @param item - the list item to be painted >=0.
1391 public void paint(Graphics g, float x, float y, float w, float h, View v,
1392 int item)
1394 // FIXME: This is a very simplistic list rendering. We still need
1395 // to implement different bullet types (see type field) and custom
1396 // bullets via images.
1397 View itemView = v.getView(item);
1398 AttributeSet viewAtts = itemView.getAttributes();
1399 Object tag = viewAtts.getAttribute(StyleConstants.NameAttribute);
1400 // Only paint something here when the child view is an LI tag
1401 // and the calling view is some of the list tags then).
1402 if (tag != null && tag == HTML.Tag.LI)
1404 g.setColor(Color.BLACK);
1405 int centerX = (int) (x - 12);
1406 int centerY = -1;
1407 // For paragraphs (almost all cases) center bullet vertically
1408 // in the middle of the first line.
1409 tmpRect.setBounds((int) x, (int) y, (int) w, (int) h);
1410 if (itemView.getViewCount() > 0)
1412 View v1 = itemView.getView(0);
1413 if (v1 instanceof ParagraphView && v1.getViewCount() > 0)
1415 Shape a1 = itemView.getChildAllocation(0, tmpRect);
1416 Rectangle r1 = a1 instanceof Rectangle ? (Rectangle) a1
1417 : a1.getBounds();
1418 ParagraphView par = (ParagraphView) v1;
1419 Shape a = par.getChildAllocation(0, r1);
1420 if (a != null)
1422 Rectangle r = a instanceof Rectangle ? (Rectangle) a
1423 : a.getBounds();
1424 centerY = (int) (r.height / 2 + r.y);
1428 if (centerY == -1)
1430 centerY =(int) (h / 2 + y);
1432 g.fillOval(centerX - 3, centerY - 3, 6, 6);
1438 * Converts an AttributeSet to a Map. This is used for CSS resolving.
1440 * @param atts the attributes to convert
1442 * @return the converted map
1444 private Map attributeSetToMap(AttributeSet atts)
1446 HashMap<String,String> map = new HashMap<String,String>();
1447 Enumeration<?> keys = atts.getAttributeNames();
1448 while (keys.hasMoreElements())
1450 Object key = keys.nextElement();
1451 Object value = atts.getAttribute(key);
1452 map.put(key.toString(), value.toString());
1454 return map;