OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [text/] [html/] [StyleSheet.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* StyleSheet.java --
2
   Copyright (C) 2005 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
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.
10
 
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.
15
 
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.
20
 
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.
25
 
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. */
37
 
38
 
39
package javax.swing.text.html;
40
 
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;
50
 
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;
73
 
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;
84
 
85
 
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.
93
 *
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.
98
 *
99
 *  The rules are stored as named styles, and other information is stored to
100
 *  translate the context of an element to a rule.
101
 *
102
 * @author Lillian Angel (langel@redhat.com)
103
 */
104
public class StyleSheet extends StyleContext
105
{
106
 
107
  /**
108
   * Parses CSS stylesheets using the parser in gnu/javax/swing/html/css.
109
   *
110
   * This is package private to avoid accessor methods.
111
   */
112
  class CSSStyleSheetParserCallback
113
    implements CSSParserCallback
114
  {
115
    /**
116
     * The current styles.
117
     */
118
    private CSSStyle[] styles;
119
 
120
    /**
121
     * The precedence of the stylesheet to be parsed.
122
     */
123
    private int precedence;
124
 
125
    /**
126
     * Creates a new CSS parser. This parser parses a CSS stylesheet with
127
     * the specified precedence.
128
     *
129
     * @param prec the precedence, according to the constants defined in
130
     *        CSSStyle
131
     */
132
    CSSStyleSheetParserCallback(int prec)
133
    {
134
      precedence = prec;
135
    }
136
 
137
    /**
138
     * Called at the beginning of a statement.
139
     *
140
     * @param sel the selector
141
     */
142
    public void startStatement(Selector[] sel)
143
    {
144
      styles = new CSSStyle[sel.length];
145
      for (int i = 0; i < sel.length; i++)
146
        styles[i] = new CSSStyle(precedence, sel[i]);
147
    }
148
 
149
    /**
150
     * Called at the end of a statement.
151
     */
152
    public void endStatement()
153
    {
154
      for (int i = 0; i < styles.length; i++)
155
        css.add(styles[i]);
156
      styles = null;
157
    }
158
 
159
    /**
160
     * Called when a declaration is parsed.
161
     *
162
     * @param property the property
163
     * @param value the value
164
     */
165
    public void declaration(String property, String value)
166
    {
167
      CSS.Attribute cssAtt = CSS.getAttribute(property);
168
      Object val = CSS.getValue(cssAtt, value);
169
      for (int i = 0; i < styles.length; i++)
170
        {
171
          CSSStyle style = styles[i];
172
          CSS.addInternal(style, cssAtt, value);
173
          if (cssAtt != null)
174
            style.addAttribute(cssAtt, val);
175
        }
176
    }
177
 
178
  }
179
 
180
  /**
181
   * Represents a style that is defined by a CSS rule.
182
   */
183
  private class CSSStyle
184
    extends SimpleAttributeSet
185
    implements Style, Comparable<CSSStyle>
186
  {
187
 
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;
193
 
194
    /**
195
     * The priority of this style when matching CSS selectors.
196
     */
197
    private int precedence;
198
 
199
    /**
200
     * The selector for this rule.
201
     *
202
     * This is package private to avoid accessor methods.
203
     */
204
    Selector selector;
205
 
206
    CSSStyle(int prec, Selector sel)
207
    {
208
      precedence = prec;
209
      selector = sel;
210
    }
211
 
212
    public String getName()
213
    {
214
      // TODO: Implement this for correctness.
215
      return null;
216
    }
217
 
218
    public void addChangeListener(ChangeListener listener)
219
    {
220
      // TODO: Implement this for correctness.
221
    }
222
 
223
    public void removeChangeListener(ChangeListener listener)
224
    {
225
      // TODO: Implement this for correctness.
226
    }
227
 
228
    /**
229
     * Sorts the rule according to the style's precedence and the
230
     * selectors specificity.
231
     */
232
    public int compareTo(CSSStyle other)
233
    {
234
      return other.precedence + other.selector.getSpecificity()
235
             - precedence - selector.getSpecificity();
236
    }
237
 
238
  }
239
 
240
  /** The base URL */
241
  URL base;
242
 
243
  /** Base font size (int) */
244
  int baseFontSize;
245
 
246
  /**
247
   * The linked style sheets stored.
248
   */
249
  private ArrayList<StyleSheet> linked;
250
 
251
  /**
252
   * Maps element names (selectors) to AttributSet (the corresponding style
253
   * information).
254
   */
255
  ArrayList<CSSStyle> css = new ArrayList<CSSStyle>();
256
 
257
  /**
258
   * Maps selectors to their resolved styles.
259
   */
260
  private HashMap<String,Style> resolvedStyles;
261
 
262
  /**
263
   * Constructs a StyleSheet.
264
   */
265
  public StyleSheet()
266
  {
267
    super();
268
    baseFontSize = 4; // Default font size from CSS
269
    resolvedStyles = new HashMap<String,Style>();
270
  }
271
 
272
  /**
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.
276
   *
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.
280
   */
281
  public Style getRule(HTML.Tag t, Element e)
282
  {
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);
290
 
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--)
296
      {
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))
302
          {
303
            selector.append('#');
304
            selector.append(atts.getAttribute(HTML.Attribute.ID));
305
          }
306
        if (atts.isDefined(HTML.Attribute.CLASS))
307
          {
308
            selector.append('.');
309
            selector.append(atts.getAttribute(HTML.Attribute.CLASS));
310
          }
311
        if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
312
          {
313
            selector.append(':');
314
            selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
315
          }
316
        if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
317
          {
318
            selector.append(':');
319
            selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
320
          }
321
        selector.append(' ');
322
      }
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())
328
      {
329
        Object o = atts.getAttribute(t);
330
        if (o instanceof AttributeSet)
331
          atts = (AttributeSet) o;
332
        else
333
          atts = null;
334
      }
335
    if (atts != null)
336
      {
337
        if (atts.isDefined(HTML.Attribute.ID))
338
          {
339
            selector.append('#');
340
            selector.append(atts.getAttribute(HTML.Attribute.ID));
341
          }
342
        if (atts.isDefined(HTML.Attribute.CLASS))
343
          {
344
            selector.append('.');
345
            selector.append(atts.getAttribute(HTML.Attribute.CLASS));
346
          }
347
        if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
348
          {
349
            selector.append(':');
350
            selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
351
          }
352
        if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
353
          {
354
            selector.append(':');
355
            selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
356
          }
357
      }
358
    return getResolvedStyle(selector.toString(), path, t);
359
  }
360
 
361
  /**
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)}.
365
   *
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
369
   *
370
   * @return the resolved style
371
   */
372
  private Style getResolvedStyle(String selector, List<Element> path, HTML.Tag tag)
373
  {
374
    Style style = resolvedStyles.get(selector);
375
    if (style == null)
376
      style = resolveStyle(selector, path, tag);
377
    return style;
378
  }
379
 
380
  /**
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[], List<Map<String,String>>)}.
384
   *
385
   * @param selector the selector
386
   * @param path the Element path
387
   * @param tag the tag
388
   *
389
   * @return the resolved style
390
   */
391
  private Style resolveStyle(String selector, List<Element> path, HTML.Tag tag)
392
  {
393
    int count = path.size();
394
    String[] tags = new String[count];
395
    List<Map<String,String>> attributes =
396
      new ArrayList<Map<String,String>>(count);
397
    for (int i = 0; i < count; i++)
398
      {
399
        Element el = path.get(i);
400
        AttributeSet atts = el.getAttributes();
401
        if (i == 0 && el.isLeaf())
402
          {
403
            Object o = atts.getAttribute(tag);
404
            if (o instanceof AttributeSet)
405
              atts = (AttributeSet) o;
406
            else
407
              atts = null;
408
          }
409
        if (atts != null)
410
          {
411
            HTML.Tag t =
412
              (HTML.Tag) atts.getAttribute(StyleConstants.NameAttribute);
413
            if (t != null)
414
              tags[i] = t.toString();
415
            else
416
              tags[i] = null;
417
            attributes.set(i, attributeSetToMap(atts));
418
          }
419
        else
420
          {
421
            tags[i] = null;
422
          }
423
      }
424
    tags[0] = tag.toString();
425
    return resolveStyle(selector, tags, attributes);
426
  }
427
 
428
  /**
429
   * Performs style resolving.
430
   *
431
   * @param selector the selector
432
   * @param tags the tags
433
   * @param attributes the attributes of the tags
434
   *
435
   * @return the resolved style
436
   */
437
  private Style resolveStyle(String selector, String[] tags,
438
                             List<Map<String,String>> attributes)
439
  {
440
    // FIXME: This style resolver is not correct. But it works good enough for
441
    // the default.css.
442
    ArrayList<CSSStyle> styles = new ArrayList<CSSStyle>();
443
    for (CSSStyle style : css)
444
      {
445
        if (style.selector.matches(tags, attributes))
446
          styles.add(style);
447
      }
448
 
449
    // Add styles from linked stylesheets.
450
    if (linked != null)
451
      {
452
        for (int i = linked.size() - 1; i >= 0; i--)
453
          {
454
            StyleSheet ss = linked.get(i);
455
            for (int j = ss.css.size() - 1; j >= 0; j--)
456
              {
457
                CSSStyle style = ss.css.get(j);
458
                if (style.selector.matches(tags, attributes))
459
                  styles.add(style);
460
              }
461
          }
462
      }
463
 
464
    // Sort selectors.
465
    Collections.sort(styles);
466
    Style[] styleArray = styles.toArray(new Style[styles.size()]);
467
    Style resolved = new MultiStyle(selector, styleArray);
468
    resolvedStyles.put(selector, resolved);
469
    return resolved;
470
  }
471
 
472
  /**
473
   * Gets the rule that best matches the selector. selector is a space
474
   * separated String of element names. The attributes of the returned
475
   * Style will change as rules are added and removed.
476
   *
477
   * @param selector - the element names separated by spaces
478
   * @return the set of CSS attributes to use to render
479
   */
480
  public Style getRule(String selector)
481
  {
482
    CSSStyle best = null;
483
    for (Iterator<CSSStyle> i = css.iterator(); i.hasNext();)
484
      {
485
        CSSStyle style = i.next();
486
        if (style.compareTo(best) < 0)
487
          best = style;
488
      }
489
    return best;
490
  }
491
 
492
  /**
493
   * Adds a set of rules to the sheet. The rules are expected to be in valid
494
   * CSS format. This is called as a result of parsing a <style> tag
495
   *
496
   * @param rule - the rule to add to the sheet
497
   */
498
  public void addRule(String rule)
499
  {
500
    CSSStyleSheetParserCallback cb =
501
      new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
502
    // FIXME: Handle ref.
503
    StringReader in = new StringReader(rule);
504
    CSSParser parser = new CSSParser(in, cb);
505
    try
506
      {
507
        parser.parse();
508
      }
509
    catch (IOException ex)
510
      {
511
        // Shouldn't happen. And if, then don't let it bork the outside code.
512
      }
513
    // Clean up resolved styles cache so that the new styles are recognized
514
    // on next stylesheet request.
515
    resolvedStyles.clear();
516
  }
517
 
518
  /**
519
   * Translates a CSS declaration into an AttributeSet. This is called
520
   * as a result of encountering an HTML style attribute.
521
   *
522
   * @param decl - the declaration to get
523
   * @return the AttributeSet representing the declaration
524
   */
525
  public AttributeSet getDeclaration(String decl)
526
  {
527
    if (decl == null)
528
      return SimpleAttributeSet.EMPTY;
529
    // FIXME: Not implemented.
530
    return null;
531
  }
532
 
533
  /**
534
   * Loads a set of rules that have been specified in terms of CSS grammar.
535
   * If there are any conflicts with existing rules, the new rule is added.
536
   *
537
   * @param in - the stream to read the CSS grammar from.
538
   * @param ref - the reference URL. It is the location of the stream, it may
539
   * be null. All relative URLs specified in the stream will be based upon this
540
   * parameter.
541
   * @throws IOException - For any IO error while reading
542
   */
543
  public void loadRules(Reader in, URL ref)
544
    throws IOException
545
  {
546
    CSSStyleSheetParserCallback cb =
547
      new CSSStyleSheetParserCallback(CSSStyle.PREC_UA);
548
    // FIXME: Handle ref.
549
    CSSParser parser = new CSSParser(in, cb);
550
    parser.parse();
551
  }
552
 
553
  /**
554
   * Gets a set of attributes to use in the view. This is a set of
555
   * attributes that can be used for View.getAttributes
556
   *
557
   * @param v - the view to get the set for
558
   * @return the AttributeSet to use in the view.
559
   */
560
  public AttributeSet getViewAttributes(View v)
561
  {
562
    return new ViewAttributeSet(v, this);
563
  }
564
 
565
  /**
566
   * Removes a style previously added.
567
   *
568
   * @param nm - the name of the style to remove
569
   */
570
  public void removeStyle(String nm)
571
  {
572
    // FIXME: Not implemented.
573
    super.removeStyle(nm);
574
  }
575
 
576
  /**
577
   * Adds the rules from ss to those of the receiver. ss's rules will
578
   * override the old rules. An added StyleSheet will never override the rules
579
   * of the receiving style sheet.
580
   *
581
   * @param ss - the new StyleSheet.
582
   */
583
  public void addStyleSheet(StyleSheet ss)
584
  {
585
    if (linked == null)
586
      linked = new ArrayList<StyleSheet>();
587
    linked.add(ss);
588
  }
589
 
590
  /**
591
   * Removes ss from those of the receiver
592
   *
593
   * @param ss - the StyleSheet to remove.
594
   */
595
  public void removeStyleSheet(StyleSheet ss)
596
  {
597
    if (linked != null)
598
      {
599
        linked.remove(ss);
600
      }
601
  }
602
 
603
  /**
604
   * Returns an array of the linked StyleSheets. May return null.
605
   *
606
   * @return - An array of the linked StyleSheets.
607
   */
608
  public StyleSheet[] getStyleSheets()
609
  {
610
    StyleSheet[] linkedSS;
611
    if (linked != null)
612
      {
613
        linkedSS = new StyleSheet[linked.size()];
614
        linkedSS = linked.toArray(linkedSS);
615
      }
616
    else
617
      {
618
        linkedSS = null;
619
      }
620
    return linkedSS;
621
  }
622
 
623
  /**
624
   * Imports a style sheet from the url. The rules are directly added to the
625
   * receiver. This is usually called when a <link> tag is resolved in an
626
   * HTML document.
627
   *
628
   * @param url the URL to import the StyleSheet from
629
   */
630
  public void importStyleSheet(URL url)
631
  {
632
    try
633
      {
634
        InputStream in = url.openStream();
635
        Reader r = new BufferedReader(new InputStreamReader(in));
636
        CSSStyleSheetParserCallback cb =
637
          new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
638
        CSSParser parser = new CSSParser(r, cb);
639
        parser.parse();
640
      }
641
    catch (IOException ex)
642
      {
643
        // We can't do anything about it I guess.
644
      }
645
  }
646
 
647
  /**
648
   * Sets the base url. All import statements that are relative, will be
649
   * relative to base.
650
   *
651
   * @param base -
652
   *          the base URL.
653
   */
654
  public void setBase(URL base)
655
  {
656
    this.base = base;
657
  }
658
 
659
  /**
660
   * Gets the base url.
661
   *
662
   * @return - the base
663
   */
664
  public URL getBase()
665
  {
666
    return base;
667
  }
668
 
669
  /**
670
   * Adds a CSS attribute to the given set.
671
   *
672
   * @param attr - the attribute set
673
   * @param key - the attribute to add
674
   * @param value - the value of the key
675
   */
676
  public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key,
677
                              String value)
678
  {
679
    Object val = CSS.getValue(key, value);
680
    CSS.addInternal(attr, key, value);
681
    attr.addAttribute(key, val);
682
  }
683
 
684
  /**
685
   * Adds a CSS attribute to the given set.
686
   * This method parses the value argument from HTML based on key.
687
   * Returns true if it finds a valid value for the given key,
688
   * and false otherwise.
689
   *
690
   * @param attr - the attribute set
691
   * @param key - the attribute to add
692
   * @param value - the value of the key
693
   * @return true if a valid value was found.
694
   */
695
  public boolean addCSSAttributeFromHTML(MutableAttributeSet attr, CSS.Attribute key,
696
                                         String value)
697
  {
698
    // FIXME: Need to parse value from HTML based on key.
699
    attr.addAttribute(key, value);
700
    return attr.containsAttribute(key, value);
701
  }
702
 
703
  /**
704
   * Converts a set of HTML attributes to an equivalent set of CSS attributes.
705
   *
706
   * @param htmlAttrSet - the set containing the HTML attributes.
707
   * @return the set of CSS attributes
708
   */
709
  public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet)
710
  {
711
    AttributeSet cssAttr = htmlAttrSet.copyAttributes();
712
 
713
    // The HTML align attribute maps directly to the CSS text-align attribute.
714
    Object o = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
715
    if (o != null)
716
      cssAttr = addAttribute(cssAttr, CSS.Attribute.TEXT_ALIGN, o);
717
 
718
    // The HTML width attribute maps directly to CSS width.
719
    o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH);
720
    if (o != null)
721
      cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH,
722
                             new Length(o.toString()));
723
 
724
    // The HTML height attribute maps directly to CSS height.
725
    o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT);
726
    if (o != null)
727
      cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT,
728
                             new Length(o.toString()));
729
 
730
    o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP);
731
    if (o != null)
732
      cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap");
733
 
734
    // Map cellspacing attr of tables to CSS border-spacing.
735
    o = htmlAttrSet.getAttribute(HTML.Attribute.CELLSPACING);
736
    if (o != null)
737
      cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_SPACING,
738
                             new Length(o.toString()));
739
 
740
    // For table cells and headers, fetch the cellpadding value from the
741
    // parent table and set it as CSS padding attribute.
742
    HTML.Tag tag = (HTML.Tag)
743
                   htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
744
    if ((tag == HTML.Tag.TD || tag == HTML.Tag.TH)
745
        && htmlAttrSet instanceof Element)
746
      {
747
        Element el = (Element) htmlAttrSet;
748
        AttributeSet tableAttrs = el.getParentElement().getParentElement()
749
                                  .getAttributes();
750
        o = tableAttrs.getAttribute(HTML.Attribute.CELLPADDING);
751
        if (o != null)
752
          {
753
            Length l = new Length(o.toString());
754
            cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_BOTTOM, l);
755
            cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_LEFT, l);
756
            cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_RIGHT, l);
757
            cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_TOP, l);
758
          }
759
        o = tableAttrs.getAttribute(HTML.Attribute.BORDER);
760
        cssAttr = translateBorder(cssAttr, o);
761
      }
762
 
763
    // Translate border attribute.
764
    o = cssAttr.getAttribute(HTML.Attribute.BORDER);
765
    cssAttr = translateBorder(cssAttr, o);
766
 
767
    // TODO: Add more mappings.
768
    return cssAttr;
769
  }
770
 
771
  /**
772
   * Translates a HTML border attribute to a corresponding set of CSS
773
   * attributes.
774
   *
775
   * @param cssAttr the original set of CSS attributes to add to
776
   * @param o the value of the border attribute
777
   *
778
   * @return the new set of CSS attributes
779
   */
780
  private AttributeSet translateBorder(AttributeSet cssAttr, Object o)
781
  {
782
    if (o != null)
783
      {
784
        BorderWidth l = new BorderWidth(o.toString());
785
        if (l.getValue() > 0)
786
          {
787
            cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_WIDTH, l);
788
            cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_STYLE,
789
                                   "solid");
790
            cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_COLOR,
791
                                   new CSSColor("black"));
792
          }
793
      }
794
    return cssAttr;
795
  }
796
 
797
  /**
798
   * Adds an attribute to the given set and returns a new set. This is implemented
799
   * to convert StyleConstants attributes to CSS before forwarding them to the superclass.
800
   * The StyleConstants attribute do not have corresponding CSS entry, the attribute
801
   * is stored (but will likely not be used).
802
   *
803
   * @param old - the old set
804
   * @param key - the non-null attribute key
805
   * @param value - the attribute value
806
   * @return the updated set
807
   */
808
  public AttributeSet addAttribute(AttributeSet old, Object key,
809
                                   Object value)
810
  {
811
    // FIXME: Not implemented.
812
    return super.addAttribute(old, key, value);
813
  }
814
 
815
  /**
816
   * Adds a set of attributes to the element. If any of these attributes are
817
   * StyleConstants, they will be converted to CSS before forwarding to the
818
   * superclass.
819
   *
820
   * @param old - the old set
821
   * @param attr - the attributes to add
822
   * @return the updated attribute set
823
   */
824
  public AttributeSet addAttributes(AttributeSet old, AttributeSet attr)
825
  {
826
    // FIXME: Not implemented.
827
    return super.addAttributes(old, attr);
828
  }
829
 
830
  /**
831
   * Removes an attribute from the set. If the attribute is a
832
   * StyleConstants, it will be converted to CSS before forwarding to the
833
   * superclass.
834
   *
835
   * @param old - the old set
836
   * @param key - the non-null attribute key
837
   * @return the updated set
838
   */
839
  public AttributeSet removeAttribute(AttributeSet old, Object key)
840
  {
841
    // FIXME: Not implemented.
842
    return super.removeAttribute(old, key);
843
  }
844
 
845
  /**
846
   * Removes an attribute from the set. If any of the attributes are
847
   * StyleConstants, they will be converted to CSS before forwarding to the
848
   * superclass.
849
   *
850
   * @param old - the old set
851
   * @param attrs - the attributes to remove
852
   * @return the updated set
853
   */
854
  public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs)
855
  {
856
    // FIXME: Not implemented.
857
    return super.removeAttributes(old, attrs);
858
  }
859
 
860
  /**
861
   * Removes a set of attributes for the element. If any of the attributes is a
862
   * StyleConstants, they will be converted to CSS before forwarding to the
863
   * superclass.
864
   *
865
   * @param old - the old attribute set
866
   * @param names - the attribute names
867
   * @return the update attribute set
868
   */
869
  public AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names)
870
  {
871
    // FIXME: Not implemented.
872
    return super.removeAttributes(old, names);
873
  }
874
 
875
  /**
876
   * Creates a compact set of attributes that might be shared. This is a hook
877
   * for subclasses that want to change the behaviour of SmallAttributeSet.
878
   *
879
   * @param a - the set of attributes to be represented in the compact form.
880
   * @return the set of attributes created
881
   */
882
  protected StyleContext.SmallAttributeSet createSmallAttributeSet(AttributeSet a)
883
  {
884
    return super.createSmallAttributeSet(a);
885
  }
886
 
887
  /**
888
   * Creates a large set of attributes. This set is not shared. This is a hook
889
   * for subclasses that want to change the behaviour of the larger attribute
890
   * storage format.
891
   *
892
   * @param a - the set of attributes to be represented in the larger form.
893
   * @return the large set of attributes.
894
   */
895
  protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
896
  {
897
    return super.createLargeAttributeSet(a);
898
  }
899
 
900
  /**
901
   * Gets the font to use for the given set.
902
   *
903
   * @param a - the set to get the font for.
904
   * @return the font for the set
905
   */
906
  public Font getFont(AttributeSet a)
907
  {
908
    int realSize = getFontSize(a);
909
 
910
    // Decrement size for subscript and superscript.
911
    Object valign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
912
    if (valign != null)
913
      {
914
        String v = valign.toString();
915
        if (v.contains("sup") || v.contains("sub"))
916
          realSize -= 2;
917
      }
918
 
919
    // TODO: Convert font family.
920
    String family = "SansSerif";
921
 
922
    int style = Font.PLAIN;
923
    FontWeight weight = (FontWeight) a.getAttribute(CSS.Attribute.FONT_WEIGHT);
924
    if (weight != null)
925
      style |= weight.getValue();
926
    FontStyle fStyle = (FontStyle) a.getAttribute(CSS.Attribute.FONT_STYLE);
927
    if (fStyle != null)
928
      style |= fStyle.getValue();
929
    return new Font(family, style, realSize);
930
  }
931
 
932
  /**
933
   * Determines the EM base value based on the specified attributes.
934
   *
935
   * @param atts the attibutes
936
   *
937
   * @return the EM base value
938
   */
939
  float getEMBase(AttributeSet atts)
940
  {
941
    Font font = getFont(atts);
942
    FontRenderContext ctx = new FontRenderContext(null, false, false);
943
    Rectangle2D bounds = font.getStringBounds("M", ctx);
944
    return (float) bounds.getWidth();
945
  }
946
 
947
  /**
948
   * Determines the EX base value based on the specified attributes.
949
   *
950
   * @param atts the attibutes
951
   *
952
   * @return the EX base value
953
   */
954
  float getEXBase(AttributeSet atts)
955
  {
956
    Font font = getFont(atts);
957
    FontRenderContext ctx = new FontRenderContext(null, false, false);
958
    Rectangle2D bounds = font.getStringBounds("x", ctx);
959
    return (float) bounds.getHeight();
960
  }
961
 
962
  /**
963
   * Resolves the fontsize for a given set of attributes.
964
   *
965
   * @param atts the attributes
966
   *
967
   * @return the resolved font size
968
   */
969
  private int getFontSize(AttributeSet atts)
970
  {
971
    int size = 12;
972
    if (atts.isDefined(CSS.Attribute.FONT_SIZE))
973
      {
974
        FontSize fs = (FontSize) atts.getAttribute(CSS.Attribute.FONT_SIZE);
975
        if (fs.isRelative())
976
          {
977
            int parSize = 12;
978
            AttributeSet resolver = atts.getResolveParent();
979
            if (resolver != null)
980
              parSize = getFontSize(resolver);
981
            size = fs.getValue(parSize);
982
          }
983
        else
984
          {
985
            size = fs.getValue();
986
          }
987
      }
988
    else
989
      {
990
        AttributeSet resolver = atts.getResolveParent();
991
        if (resolver != null)
992
          size = getFontSize(resolver);
993
      }
994
    return size;
995
  }
996
 
997
  /**
998
   * Takes a set of attributes and turns it into a foreground
999
   * color specification. This is used to specify things like, brigher, more hue
1000
   * etc.
1001
   *
1002
   * @param a - the set to get the foreground color for
1003
   * @return the foreground color for the set
1004
   */
1005
  public Color getForeground(AttributeSet a)
1006
  {
1007
    CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.COLOR);
1008
    Color color = null;
1009
    if (c != null)
1010
      color = c.getValue();
1011
    return color;
1012
  }
1013
 
1014
  /**
1015
   * Takes a set of attributes and turns it into a background
1016
   * color specification. This is used to specify things like, brigher, more hue
1017
   * etc.
1018
   *
1019
   * @param a - the set to get the background color for
1020
   * @return the background color for the set
1021
   */
1022
  public Color getBackground(AttributeSet a)
1023
  {
1024
    CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.BACKGROUND_COLOR);
1025
    Color color = null;
1026
    if (c != null)
1027
      color = c.getValue();
1028
    return color;
1029
  }
1030
 
1031
  /**
1032
   * Gets the box formatter to use for the given set of CSS attributes.
1033
   *
1034
   * @param a - the given set
1035
   * @return the box formatter
1036
   */
1037
  public BoxPainter getBoxPainter(AttributeSet a)
1038
  {
1039
    return new BoxPainter(a, this);
1040
  }
1041
 
1042
  /**
1043
   * Gets the list formatter to use for the given set of CSS attributes.
1044
   *
1045
   * @param a - the given set
1046
   * @return the list formatter
1047
   */
1048
  public ListPainter getListPainter(AttributeSet a)
1049
  {
1050
    return new ListPainter(a, this);
1051
  }
1052
 
1053
  /**
1054
   * Sets the base font size between 1 and 7.
1055
   *
1056
   * @param sz - the new font size for the base.
1057
   */
1058
  public void setBaseFontSize(int sz)
1059
  {
1060
    if (sz <= 7 && sz >= 1)
1061
      baseFontSize = sz;
1062
  }
1063
 
1064
  /**
1065
   * Sets the base font size from the String. It can either identify
1066
   * a specific font size (between 1 and 7) or identify a relative
1067
   * font size such as +1 or -2.
1068
   *
1069
   * @param size - the new font size as a String.
1070
   */
1071
  public void setBaseFontSize(String size)
1072
  {
1073
    size = size.trim();
1074
    int temp = 0;
1075
    try
1076
      {
1077
        if (size.length() == 2)
1078
          {
1079
            int i = new Integer(size.substring(1)).intValue();
1080
            if (size.startsWith("+"))
1081
              temp = baseFontSize + i;
1082
            else if (size.startsWith("-"))
1083
              temp = baseFontSize - i;
1084
          }
1085
        else if (size.length() == 1)
1086
          temp = new Integer(size.substring(0)).intValue();
1087
 
1088
        if (temp <= 7 && temp >= 1)
1089
          baseFontSize = temp;
1090
      }
1091
    catch (NumberFormatException nfe)
1092
      {
1093
        // Do nothing here
1094
      }
1095
  }
1096
 
1097
  /**
1098
   * TODO
1099
   *
1100
   * @param pt - TODO
1101
   * @return TODO
1102
   */
1103
  public static int getIndexOfSize(float pt)
1104
  {
1105
    // FIXME: Not implemented.
1106
    return 0;
1107
  }
1108
 
1109
  /**
1110
   * Gets the point size, given a size index.
1111
   *
1112
   * @param index - the size index
1113
   * @return the point size.
1114
   */
1115
  public float getPointSize(int index)
1116
  {
1117
    // FIXME: Not implemented.
1118
    return 0;
1119
  }
1120
 
1121
  /**
1122
   * Given the string of the size, returns the point size value.
1123
   *
1124
   * @param size - the string representation of the size.
1125
   * @return - the point size value.
1126
   */
1127
  public float getPointSize(String size)
1128
  {
1129
    // FIXME: Not implemented.
1130
    return 0;
1131
  }
1132
 
1133
  /**
1134
   * Convert the color string represenation into java.awt.Color. The valid
1135
   * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)".
1136
   *
1137
   * @param colorName the color to convert.
1138
   * @return the matching java.awt.color
1139
   */
1140
  public Color stringToColor(String colorName)
1141
  {
1142
    return CSSColor.convertValue(colorName);
1143
  }
1144
 
1145
  /**
1146
   * This class carries out some of the duties of CSS formatting. This enables views
1147
   * to present the CSS formatting while not knowing how the CSS values are cached.
1148
   *
1149
   * This object is reponsible for the insets of a View and making sure
1150
   * the background is maintained according to the CSS attributes.
1151
   *
1152
   * @author Lillian Angel (langel@redhat.com)
1153
   */
1154
  public static class BoxPainter extends Object implements Serializable
1155
  {
1156
 
1157
    /**
1158
     * The left inset.
1159
     */
1160
    private float leftInset;
1161
 
1162
    /**
1163
     * The right inset.
1164
     */
1165
    private float rightInset;
1166
 
1167
    /**
1168
     * The top inset.
1169
     */
1170
    private float topInset;
1171
 
1172
    /**
1173
     * The bottom inset.
1174
     */
1175
    private float bottomInset;
1176
 
1177
    /**
1178
     * The border of the box.
1179
     */
1180
    private Border border;
1181
 
1182
    private float leftPadding;
1183
    private float rightPadding;
1184
    private float topPadding;
1185
    private float bottomPadding;
1186
 
1187
    /**
1188
     * The background color.
1189
     */
1190
    private Color background;
1191
 
1192
    /**
1193
     * Package-private constructor.
1194
     *
1195
     * @param as - AttributeSet for painter
1196
     */
1197
    BoxPainter(AttributeSet as, StyleSheet ss)
1198
    {
1199
      float emBase = ss.getEMBase(as);
1200
      float exBase = ss.getEXBase(as);
1201
      // Fetch margins.
1202
      Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
1203
      if (l != null)
1204
        {
1205
          l.setFontBases(emBase, exBase);
1206
          leftInset = l.getValue();
1207
        }
1208
      l = (Length) as.getAttribute(CSS.Attribute.MARGIN_RIGHT);
1209
      if (l != null)
1210
        {
1211
          l.setFontBases(emBase, exBase);
1212
          rightInset = l.getValue();
1213
        }
1214
      l = (Length) as.getAttribute(CSS.Attribute.MARGIN_TOP);
1215
      if (l != null)
1216
        {
1217
          l.setFontBases(emBase, exBase);
1218
          topInset = l.getValue();
1219
        }
1220
      l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM);
1221
      if (l != null)
1222
        {
1223
          l.setFontBases(emBase, exBase);
1224
          bottomInset = l.getValue();
1225
        }
1226
 
1227
      // Fetch padding.
1228
      l = (Length) as.getAttribute(CSS.Attribute.PADDING_LEFT);
1229
      if (l != null)
1230
        {
1231
          l.setFontBases(emBase, exBase);
1232
          leftPadding = l.getValue();
1233
        }
1234
      l = (Length) as.getAttribute(CSS.Attribute.PADDING_RIGHT);
1235
      if (l != null)
1236
        {
1237
          l.setFontBases(emBase, exBase);
1238
          rightPadding = l.getValue();
1239
        }
1240
      l = (Length) as.getAttribute(CSS.Attribute.PADDING_TOP);
1241
      if (l != null)
1242
        {
1243
          l.setFontBases(emBase, exBase);
1244
          topPadding = l.getValue();
1245
        }
1246
      l = (Length) as.getAttribute(CSS.Attribute.PADDING_BOTTOM);
1247
      if (l != null)
1248
        {
1249
          l.setFontBases(emBase, exBase);
1250
          bottomPadding = l.getValue();
1251
        }
1252
 
1253
      // Determine border.
1254
      border = new CSSBorder(as, ss);
1255
 
1256
      // Determine background.
1257
      background = ss.getBackground(as);
1258
 
1259
    }
1260
 
1261
 
1262
    /**
1263
     * Gets the inset needed on a given side to account for the margin, border
1264
     * and padding.
1265
     *
1266
     * @param size - the size of the box to get the inset for. View.TOP, View.LEFT,
1267
     * View.BOTTOM or View.RIGHT.
1268
     * @param v - the view making the request. This is used to get the AttributeSet,
1269
     * amd may be used to resolve percentage arguments.
1270
     * @return the inset
1271
     * @throws IllegalArgumentException - for an invalid direction.
1272
     */
1273
    public float getInset(int size, View v)
1274
    {
1275
      float inset;
1276
      switch (size)
1277
        {
1278
        case View.TOP:
1279
          inset = topInset;
1280
          if (border != null)
1281
            inset += border.getBorderInsets(null).top;
1282
          inset += topPadding;
1283
          break;
1284
        case View.BOTTOM:
1285
          inset = bottomInset;
1286
          if (border != null)
1287
            inset += border.getBorderInsets(null).bottom;
1288
          inset += bottomPadding;
1289
          break;
1290
        case View.LEFT:
1291
          inset = leftInset;
1292
          if (border != null)
1293
            inset += border.getBorderInsets(null).left;
1294
          inset += leftPadding;
1295
          break;
1296
        case View.RIGHT:
1297
          inset = rightInset;
1298
          if (border != null)
1299
            inset += border.getBorderInsets(null).right;
1300
          inset += rightPadding;
1301
          break;
1302
        default:
1303
          inset = 0.0F;
1304
      }
1305
      return inset;
1306
    }
1307
 
1308
    /**
1309
     * Paints the CSS box according to the attributes given. This should
1310
     * paint the border, padding and background.
1311
     *
1312
     * @param g - the graphics configuration
1313
     * @param x - the x coordinate
1314
     * @param y - the y coordinate
1315
     * @param w - the width of the allocated area
1316
     * @param h - the height of the allocated area
1317
     * @param v - the view making the request
1318
     */
1319
    public void paint(Graphics g, float x, float y, float w, float h, View v)
1320
    {
1321
      int inX = (int) (x + leftInset);
1322
      int inY = (int) (y + topInset);
1323
      int inW = (int) (w - leftInset - rightInset);
1324
      int inH = (int) (h - topInset - bottomInset);
1325
      if (background != null)
1326
        {
1327
          g.setColor(background);
1328
          g.fillRect(inX, inY, inW, inH);
1329
        }
1330
      if (border != null)
1331
        {
1332
          border.paintBorder(null, g, inX, inY, inW, inH);
1333
        }
1334
    }
1335
  }
1336
 
1337
  /**
1338
   * This class carries out some of the CSS list formatting duties. Implementations
1339
   * of this class enable views to present the CSS formatting while not knowing anything
1340
   * about how the CSS values are being cached.
1341
   *
1342
   * @author Lillian Angel (langel@redhat.com)
1343
   */
1344
  public static class ListPainter implements Serializable
1345
  {
1346
 
1347
    /**
1348
     * Attribute set for painter
1349
     */
1350
    private AttributeSet attributes;
1351
 
1352
    /**
1353
     * The associated style sheet.
1354
     */
1355
    private StyleSheet styleSheet;
1356
 
1357
    /**
1358
     * The bullet type.
1359
     */
1360
    private String type;
1361
 
1362
    /**
1363
     * Package-private constructor.
1364
     *
1365
     * @param as - AttributeSet for painter
1366
     */
1367
    ListPainter(AttributeSet as, StyleSheet ss)
1368
    {
1369
      attributes = as;
1370
      styleSheet = ss;
1371
      type = (String) as.getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
1372
    }
1373
 
1374
    /**
1375
     * Cached rectangle re-used in the paint method below.
1376
     */
1377
    private final Rectangle tmpRect = new Rectangle();
1378
 
1379
    /**
1380
     * Paints the CSS list decoration according to the attributes given.
1381
     *
1382
     * @param g - the graphics configuration
1383
     * @param x - the x coordinate
1384
     * @param y - the y coordinate
1385
     * @param w - the width of the allocated area
1386
     * @param h - the height of the allocated area
1387
     * @param v - the view making the request
1388
     * @param item - the list item to be painted >=0.
1389
     */
1390
    public void paint(Graphics g, float x, float y, float w, float h, View v,
1391
                      int item)
1392
    {
1393
      // FIXME: This is a very simplistic list rendering. We still need
1394
      // to implement different bullet types (see type field) and custom
1395
      // bullets via images.
1396
      View itemView = v.getView(item);
1397
      AttributeSet viewAtts = itemView.getAttributes();
1398
      Object tag = viewAtts.getAttribute(StyleConstants.NameAttribute);
1399
      // Only paint something here when the child view is an LI tag
1400
      // and the calling view is some of the list tags then).
1401
      if (tag != null && tag == HTML.Tag.LI)
1402
        {
1403
          g.setColor(Color.BLACK);
1404
          int centerX = (int) (x - 12);
1405
          int centerY = -1;
1406
          // For paragraphs (almost all cases) center bullet vertically
1407
          // in the middle of the first line.
1408
          tmpRect.setBounds((int) x, (int) y, (int) w, (int) h);
1409
          if (itemView.getViewCount() > 0)
1410
            {
1411
              View v1 = itemView.getView(0);
1412
              if (v1 instanceof ParagraphView && v1.getViewCount() > 0)
1413
                {
1414
                  Shape a1 = itemView.getChildAllocation(0, tmpRect);
1415
                  Rectangle r1 = a1 instanceof Rectangle ? (Rectangle) a1
1416
                                                         : a1.getBounds();
1417
                  ParagraphView par = (ParagraphView) v1;
1418
                  Shape a = par.getChildAllocation(0, r1);
1419
                  if (a != null)
1420
                    {
1421
                      Rectangle r = a instanceof Rectangle ? (Rectangle) a
1422
                                                           : a.getBounds();
1423
                      centerY = (int) (r.height / 2 + r.y);
1424
                    }
1425
                }
1426
            }
1427
          if (centerY == -1)
1428
            {
1429
              centerY =(int) (h / 2 + y);
1430
            }
1431
          g.fillOval(centerX - 3, centerY - 3, 6, 6);
1432
        }
1433
    }
1434
  }
1435
 
1436
  /**
1437
   * Converts an AttributeSet to a Map. This is used for CSS resolving.
1438
   *
1439
   * @param atts the attributes to convert
1440
   *
1441
   * @return the converted map
1442
   */
1443
  private Map<String,String> attributeSetToMap(AttributeSet atts)
1444
  {
1445
    HashMap<String,String> map = new HashMap<String,String>();
1446
    Enumeration<?> keys = atts.getAttributeNames();
1447
    while (keys.hasMoreElements())
1448
      {
1449
        Object key = keys.nextElement();
1450
        Object value = atts.getAttribute(key);
1451
        map.put(key.toString(), value.toString());
1452
      }
1453
    return map;
1454
  }
1455
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.