Source for javax.swing.text.html.CSS

   1: /* CSS.java -- Provides CSS attributes
   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: package javax.swing.text.html;
  39: 
  40: import gnu.javax.swing.text.html.css.BorderStyle;
  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.FontSize;
  44: import gnu.javax.swing.text.html.css.FontStyle;
  45: import gnu.javax.swing.text.html.css.FontWeight;
  46: import gnu.javax.swing.text.html.css.Length;
  47: 
  48: import java.io.Serializable;
  49: import java.util.HashMap;
  50: import java.util.StringTokenizer;
  51: 
  52: import javax.swing.text.MutableAttributeSet;
  53: 
  54: /**
  55:  * Provides CSS attributes to be used by the HTML view classes. The constants
  56:  * defined here are used as keys for text attributes for use in
  57:  * {@link javax.swing.text.AttributeSet}s of {@link javax.swing.text.Element}s.
  58:  *
  59:  * @author Roman Kennke (kennke@aicas.com)
  60:  */
  61: public class CSS implements Serializable
  62: {
  63:   /**
  64:    * Returns an array of all CSS attributes.
  65:    *
  66:    * @return All available CSS.Attribute objects.
  67:    */
  68:   public static CSS.Attribute[] getAllAttributeKeys()
  69:   {
  70:     Object[] src = Attribute.attributeMap.values().toArray();
  71:     CSS.Attribute[] dst = new CSS.Attribute[ src.length ];
  72:     System.arraycopy(src, 0, dst, 0, src.length);
  73:     return dst;
  74:   }
  75: 
  76:   /**
  77:    * Returns an a given CSS attribute.
  78:    *
  79:    * @param name - The name of the attribute.
  80:    * @return The CSS attribute with the given name, or <code>null</code> if
  81:    * no attribute with that name exists.
  82:    */
  83:   public static CSS.Attribute getAttribute(String name)
  84:   {
  85:     return (CSS.Attribute)Attribute.attributeMap.get( name );
  86:   }
  87: 
  88:   public static final class Attribute
  89:   {
  90:     /**
  91:      * The CSS attribute 'background'.
  92:      */
  93:     public static final Attribute BACKGROUND =
  94:       new Attribute("background", false, null);
  95: 
  96:     /**
  97:      * The CSS attribute 'background-attachment'.
  98:      */
  99:     public static final Attribute BACKGROUND_ATTACHMENT =
 100:       new Attribute("background-attachment", false, "scroll");
 101: 
 102:     /**
 103:      * The CSS attribute 'background-color'.
 104:      */
 105:     public static final Attribute BACKGROUND_COLOR =
 106:       new Attribute("background-color", false, "transparent");
 107: 
 108:     /**
 109:      * The CSS attribute 'background-image'.
 110:      */
 111:     public static final Attribute BACKGROUND_IMAGE =
 112:       new Attribute("background-image", false, "none");
 113: 
 114:     /**
 115:      * The CSS attribute 'background-position'.
 116:      */
 117:     public static final Attribute BACKGROUND_POSITION =
 118:       new Attribute("background-position", false, null);
 119: 
 120:     /**
 121:      * The CSS attribute 'background-repeat'.
 122:      */
 123:     public static final Attribute BACKGROUND_REPEAT =
 124:       new Attribute("background-repeat", false, "repeat");
 125: 
 126:     /**
 127:      * The CSS attribute 'border'.
 128:      */
 129:     public static final Attribute BORDER = new Attribute("border", false, null);
 130: 
 131:     /**
 132:      * The CSS attribute 'border-bottom'.
 133:      */
 134:     public static final Attribute BORDER_BOTTOM =
 135:       new Attribute("border-bottom", false, null);
 136: 
 137:     /**
 138:      * The CSS attribute 'border-bottom-width'.
 139:      */
 140:     public static final Attribute BORDER_BOTTOM_WIDTH =
 141:       new Attribute("border-bottom-width", false, "medium");
 142: 
 143:     /**
 144:      * The CSS attribute 'border-color'.
 145:      */
 146:     public static final Attribute BORDER_COLOR =
 147:       new Attribute("border-color", false, "black");
 148: 
 149:     /**
 150:      * The CSS attribute 'border-left'.
 151:      */
 152:     public static final Attribute BORDER_LEFT =
 153:       new Attribute("border-left", false, null);
 154: 
 155:     /**
 156:      * The CSS attribute 'border-left-width'.
 157:      */
 158:     public static final Attribute BORDER_LEFT_WIDTH =
 159:       new Attribute("border-left-width", false, "medium");
 160: 
 161:     /**
 162:      * The CSS attribute 'border-right'.
 163:      */
 164:     public static final Attribute BORDER_RIGHT =
 165:       new Attribute("border-right", false, null);
 166: 
 167:     /**
 168:      * The CSS attribute 'border-right-width'.
 169:      */
 170:     public static final Attribute BORDER_RIGHT_WIDTH =
 171:       new Attribute("border-right-width", false, "medium");
 172: 
 173:     /**
 174:      * The CSS attribute 'border-style'.
 175:      */
 176:     public static final Attribute BORDER_STYLE =
 177:       new Attribute("border-style", false, "none");
 178: 
 179:     /**
 180:      * The CSS attribute 'border-top'.
 181:      */
 182:     public static final Attribute BORDER_TOP =
 183:       new Attribute("border-top", false, null);
 184: 
 185:     /**
 186:      * The CSS attribute 'border-top-width'.
 187:      */
 188:     public static final Attribute BORDER_TOP_WIDTH =
 189:       new Attribute("border-top-width", false, "medium");
 190: 
 191:     /**
 192:      * The CSS attribute 'border-width'.
 193:      */
 194:     public static final Attribute BORDER_WIDTH =
 195:       new Attribute("border-width", false, "medium");
 196: 
 197:     /**
 198:      * The CSS attribute 'clear'.
 199:      */
 200:     public static final Attribute CLEAR = new Attribute("clear", false, "none");
 201: 
 202:     /**
 203:      * The CSS attribute 'color'.
 204:      */
 205:     public static final Attribute COLOR = new Attribute("color", true, "black");
 206: 
 207:     /**
 208:      * The CSS attribute 'display'.
 209:      */
 210:     public static final Attribute DISPLAY =
 211:       new Attribute("display", false, "block");
 212: 
 213:     /**
 214:      * The CSS attribute 'float'.
 215:      */
 216:     public static final Attribute FLOAT = new Attribute("float", false, "none");
 217: 
 218:     /**
 219:      * The CSS attribute 'font'.
 220:      */
 221:     public static final Attribute FONT = new Attribute("font", true, null);
 222: 
 223:     /**
 224:      * The CSS attribute 'font-family'.
 225:      */
 226:     public static final Attribute FONT_FAMILY =
 227:       new Attribute("font-family", true, null);
 228: 
 229:     /**
 230:      * The CSS attribute 'font-size'.
 231:      */
 232:     public static final Attribute FONT_SIZE =
 233:       new Attribute("font-size", true, "medium");
 234: 
 235:     /**
 236:      * The CSS attribute 'font-style'.
 237:      */
 238:     public static final Attribute FONT_STYLE =
 239:       new Attribute("font-style", true, "normal");
 240: 
 241:     /**
 242:      * The CSS attribute 'font-variant'.
 243:      */
 244:     public static final Attribute FONT_VARIANT =
 245:       new Attribute("font-variant", true, "normal");
 246: 
 247:     /**
 248:      * The CSS attribute 'font-weight'.
 249:      */
 250:     public static final Attribute FONT_WEIGHT =
 251:       new Attribute("font-weight", true, "normal");
 252: 
 253:     /**
 254:      * The CSS attribute 'height'.
 255:      */
 256:     public static final Attribute HEIGHT =
 257:       new Attribute("height", false, "auto");
 258: 
 259:     /**
 260:      * The CSS attribute 'letter-spacing'.
 261:      */
 262:     public static final Attribute LETTER_SPACING =
 263:       new Attribute("letter-spacing", true, "normal");
 264: 
 265:     /**
 266:      * The CSS attribute 'line-height'.
 267:      */
 268:     public static final Attribute LINE_HEIGHT =
 269:       new Attribute("line-height", true, "normal");
 270: 
 271:     /**
 272:      * The CSS attribute 'list-style'.
 273:      */
 274:     public static final Attribute LIST_STYLE =
 275:       new Attribute("list-style", true, null);
 276: 
 277:     /**
 278:      * The CSS attribute 'list-style-image'.
 279:      */
 280:     public static final Attribute LIST_STYLE_IMAGE =
 281:       new Attribute("list-style-image", true, "none");
 282: 
 283:     /**
 284:      * The CSS attribute 'list-style-position'.
 285:      */
 286:     public static final Attribute LIST_STYLE_POSITION =
 287:       new Attribute("list-style-position", true, "outside");
 288: 
 289:     /**
 290:      * The CSS attribute 'list-style-type'.
 291:      */
 292:     public static final Attribute LIST_STYLE_TYPE =
 293:       new Attribute("list-style-type", true, "disc");
 294: 
 295:     /**
 296:      * The CSS attribute 'margin'.
 297:      */
 298:     public static final Attribute MARGIN = new Attribute("margin", false, null);
 299: 
 300:     /**
 301:      * The CSS attribute 'margin-bottom'.
 302:      */
 303:     public static final Attribute MARGIN_BOTTOM =
 304:       new Attribute("margin-bottom", false, "0");
 305: 
 306:     /**
 307:      * The CSS attribute 'margin-left'.
 308:      */
 309:     public static final Attribute MARGIN_LEFT =
 310:       new Attribute("margin-left", false, "0");
 311: 
 312:     /**
 313:      * The CSS attribute 'margin-right'.
 314:      */
 315:     public static final Attribute MARGIN_RIGHT =
 316:       new Attribute("margin-right", false, "0");
 317: 
 318:     /**
 319:      * The CSS attribute 'margin-top'.
 320:      */
 321:     public static final Attribute MARGIN_TOP =
 322:       new Attribute("margin-top", false, "0");
 323: 
 324:     /**
 325:      * The CSS attribute 'padding'.
 326:      */
 327:     public static final Attribute PADDING =
 328:       new Attribute("padding", false, null);
 329: 
 330:     /**
 331:      * The CSS attribute 'padding-bottom'.
 332:      */
 333:     public static final Attribute PADDING_BOTTOM =
 334:       new Attribute("padding-bottom", false, "0");
 335: 
 336:     /**
 337:      * The CSS attribute 'padding-left'.
 338:      */
 339:     public static final Attribute PADDING_LEFT =
 340:       new Attribute("padding-left", false, "0");
 341: 
 342:     /**
 343:      * The CSS attribute 'padding-right'.
 344:      */
 345:     public static final Attribute PADDING_RIGHT =
 346:       new Attribute("padding-right", false, "0");
 347: 
 348:     /**
 349:      * The CSS attribute 'padding-top'.
 350:      */
 351:     public static final Attribute PADDING_TOP =
 352:       new Attribute("padding-top", false, "0");
 353: 
 354:     /**
 355:      * The CSS attribute 'text-align'.
 356:      */
 357:     public static final Attribute TEXT_ALIGN =
 358:       new Attribute("text-align", true, null);
 359: 
 360:     /**
 361:      * The CSS attribute 'text-decoration'.
 362:      */
 363:     public static final Attribute TEXT_DECORATION =
 364:       new Attribute("text-decoration", true, "none");
 365: 
 366:     /**
 367:      * The CSS attribute 'text-indent'.
 368:      */
 369:     public static final Attribute TEXT_INDENT =
 370:       new Attribute("text-indent", true, "0");
 371: 
 372:     /**
 373:      * The CSS attribute 'text-transform'.
 374:      */
 375:     public static final Attribute TEXT_TRANSFORM =
 376:       new Attribute("text-transform", true, "none");
 377: 
 378:     /**
 379:      * The CSS attribute 'vertical-align'.
 380:      */
 381:     public static final Attribute VERTICAL_ALIGN =
 382:       new Attribute("vertical-align", false, "baseline");
 383: 
 384:     /**
 385:      * The CSS attribute 'white-space'.
 386:      */
 387:     public static final Attribute WHITE_SPACE =
 388:       new Attribute("white-space", true, "normal");
 389: 
 390:     /**
 391:      * The CSS attribute 'width'.
 392:      */
 393:     public static final Attribute WIDTH =
 394:       new Attribute("width", false, "auto");
 395: 
 396:     /**
 397:      * The CSS attribute 'word-spacing'.
 398:      */
 399:     public static final Attribute WORD_SPACING =
 400:       new Attribute("word-spacing", true, "normal");
 401: 
 402:     // Some GNU Classpath specific extensions.
 403:     static final Attribute BORDER_TOP_STYLE =
 404:       new Attribute("border-top-style", false, null);
 405:     static final Attribute BORDER_BOTTOM_STYLE =
 406:       new Attribute("border-bottom-style", false, null);
 407:     static final Attribute BORDER_LEFT_STYLE =
 408:       new Attribute("border-left-style", false, null);
 409:     static final Attribute BORDER_RIGHT_STYLE =
 410:       new Attribute("border-right-style", false, null);
 411:     static final Attribute BORDER_TOP_COLOR =
 412:       new Attribute("border-top-color", false, null);
 413:     static final Attribute BORDER_BOTTOM_COLOR =
 414:       new Attribute("border-bottom-color", false, null);
 415:     static final Attribute BORDER_LEFT_COLOR =
 416:       new Attribute("border-left-color", false, null);
 417:     static final Attribute BORDER_RIGHT_COLOR =
 418:       new Attribute("border-right-color", false, null);
 419:     static final Attribute BORDER_SPACING =
 420:       new Attribute("border-spacing", false, null);
 421:     static final Attribute POSITION =
 422:       new Attribute("position", false, null);
 423:     static final Attribute LEFT =
 424:       new Attribute("left", false, null);
 425:     static final Attribute RIGHT =
 426:       new Attribute("right", false, null);
 427:     static final Attribute TOP =
 428:       new Attribute("top", false, null);
 429:     static final Attribute BOTTOM =
 430:       new Attribute("bottom", false, null);
 431: 
 432:     /**
 433:      * The attribute string.
 434:      */
 435:     String attStr;
 436: 
 437:     /**
 438:      * Indicates if this attribute should be inherited from it's parent or
 439:      * not.
 440:      */
 441:     boolean isInherited;
 442: 
 443:     /**
 444:      * A default value for this attribute if one exists, otherwise null.
 445:      */
 446:     String defaultValue;
 447: 
 448:     /**
 449:      * A HashMap of all attributes.
 450:      */
 451:     static HashMap attributeMap;
 452: 
 453:     /**
 454:      * Creates a new Attribute instance with the specified values.
 455:      *
 456:      * @param attr the attribute string
 457:      * @param inherited if the attribute should be inherited or not
 458:      * @param def a default value; may be <code>null</code> 
 459:      */
 460:     Attribute(String attr, boolean inherited, String def)
 461:     {
 462:       attStr = attr;
 463:       isInherited = inherited;
 464:       defaultValue = def;
 465:       if( attributeMap == null)
 466:     attributeMap = new HashMap();
 467:       attributeMap.put( attr, this );
 468:     }
 469: 
 470:     /**
 471:      * Returns the string representation of this attribute as specified
 472:      * in the CSS specification.
 473:      */
 474:     public String toString()
 475:     {
 476:       return attStr;
 477:     }
 478: 
 479:     /**
 480:      * Returns <code>true</code> if the attribute should be inherited from
 481:      * the parent, <code>false</code> otherwise.
 482:      *
 483:      * @return <code>true</code> if the attribute should be inherited from
 484:      *         the parent, <code>false</code> otherwise
 485:      */
 486:     public boolean isInherited()
 487:     {
 488:       return isInherited;
 489:     }
 490: 
 491:     /**
 492:      * Returns the default value of this attribute if one exists,
 493:      * <code>null</code> otherwise.
 494:      *
 495:      * @return the default value of this attribute if one exists,
 496:      *         <code>null</code> otherwise
 497:      */
 498:     public String getDefaultValue()
 499:     {
 500:       return defaultValue;
 501:     }
 502:   }
 503: 
 504:   /**
 505:    * Maps attribute values (String) to some converter class, based on the
 506:    * key.
 507:    *
 508:    * @param att the key
 509:    * @param v the value
 510:    *
 511:    * @return the wrapped value
 512:    */
 513:   static Object getValue(Attribute att, String v)
 514:   {
 515:     Object o;
 516:     if (att == Attribute.FONT_SIZE)
 517:       o = new FontSize(v);
 518:     else if (att == Attribute.FONT_WEIGHT)
 519:       o = new FontWeight(v);
 520:     else if (att == Attribute.FONT_STYLE)
 521:       o = new FontStyle(v);
 522:     else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR
 523:              || att == Attribute.BORDER_COLOR
 524:              || att == Attribute.BORDER_TOP_COLOR
 525:              || att == Attribute.BORDER_BOTTOM_COLOR
 526:              || att == Attribute.BORDER_LEFT_COLOR
 527:              || att == Attribute.BORDER_RIGHT_COLOR)
 528:       o = new CSSColor(v);
 529:     else if (att == Attribute.MARGIN || att == Attribute.MARGIN_BOTTOM
 530:              || att == Attribute.MARGIN_LEFT || att == Attribute.MARGIN_RIGHT
 531:              || att == Attribute.MARGIN_TOP || att == Attribute.WIDTH
 532:              || att == Attribute.HEIGHT
 533:              || att == Attribute.PADDING || att == Attribute.PADDING_BOTTOM
 534:              || att == Attribute.PADDING_LEFT || att == Attribute.PADDING_RIGHT
 535:              || att == Attribute.PADDING_TOP
 536:              || att == Attribute.LEFT || att == Attribute.RIGHT
 537:              || att == Attribute.TOP || att == Attribute.BOTTOM)
 538:       o = new Length(v);
 539:     else if (att == Attribute.BORDER_WIDTH || att == Attribute.BORDER_TOP_WIDTH
 540:              || att == Attribute.BORDER_LEFT_WIDTH
 541:              || att == Attribute.BORDER_RIGHT_WIDTH
 542:              || att == Attribute.BORDER_BOTTOM_WIDTH)
 543:       o = new BorderWidth(v);
 544:     else
 545:       o = v;
 546:     return o;
 547:   }
 548: 
 549:   static void addInternal(MutableAttributeSet atts, Attribute a, String v)
 550:   {
 551:     if (a == Attribute.BACKGROUND)
 552:       parseBackgroundShorthand(atts, v);
 553:     else if (a == Attribute.PADDING)
 554:       parsePaddingShorthand(atts, v);
 555:     else if (a == Attribute.MARGIN)
 556:       parseMarginShorthand(atts, v);
 557:     else if (a == Attribute.BORDER || a == Attribute.BORDER_LEFT
 558:              || a == Attribute.BORDER_RIGHT || a == Attribute.BORDER_TOP
 559:              || a == Attribute.BORDER_BOTTOM)
 560:       parseBorderShorthand(atts, v, a);
 561:   }
 562: 
 563:   /**
 564:    * Parses the background shorthand and translates it to more specific
 565:    * background attributes.
 566:    *
 567:    * @param atts the attributes
 568:    * @param v the value
 569:    */
 570:   private static void parseBackgroundShorthand(MutableAttributeSet atts,
 571:                                                String v)
 572:   {
 573:     StringTokenizer tokens = new StringTokenizer(v, " ");
 574:     while (tokens.hasMoreElements())
 575:       {
 576:         String token = tokens.nextToken();
 577:         if (CSSColor.isValidColor(token))
 578:           atts.addAttribute(Attribute.BACKGROUND_COLOR,
 579:                             new CSSColor(token));
 580:       }
 581:   }
 582: 
 583:   /**
 584:    * Parses the padding shorthand and translates to the specific padding
 585:    * values.
 586:    *
 587:    * @param atts the attributes
 588:    * @param v the actual value
 589:    */
 590:   private static void parsePaddingShorthand(MutableAttributeSet atts, String v)
 591:   {
 592:     StringTokenizer tokens = new StringTokenizer(v, " ");
 593:     int numTokens = tokens.countTokens();
 594:     if (numTokens == 1)
 595:       {
 596:         Length l = new Length(tokens.nextToken());
 597:         atts.addAttribute(Attribute.PADDING_BOTTOM, l);
 598:         atts.addAttribute(Attribute.PADDING_LEFT, l);
 599:         atts.addAttribute(Attribute.PADDING_RIGHT, l);
 600:         atts.addAttribute(Attribute.PADDING_TOP, l);
 601:       }
 602:     else if (numTokens == 2)
 603:       {
 604:         Length l1 = new Length(tokens.nextToken());
 605:         Length l2 = new Length(tokens.nextToken());
 606:         atts.addAttribute(Attribute.PADDING_BOTTOM, l1);
 607:         atts.addAttribute(Attribute.PADDING_TOP, l1);
 608:         atts.addAttribute(Attribute.PADDING_LEFT, l2);
 609:         atts.addAttribute(Attribute.PADDING_RIGHT, l2);
 610:       }
 611:     else if (numTokens == 3)
 612:       {
 613:         Length l1 = new Length(tokens.nextToken());
 614:         Length l2 = new Length(tokens.nextToken());
 615:         Length l3 = new Length(tokens.nextToken());
 616:         atts.addAttribute(Attribute.PADDING_TOP, l1);
 617:         atts.addAttribute(Attribute.PADDING_LEFT, l2);
 618:         atts.addAttribute(Attribute.PADDING_RIGHT, l2);
 619:         atts.addAttribute(Attribute.PADDING_BOTTOM, l3);
 620:       }
 621:     else
 622:       {
 623:         Length l1 = new Length(tokens.nextToken());
 624:         Length l2 = new Length(tokens.nextToken());
 625:         Length l3 = new Length(tokens.nextToken());
 626:         Length l4 = new Length(tokens.nextToken());
 627:         atts.addAttribute(Attribute.PADDING_TOP, l1);
 628:         atts.addAttribute(Attribute.PADDING_RIGHT, l2);
 629:         atts.addAttribute(Attribute.PADDING_BOTTOM, l3);
 630:         atts.addAttribute(Attribute.PADDING_LEFT, l4);
 631:       }
 632:   }
 633: 
 634:   /**
 635:    * Parses the margin shorthand and translates to the specific margin
 636:    * values.
 637:    *
 638:    * @param atts the attributes
 639:    * @param v the actual value
 640:    */
 641:   private static void parseMarginShorthand(MutableAttributeSet atts, String v)
 642:   {
 643:     StringTokenizer tokens = new StringTokenizer(v, " ");
 644:     int numTokens = tokens.countTokens();
 645:     if (numTokens == 1)
 646:       {
 647:         Length l = new Length(tokens.nextToken());
 648:         atts.addAttribute(Attribute.MARGIN_BOTTOM, l);
 649:         atts.addAttribute(Attribute.MARGIN_LEFT, l);
 650:         atts.addAttribute(Attribute.MARGIN_RIGHT, l);
 651:         atts.addAttribute(Attribute.MARGIN_TOP, l);
 652:       }
 653:     else if (numTokens == 2)
 654:       {
 655:         Length l1 = new Length(tokens.nextToken());
 656:         Length l2 = new Length(tokens.nextToken());
 657:         atts.addAttribute(Attribute.MARGIN_BOTTOM, l1);
 658:         atts.addAttribute(Attribute.MARGIN_TOP, l1);
 659:         atts.addAttribute(Attribute.MARGIN_LEFT, l2);
 660:         atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
 661:       }
 662:     else if (numTokens == 3)
 663:       {
 664:         Length l1 = new Length(tokens.nextToken());
 665:         Length l2 = new Length(tokens.nextToken());
 666:         Length l3 = new Length(tokens.nextToken());
 667:         atts.addAttribute(Attribute.MARGIN_TOP, l1);
 668:         atts.addAttribute(Attribute.MARGIN_LEFT, l2);
 669:         atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
 670:         atts.addAttribute(Attribute.MARGIN_BOTTOM, l3);
 671:       }
 672:     else
 673:       {
 674:         Length l1 = new Length(tokens.nextToken());
 675:         Length l2 = new Length(tokens.nextToken());
 676:         Length l3 = new Length(tokens.nextToken());
 677:         Length l4 = new Length(tokens.nextToken());
 678:         atts.addAttribute(Attribute.MARGIN_TOP, l1);
 679:         atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
 680:         atts.addAttribute(Attribute.MARGIN_BOTTOM, l3);
 681:         atts.addAttribute(Attribute.MARGIN_LEFT, l4);
 682:       }
 683:   }
 684: 
 685:   /**
 686:    * Parses the CSS border shorthand attribute and translates it to the
 687:    * more specific border attributes.
 688:    *
 689:    * @param atts the attribute
 690:    * @param value the value
 691:    */
 692:   private static void parseBorderShorthand(MutableAttributeSet atts,
 693:                                            String value, Attribute cssAtt)
 694:   {
 695:     StringTokenizer tokens = new StringTokenizer(value, " ");
 696:     while (tokens.hasMoreTokens())
 697:       {
 698:         String token = tokens.nextToken();
 699:         if (BorderStyle.isValidStyle(token))
 700:           {
 701:             if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
 702:               atts.addAttribute(Attribute.BORDER_LEFT_STYLE, token);
 703:             if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
 704:               atts.addAttribute(Attribute.BORDER_RIGHT_STYLE, token);
 705:             if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
 706:               atts.addAttribute(Attribute.BORDER_BOTTOM_STYLE, token);
 707:             if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
 708:               atts.addAttribute(Attribute.BORDER_TOP_STYLE, token);
 709:           }
 710:         else if (BorderWidth.isValid(token))
 711:           {
 712:             BorderWidth w = new BorderWidth(token);
 713:             if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
 714:               atts.addAttribute(Attribute.BORDER_LEFT_WIDTH, w);
 715:             if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
 716:               atts.addAttribute(Attribute.BORDER_RIGHT_WIDTH, w);
 717:             if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
 718:               atts.addAttribute(Attribute.BORDER_BOTTOM_WIDTH, w);
 719:             if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
 720:               atts.addAttribute(Attribute.BORDER_TOP_WIDTH, w);
 721:           }
 722:         else if (CSSColor.isValidColor(token))
 723:           {
 724:             CSSColor c = new CSSColor(token);
 725:             if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
 726:               atts.addAttribute(Attribute.BORDER_LEFT_COLOR, c);
 727:             if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
 728:               atts.addAttribute(Attribute.BORDER_RIGHT_COLOR, c);
 729:             if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
 730:               atts.addAttribute(Attribute.BORDER_BOTTOM_COLOR, c);
 731:             if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
 732:               atts.addAttribute(Attribute.BORDER_TOP_COLOR, c);
 733:           }
 734:       }
 735:   }
 736: }