Source for javax.swing.text.html.BlockView

   1: /* BlockView.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.Length;
  42: 
  43: import java.awt.Graphics;
  44: import java.awt.Rectangle;
  45: import java.awt.Shape;
  46: import java.util.HashMap;
  47: 
  48: import javax.swing.SizeRequirements;
  49: import javax.swing.event.DocumentEvent;
  50: import javax.swing.text.AttributeSet;
  51: import javax.swing.text.BoxView;
  52: import javax.swing.text.Element;
  53: import javax.swing.text.View;
  54: import javax.swing.text.ViewFactory;
  55: 
  56: /**
  57:  * @author Lillian Angel <langel@redhat.com>
  58:  */
  59: public class BlockView extends BoxView
  60: {
  61: 
  62:   /**
  63:    * Stores information about child positioning according to the
  64:    * CSS attributes position, left, right, top and bottom.
  65:    */
  66:   private static class PositionInfo
  67:   {
  68:     // TODO: Use enums when available.
  69: 
  70:     /**
  71:      * Static positioning. This is the default and is thus rarely really
  72:      * used.
  73:      */
  74:     static final int STATIC = 0;
  75: 
  76:     /**
  77:      * Relative positioning. The box is teaked relative to its static
  78:      * computed bounds.
  79:      */
  80:     static final int RELATIVE = 1;
  81: 
  82:     /**
  83:      * Absolute positioning. The box is moved relative to the parent's box.
  84:      */
  85:     static final int ABSOLUTE = 2;
  86: 
  87:     /**
  88:      * Like ABSOLUTE, with some fixation against the viewport (not yet
  89:      * implemented).
  90:      */
  91:     static final int FIXED = 3;
  92: 
  93:     /**
  94:      * The type according to the constants of this class.
  95:      */
  96:     int type;
  97: 
  98:     /**
  99:      * The left constraint, null if not set.
 100:      */
 101:     Length left;
 102: 
 103:     /**
 104:      * The right constraint, null if not set.
 105:      */
 106:     Length right;
 107: 
 108:     /**
 109:      * The top constraint, null if not set.
 110:      */
 111:     Length top;
 112: 
 113:     /**
 114:      * The bottom constraint, null if not set.
 115:      */
 116:     Length bottom;
 117: 
 118:     /**
 119:      * Creates a new PositionInfo object.
 120:      *
 121:      * @param typ the type to set
 122:      * @param l the left constraint
 123:      * @param r the right constraint
 124:      * @param t the top constraint
 125:      * @param b the bottom constraint
 126:      */
 127:     PositionInfo(int typ, Length l, Length r, Length t, Length b)
 128:     {
 129:       type = typ;
 130:       left = l;
 131:       right = r;
 132:       top = t;
 133:       bottom = b;
 134:     }
 135:   }
 136: 
 137:   /**
 138:    * The attributes for this view.
 139:    */
 140:   private AttributeSet attributes;
 141: 
 142:   /**
 143:    * The box painter for this view.
 144:    *
 145:    * This is package private because the TableView needs access to it.
 146:    */
 147:   StyleSheet.BoxPainter painter;
 148: 
 149:   /**
 150:    * The width and height as specified in the stylesheet, null if not
 151:    * specified. The first value is the X_AXIS, the second the Y_AXIS. You
 152:    * can index this directly by the X_AXIS and Y_AXIS constants.
 153:    */
 154:   private Length[] cssSpans;
 155: 
 156:   /**
 157:    * Stores additional CSS layout information.
 158:    */
 159:   private HashMap positionInfo;
 160: 
 161:   /**
 162:    * Creates a new view that represents an html box. 
 163:    * This can be used for a number of elements.
 164:    * 
 165:    * @param elem - the element to create a view for
 166:    * @param axis - either View.X_AXIS or View.Y_AXIS
 167:    */
 168:   public BlockView(Element elem, int axis)
 169:   {
 170:     super(elem, axis);
 171:     cssSpans = new Length[2];
 172:     positionInfo = new HashMap();
 173:   }
 174: 
 175:   /**
 176:    * Creates the parent view for this. It is called before
 177:    * any other methods, if the parent view is working properly.
 178:    * Implemented to forward to the superclass and call
 179:    * setPropertiesFromAttributes to set the paragraph 
 180:    * properties.
 181:    * 
 182:    * @param parent - the new parent, or null if the view
 183:    * is being removed from a parent it was added to. 
 184:    */
 185:   public void setParent(View parent)
 186:   {
 187:     super.setParent(parent);
 188:     
 189:     if (parent != null)
 190:       setPropertiesFromAttributes();
 191:   }
 192:   
 193:   /**
 194:    * Calculates the requirements along the major axis.
 195:    * This is implemented to call the superclass and then
 196:    * adjust it if the CSS width or height attribute is specified
 197:    * and applicable.
 198:    * 
 199:    * @param axis - the axis to check the requirements for.
 200:    * @param r - the SizeRequirements. If null, one is created.
 201:    * @return the new SizeRequirements object.
 202:    */
 203:   protected SizeRequirements calculateMajorAxisRequirements(int axis,
 204:                                                             SizeRequirements r)
 205:   {
 206:     if (r == null)
 207:       r = new SizeRequirements();
 208:     
 209:     if (setCSSSpan(r, axis))
 210:       {
 211:         // If we have set the span from CSS, then we need to adjust
 212:         // the margins.
 213:         SizeRequirements parent = super.calculateMajorAxisRequirements(axis,
 214:                                                                        null);
 215:         int margin = axis == X_AXIS ? getLeftInset() + getRightInset()
 216:                                     : getTopInset() + getBottomInset();
 217:         r.minimum -= margin;
 218:         r.preferred -= margin;
 219:         r.maximum -= margin;
 220:         constrainSize(axis, r, parent);
 221:       }
 222:     else
 223:       r = super.calculateMajorAxisRequirements(axis, r);
 224:     return r;
 225:   }
 226: 
 227:   /**
 228:    * Calculates the requirements along the minor axis.
 229:    * This is implemented to call the superclass and then
 230:    * adjust it if the CSS width or height attribute is specified
 231:    * and applicable.
 232:    * 
 233:    * @param axis - the axis to check the requirements for.
 234:    * @param r - the SizeRequirements. If null, one is created.
 235:    * @return the new SizeRequirements object.
 236:    */
 237:   protected SizeRequirements calculateMinorAxisRequirements(int axis,
 238:                                                             SizeRequirements r)
 239:   {
 240:     if (r == null)
 241:       r = new SizeRequirements();
 242:     
 243:     if (setCSSSpan(r, axis))
 244:       {
 245:         // If we have set the span from CSS, then we need to adjust
 246:         // the margins.
 247:         SizeRequirements parent = super.calculateMinorAxisRequirements(axis,
 248:                                                                        null);
 249:         int margin = axis == X_AXIS ? getLeftInset() + getRightInset()
 250:                                     : getTopInset() + getBottomInset();
 251:         r.minimum -= margin;
 252:         r.preferred -= margin;
 253:         r.maximum -= margin;
 254:         constrainSize(axis, r, parent);
 255:       }
 256:     else
 257:       r = super.calculateMinorAxisRequirements(axis, r);
 258: 
 259:     // Apply text alignment if appropriate.
 260:     if (axis == X_AXIS)
 261:       {
 262:         Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
 263:         if (o != null)
 264:           {
 265:             String al = o.toString().trim();
 266:             if (al.equals("center"))
 267:               r.alignment = 0.5f;
 268:             else if (al.equals("right"))
 269:               r.alignment = 1.0f;
 270:             else
 271:               r.alignment = 0.0f;
 272:           }
 273:       }
 274:     return r;
 275:   }
 276: 
 277:   /**
 278:    * Sets the span on the SizeRequirements object according to the
 279:    * according CSS span value, when it is set.
 280:    * 
 281:    * @param r the size requirements
 282:    * @param axis the axis
 283:    *
 284:    * @return <code>true</code> when the CSS span has been set,
 285:    *         <code>false</code> otherwise
 286:    */
 287:   private boolean setCSSSpan(SizeRequirements r, int axis)
 288:   {
 289:     boolean ret = false;
 290:     Length span = cssSpans[axis];
 291:     // We can't set relative CSS spans here because we don't know
 292:     // yet about the allocated span. Instead we use the view's
 293:     // normal requirements.
 294:     if (span != null && ! span.isPercentage())
 295:       {
 296:         r.minimum = (int) span.getValue();
 297:         r.preferred = (int) span.getValue();
 298:         r.maximum = (int) span.getValue();
 299:         ret = true;
 300:       }
 301:     return ret;
 302:   }
 303: 
 304:   /**
 305:    * Constrains the <code>r</code> requirements according to
 306:    * <code>min</code>.
 307:    *
 308:    * @param axis the axis
 309:    * @param r the requirements to constrain
 310:    * @param min the constraining requirements
 311:    */
 312:   private void constrainSize(int axis, SizeRequirements r,
 313:                              SizeRequirements min)
 314:   {
 315:     if (min.minimum > r.minimum)
 316:       {
 317:         r.minimum = min.minimum;
 318:         r.preferred = min.minimum;
 319:         r.maximum = Math.max(r.maximum, min.maximum);
 320:       }
 321:   }
 322: 
 323:   /**
 324:    * Lays out the box along the minor axis (the axis that is
 325:    * perpendicular to the axis that it represents). The results
 326:    * of the layout are placed in the given arrays which are
 327:    * the allocations to the children along the minor axis.
 328:    * 
 329:    * @param targetSpan - the total span given to the view, also 
 330:    * used to layout the children.
 331:    * @param axis - the minor axis
 332:    * @param offsets - the offsets from the origin of the view for
 333:    * all the child views. This is a return value and is filled in by this
 334:    * function.
 335:    * @param spans - the span of each child view. This is a return value and is 
 336:    * filled in by this function.
 337:    */
 338:   protected void layoutMinorAxis(int targetSpan, int axis,
 339:                                  int[] offsets, int[] spans)
 340:   {
 341:     int viewCount = getViewCount();
 342:     for (int i = 0; i < viewCount; i++)
 343:       {
 344:         View view = getView(i);
 345:         int min = (int) view.getMinimumSpan(axis);
 346:         int max;
 347:         // Handle CSS span value of child.
 348:         Length length = cssSpans[axis];
 349:         if (length != null)
 350:           {
 351:             min = Math.max((int) length.getValue(targetSpan), min);
 352:             max = min;
 353:           }
 354:         else
 355:           max = (int) view.getMaximumSpan(axis);
 356: 
 357:         if (max < targetSpan)
 358:           {
 359:             // Align child.
 360:             float align = view.getAlignment(axis);
 361:             offsets[i] = (int) ((targetSpan - max) * align);
 362:             spans[i] = max;
 363:           }
 364:         else
 365:           {
 366:             offsets[i] = 0;
 367:             spans[i] = Math.max(min, targetSpan);
 368:           }
 369: 
 370:         // Adjust according to CSS position info.
 371:         positionView(targetSpan, axis, i, offsets, spans);
 372:       }
 373:   }
 374: 
 375:   /**
 376:    * Overridden to perform additional CSS layout (absolute/relative
 377:    * positioning).
 378:    */
 379:   protected void layoutMajorAxis(int targetSpan, int axis,
 380:                                  int[] offsets, int[] spans)
 381:   {
 382:     super.layoutMajorAxis(targetSpan, axis, offsets, spans);
 383: 
 384:     // Adjust according to CSS position info.
 385:     int viewCount = getViewCount();
 386:     for (int i = 0; i < viewCount; i++)
 387:       {
 388:         positionView(targetSpan, axis, i, offsets, spans);
 389:       }
 390:   }
 391: 
 392:   /**
 393:    * Positions a view according to any additional CSS constraints.
 394:    *
 395:    * @param targetSpan the target span
 396:    * @param axis the axis
 397:    * @param i the index of the view
 398:    * @param offsets the offsets get placed here
 399:    * @param spans the spans get placed here
 400:    */
 401:   private void positionView(int targetSpan, int axis, int i, int[] offsets,
 402:                             int[] spans)
 403:   {
 404:     View view = getView(i);
 405:     PositionInfo pos = (PositionInfo) positionInfo.get(view);
 406:     if (pos != null)
 407:       {
 408:         int p0 = -1;
 409:         int p1 = -1;
 410:         if (axis == X_AXIS)
 411:           {
 412:             Length l = pos.left;
 413:             if (l != null)
 414:               p0 = (int) l.getValue(targetSpan);
 415:             l = pos.right;
 416:             if (l != null)
 417:               p1 = (int) l.getValue(targetSpan);
 418:           }
 419:         else
 420:           {
 421:             Length l = pos.top;
 422:             if (l != null)
 423:               p0 = (int) l.getValue(targetSpan);
 424:             l = pos.bottom;
 425:             if (l != null)
 426:               p1 = (int) l.getValue(targetSpan);
 427:           }
 428:         if (pos.type == PositionInfo.ABSOLUTE
 429:             || pos.type == PositionInfo.FIXED)
 430:           {
 431:             if (p0 != -1)
 432:               {
 433:                 offsets[i] = p0;
 434:                 if (p1 != -1)
 435:                   {
 436:                     // Overrides computed width. (Possibly overconstrained
 437:                     // when the width attribute was set too.)
 438:                     spans[i] = targetSpan - p1 - offsets[i];
 439:                   }
 440:               }
 441:             else if (p1 != -1)
 442:               {
 443:                 // Preserve any computed width.
 444:                 offsets[i] = targetSpan - p1 - spans[i];
 445:               }
 446:           }
 447:         else if (pos.type == PositionInfo.RELATIVE)
 448:           {
 449:             if (p0 != -1)
 450:               {
 451:                 offsets[i] += p0;
 452:                 if (p1 != -1)
 453:                   {
 454:                     // Overrides computed width. (Possibly overconstrained
 455:                     // when the width attribute was set too.)
 456:                     spans[i] = spans[i] - p0 - p1 - offsets[i];
 457:                   }
 458:               }
 459:             else if (p1 != -1)
 460:               {
 461:                 // Preserve any computed width.
 462:                 offsets[i] -= p1;
 463:               }
 464:           }
 465:       }
 466:   }
 467: 
 468:   /**
 469:    * Paints using the given graphics configuration and shape.
 470:    * This delegates to the css box painter to paint the
 471:    * border and background prior to the interior.
 472:    * 
 473:    * @param g - Graphics configuration
 474:    * @param a - the Shape to render into.
 475:    */
 476:   public void paint(Graphics g, Shape a)
 477:   {
 478:     Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
 479: 
 480:     // Debug output. Shows blocks in green rectangles.
 481:     // g.setColor(Color.GREEN);
 482:     // g.drawRect(rect.x, rect.y, rect.width, rect.height);
 483: 
 484:     painter.paint(g, rect.x, rect.y, rect.width, rect.height, this);
 485:     super.paint(g, a);
 486:   }
 487: 
 488:   /**
 489:    * Fetches the attributes to use when painting.
 490:    * 
 491:    * @return the attributes of this model.
 492:    */
 493:   public AttributeSet getAttributes()
 494:   {
 495:     if (attributes == null)
 496:       attributes = getStyleSheet().getViewAttributes(this);
 497:     return attributes;
 498:   }
 499:   
 500:   /**
 501:    * Gets the resize weight.
 502:    * 
 503:    * @param axis - the axis to get the resize weight for.
 504:    * @return the resize weight.
 505:    * @throws IllegalArgumentException - for an invalid axis
 506:    */
 507:   public int getResizeWeight(int axis) throws IllegalArgumentException
 508:   {
 509:     // Can't resize the Y_AXIS
 510:     if (axis == Y_AXIS)
 511:       return 0;
 512:     if (axis == X_AXIS)
 513:       return 1;
 514:     throw new IllegalArgumentException("Invalid Axis");
 515:   }
 516:   
 517:   /**
 518:    * Gets the alignment.
 519:    * 
 520:    * @param axis - the axis to get the alignment for.
 521:    * @return the alignment.
 522:    */
 523:   public float getAlignment(int axis)
 524:   {
 525:     if (axis == X_AXIS)
 526:       return super.getAlignment(axis);
 527:     if (axis == Y_AXIS)
 528:       {
 529:         if (getViewCount() == 0)
 530:           return 0.0F;
 531:         float prefHeight = getPreferredSpan(Y_AXIS);
 532:         View first = getView(0);
 533:         float firstRowHeight = first.getPreferredSpan(Y_AXIS);
 534:         return prefHeight != 0 ? (firstRowHeight * first.getAlignment(Y_AXIS))
 535:                                  / prefHeight
 536:                                : 0;
 537:       }
 538:     throw new IllegalArgumentException("Invalid Axis");
 539:   }
 540:   
 541:   /**
 542:    * Gives notification from the document that attributes were
 543:    * changed in a location that this view is responsible for.
 544:    * 
 545:    * @param ev - the change information
 546:    * @param a - the current shape of the view
 547:    * @param f - the factory to use to rebuild if the view has children.
 548:    */
 549:   public void changedUpdate(DocumentEvent ev,
 550:                             Shape a, ViewFactory f)
 551:   {
 552:     super.changedUpdate(ev, a, f);
 553:     
 554:     // If more elements were added, then need to set the properties for them
 555:     int currPos = ev.getOffset();
 556:     if (currPos <= getStartOffset()
 557:         && (currPos + ev.getLength()) >= getEndOffset())
 558:         setPropertiesFromAttributes();
 559:   }
 560: 
 561:   /**
 562:    * Determines the preferred span along the axis.
 563:    * 
 564:    * @param axis - the view to get the preferred span for.
 565:    * @return the span the view would like to be painted into >=0/
 566:    * The view is usually told to paint into the span that is returned, 
 567:    * although the parent may choose to resize or break the view.
 568:    * @throws IllegalArgumentException - for an invalid axis
 569:    */
 570:   public float getPreferredSpan(int axis) throws IllegalArgumentException
 571:   {
 572:     if (axis == X_AXIS || axis == Y_AXIS)
 573:       return super.getPreferredSpan(axis);
 574:     throw new IllegalArgumentException("Invalid Axis");
 575:   }
 576:   
 577:   /**
 578:    * Determines the minimum span along the axis.
 579:    * 
 580:    * @param axis - the axis to get the minimum span for.
 581:    * @return the span the view would like to be painted into >=0/
 582:    * The view is usually told to paint into the span that is returned, 
 583:    * although the parent may choose to resize or break the view.
 584:    * @throws IllegalArgumentException - for an invalid axis
 585:    */
 586:   public float getMinimumSpan(int axis) throws IllegalArgumentException
 587:   {
 588:     if (axis == X_AXIS || axis == Y_AXIS)
 589:       return super.getMinimumSpan(axis);
 590:     throw new IllegalArgumentException("Invalid Axis");
 591:   }
 592:   
 593:   /**
 594:    * Determines the maximum span along the axis.
 595:    * 
 596:    * @param axis - the axis to get the maximum span for.
 597:    * @return the span the view would like to be painted into >=0/
 598:    * The view is usually told to paint into the span that is returned, 
 599:    * although the parent may choose to resize or break the view.
 600:    * @throws IllegalArgumentException - for an invalid axis
 601:    */
 602:   public float getMaximumSpan(int axis) throws IllegalArgumentException
 603:   {
 604:     if (axis == X_AXIS || axis == Y_AXIS)
 605:       return super.getMaximumSpan(axis);
 606:     throw new IllegalArgumentException("Invalid Axis");
 607:   }
 608:   
 609:   /**
 610:    * Updates any cached values that come from attributes.
 611:    */
 612:   protected void setPropertiesFromAttributes()
 613:   {
 614:     // Fetch attributes.
 615:     StyleSheet ss = getStyleSheet();
 616:     attributes = ss.getViewAttributes(this);
 617: 
 618:     // Fetch painter.
 619:     painter = ss.getBoxPainter(attributes);
 620: 
 621:     // Update insets.
 622:     if (attributes != null)
 623:       {
 624:         setInsets((short) painter.getInset(TOP, this),
 625:                   (short) painter.getInset(LEFT, this),
 626:                   (short) painter.getInset(BOTTOM, this),
 627:                   (short) painter.getInset(RIGHT, this));
 628:       }
 629: 
 630:     // Fetch width and height.
 631:     float emBase = ss.getEMBase(attributes);
 632:     float exBase = ss.getEXBase(attributes);
 633:     cssSpans[X_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
 634:     if (cssSpans[X_AXIS] != null)
 635:       cssSpans[X_AXIS].setFontBases(emBase, exBase);
 636:     cssSpans[Y_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.HEIGHT);
 637:     if (cssSpans[Y_AXIS] != null)
 638:       cssSpans[Y_AXIS].setFontBases(emBase, exBase);
 639:   }
 640: 
 641:   /**
 642:    * Gets the default style sheet.
 643:    * 
 644:    * @return the style sheet
 645:    */
 646:   protected StyleSheet getStyleSheet()
 647:   {
 648:     HTMLDocument doc = (HTMLDocument) getDocument();
 649:     return doc.getStyleSheet();
 650:   }
 651: 
 652:   /**
 653:    * Overridden to fetch additional CSS layout information.
 654:    */
 655:   public void replace(int offset, int length, View[] views)
 656:   {
 657:     // First remove unneeded stuff.
 658:     for (int i = 0; i < length; i++)
 659:       {
 660:         View child = getView(i + offset);
 661:         positionInfo.remove(child);
 662:       }
 663: 
 664:     // Call super to actually replace the views.
 665:     super.replace(offset, length, views);
 666: 
 667:     // Now fetch the position infos for the new views.
 668:     for (int i = 0; i < views.length; i++)
 669:       {
 670:         fetchLayoutInfo(views[i]);
 671:       }
 672:   }
 673: 
 674:   /**
 675:    * Fetches and stores the layout info for the specified view.
 676:    *
 677:    * @param view the view for which the layout info is stored
 678:    */
 679:   private void fetchLayoutInfo(View view)
 680:   {
 681:     AttributeSet atts = view.getAttributes();
 682:     Object o = atts.getAttribute(CSS.Attribute.POSITION);
 683:     if (o != null && o instanceof String && ! o.equals("static"))
 684:       {
 685:         int type;
 686:         if (o.equals("relative"))
 687:           type = PositionInfo.RELATIVE;
 688:         else if (o.equals("absolute"))
 689:           type = PositionInfo.ABSOLUTE;
 690:         else if (o.equals("fixed"))
 691:           type = PositionInfo.FIXED;
 692:         else
 693:           type = PositionInfo.STATIC;
 694: 
 695:         if (type != PositionInfo.STATIC)
 696:           {
 697:             StyleSheet ss = getStyleSheet();
 698:             float emBase = ss.getEMBase(atts);
 699:             float exBase = ss.getEXBase(atts);
 700:             Length left = (Length) atts.getAttribute(CSS.Attribute.LEFT);
 701:             if (left != null)
 702:               left.setFontBases(emBase, exBase);
 703:             Length right = (Length) atts.getAttribute(CSS.Attribute.RIGHT);
 704:             if (right != null)
 705:               right.setFontBases(emBase, exBase);
 706:             Length top = (Length) atts.getAttribute(CSS.Attribute.TOP);
 707:             if (top != null)
 708:               top.setFontBases(emBase, exBase);
 709:             Length bottom = (Length) atts.getAttribute(CSS.Attribute.BOTTOM);
 710:             if (bottom != null)
 711:               bottom.setFontBases(emBase, exBase);
 712:             if (left != null || right != null || top != null || bottom != null)
 713:               {
 714:                 PositionInfo pos = new PositionInfo(type, left, right, top,
 715:                                                     bottom);
 716:                 positionInfo.put(view, pos);
 717:               }
 718:           }
 719:       }
 720:   }
 721: }