Clover coverage report -
Coverage timestamp: Sun Apr 18 2004 21:32:30 EDT
file stats: LOC: 1,835   Methods: 90
NCLOC: 996   Classes: 6
 
 Source file Conditionals Statements Methods TOTAL
SHTMLTableView.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
 * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
 3   
 *
 4   
 * This software is the proprietary information of Sun Microsystems, Inc.
 5   
 * Use is subject to license terms.
 6   
 *
 7   
  */
 8   
 import java.awt.*;
 9   
 import javax.swing.*;
 10   
 import javax.swing.event.*;
 11   
 import javax.swing.text.*;
 12   
 import javax.swing.text.html.*;
 13   
 import java.util.*;
 14   
 
 15   
 /**
 16   
  * HTML table view copied from javax.swing.text.html.TableView.java.
 17   
  *
 18   
  * The original intention was to implement a box painter other
 19   
  * than StyleSheet.BoxPainter which obviously is not complete.
 20   
  *
 21   
  * This could have been a simple task just overriding TableView.create
 22   
  * with our own ViewFactory implementing an alternate BoxPainter.
 23   
  *
 24   
  * Unfortunately while create is public, TableView itself is
 25   
  * not (why???). We have to copy the whole thing and just
 26   
  * adapt one line to make inner class CellView a subclass of
 27   
  * our own SHTMLBlockView instead of javax.swing.text.html.BlockView.
 28   
  *
 29   
  * To make things worse, TableView uses some methods from class CSS which
 30   
  * are not public as well (again not clear why) so these had to be
 31   
  * copied into this class too.
 32   
  *
 33   
  * All in all a totally ugly solution which hopefully can be corrected
 34   
  * once Sun decided to tidy up the CSS part of Swing.
 35   
  *
 36   
  * @version stage 11, April 27, 2003
 37   
  */
 38   
 
 39   
 public class SHTMLTableView extends BoxView implements ViewFactory {
 40   
 
 41   
   /**
 42   
    * Constructs a TableView for the given element.
 43   
    *
 44   
    * @param elem the element that this view is responsible for
 45   
    */
 46  0
   public SHTMLTableView(Element elem) {
 47  0
     super(elem, View.Y_AXIS);
 48  0
     rows = new Vector();
 49  0
     gridValid = false;
 50  0
     captionIndex = -1;
 51  0
     totalColumnRequirements = new SizeRequirements();
 52   
   }
 53   
 
 54   
   /**
 55   
    * Creates a new table row.
 56   
    *
 57   
    * @param elem an element
 58   
    * @return the row
 59   
    */
 60  0
   protected RowView createTableRow(Element elem) {
 61   
     // PENDING(prinz) need to add support for some of the other
 62   
     // elements, but for now just ignore anything that is not
 63   
     // a TR.
 64  0
     Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
 65  0
     if (o == HTML.Tag.TR) {
 66  0
       return new RowView(elem);
 67   
     }
 68  0
     return null;
 69   
   }
 70   
 
 71   
   /**
 72   
    * The number of columns in the table.
 73   
    */
 74  0
   public int getColumnCount() {
 75  0
     return columnSpans.length;
 76   
   }
 77   
 
 78   
   /**
 79   
    * Fetches the span (width) of the given column.
 80   
    * This is used by the nested cells to query the
 81   
    * sizes of grid locations outside of themselves.
 82   
    */
 83  0
   public int getColumnSpan(int col) {
 84  0
     if (col < columnSpans.length) {
 85  0
       return columnSpans[col];
 86   
     }
 87  0
     return 0;
 88   
   }
 89   
 
 90   
   /**
 91   
    * The number of rows in the table.
 92   
    */
 93  0
   public int getRowCount() {
 94  0
     return rows.size();
 95   
   }
 96   
 
 97   
   /**
 98   
    * Fetch the span of multiple rows.  This includes
 99   
    * the border area.
 100   
    */
 101  0
   public int getMultiRowSpan(int row0, int row1) {
 102  0
     RowView rv0 = getRow(row0);
 103  0
     RowView rv1 = getRow(row1);
 104  0
     if ((rv0 != null) && (rv1 != null)) {
 105  0
       int index0 = rv0.viewIndex;
 106  0
       int index1 = rv1.viewIndex;
 107  0
       int span = getOffset(Y_AXIS, index1) - getOffset(Y_AXIS, index0) +
 108   
                  getSpan(Y_AXIS, index1);
 109  0
       return span;
 110   
     }
 111  0
     return 0;
 112   
   }
 113   
 
 114   
   /**
 115   
    * Fetches the span (height) of the given row.
 116   
    */
 117  0
   public int getRowSpan(int row) {
 118  0
     RowView rv = getRow(row);
 119  0
     if (rv != null) {
 120  0
       return getSpan(Y_AXIS, rv.viewIndex);
 121   
     }
 122  0
     return 0;
 123   
   }
 124   
 
 125  0
   RowView getRow(int row) {
 126  0
     if (row < rows.size()) {
 127  0
       return (RowView) rows.elementAt(row);
 128   
     }
 129  0
     return null;
 130   
   }
 131   
 
 132   
   /**
 133   
    * Determines the number of columns occupied by
 134   
    * the table cell represented by given element.
 135   
    */
 136  0
   protected int getColumnsOccupied(View v) {
 137  0
     AttributeSet a = v.getElement().getAttributes();
 138   
 
 139  0
     if (a.isDefined(HTML.Attribute.COLSPAN)) {
 140  0
       String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);
 141  0
       if (s != null) {
 142  0
         try {
 143  0
           return Integer.parseInt(s);
 144   
         } catch (NumberFormatException nfe) {
 145   
           // fall through to one column
 146   
         }
 147   
       }
 148   
     }
 149   
 
 150  0
     return 1;
 151   
   }
 152   
 
 153   
   /**
 154   
    * Determines the number of rows occupied by
 155   
    * the table cell represented by given element.
 156   
    */
 157  0
   protected int getRowsOccupied(View v) {
 158  0
     AttributeSet a = v.getElement().getAttributes();
 159   
 
 160  0
     if (a.isDefined(HTML.Attribute.ROWSPAN)) {
 161  0
       String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);
 162  0
       if (s != null) {
 163  0
         try {
 164  0
           return Integer.parseInt(s);
 165   
         } catch (NumberFormatException nfe) {
 166   
           // fall through to one row
 167   
         }
 168   
       }
 169   
     }
 170   
 
 171  0
     return 1;
 172   
   }
 173   
 
 174  0
   protected void invalidateGrid() {
 175  0
     gridValid = false;
 176   
   }
 177   
 
 178  0
   protected StyleSheet getStyleSheet() {
 179  0
     HTMLDocument doc = (HTMLDocument) getDocument();
 180  0
     return doc.getStyleSheet();
 181   
   }
 182   
 
 183   
   /**
 184   
    * Update the insets, which contain the caption if there
 185   
    * is a caption.
 186   
    */
 187  0
   void updateInsets() {
 188  0
     short top = (short) painter.getInset(TOP, this);
 189  0
     short bottom = (short) painter.getInset(BOTTOM, this);
 190  0
     if (captionIndex != -1) {
 191  0
       View caption = getView(captionIndex);
 192  0
       short h = (short) caption.getPreferredSpan(Y_AXIS);
 193  0
       AttributeSet a = caption.getAttributes();
 194   
             /* change in retrieval of CSS.Attribute.CAPTION_SIDE
 195   
                as this Attribute is not public */
 196   
       //de.calcom.cclib.html.HTMLDiag hd = new de.calcom.cclib.html.HTMLDiag();
 197   
       //hd.listAttributes(a, 2);
 198  0
       Object align = null;
 199   
       //Object align = a.getAttribute(attribute);
 200   
       //Object align = a.getAttribute(CSS.Attribute.CAPTION_SIDE);
 201   
             /* change end */
 202  0
       if ((align != null) && (align.equals("bottom"))) {
 203  0
         bottom += h;
 204   
       } else {
 205  0
         top += h;
 206   
       }
 207   
     }
 208  0
     setInsets(top, (short) painter.getInset(LEFT, this),
 209   
               bottom, (short) painter.getInset(RIGHT, this));
 210   
   }
 211   
 
 212   
   /**
 213   
    * Update any cached values that come from attributes.
 214   
    */
 215  0
   protected void setPropertiesFromAttributes() {
 216  0
     StyleSheet sheet = getStyleSheet();
 217  0
     attr = sheet.getViewAttributes(this);
 218  0
     painter = sheet.getBoxPainter(attr);
 219  0
     if (attr != null) {
 220  0
       setInsets((short) painter.getInset(TOP, this),
 221   
                 (short) painter.getInset(LEFT, this),
 222   
                 (short) painter.getInset(BOTTOM, this),
 223   
                 (short) painter.getInset(RIGHT, this));
 224   
 /*
 225   
           CSS.LengthValue lv = (CSS.LengthValue)
 226   
               attr.getAttribute(CSS.Attribute.BORDER_SPACING);
 227   
           if (lv != null) {
 228   
               cellSpacing = (int) lv.getValue();
 229   
           } else {
 230   
               cellSpacing = 0;
 231   
           }
 232   
           */
 233   
     }
 234   
   }
 235   
 
 236   
   /**
 237   
    * Fill in the grid locations that are placeholders
 238   
    * for multi-column, multi-row, and missing grid
 239   
    * locations.
 240   
    */
 241  0
   void updateGrid() {
 242  0
     if (! gridValid) {
 243  0
       relativeCells = false;
 244  0
       multiRowCells = false;
 245   
 
 246   
       // determine which views are table rows and clear out
 247   
       // grid points marked filled.
 248  0
       captionIndex = -1;
 249  0
       rows.removeAllElements();
 250  0
       int n = getViewCount();
 251  0
       for (int i = 0; i < n; i++) {
 252  0
         View v = getView(i);
 253  0
         if (v instanceof RowView) {
 254  0
           rows.addElement(v);
 255  0
           RowView rv = (RowView) v;
 256  0
           rv.clearFilledColumns();
 257  0
           rv.rowIndex = rows.size() - 1;
 258  0
           rv.viewIndex = i;
 259   
         } else {
 260  0
           Object o = v.getElement().getAttributes().getAttribute(StyleConstants.NameAttribute);
 261  0
           if (o instanceof HTML.Tag) {
 262  0
             HTML.Tag kind = (HTML.Tag) o;
 263  0
             if (kind == HTML.Tag.CAPTION) {
 264  0
               captionIndex = i;
 265   
             }
 266   
           }
 267   
         }
 268   
       }
 269   
 
 270  0
       int maxColumns = 0;
 271  0
       int nrows = rows.size();
 272  0
       for (int row = 0; row < nrows; row++) {
 273  0
         RowView rv = getRow(row);
 274  0
         int col = 0;
 275  0
         for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
 276  0
           View cv = rv.getView(cell);
 277  0
           if (! relativeCells) {
 278  0
             AttributeSet a = cv.getAttributes();
 279   
                       /*LengthVal lv = (LengthVal)
 280   
                           a.getAttribute(CSS.Attribute.WIDTH);*/
 281  0
             Object lv = a.getAttribute(CSS.Attribute.WIDTH);
 282  0
             if ((lv != null) /*&& (lv.isPercentage())*/) {
 283  0
               if(lv.toString().trim().endsWith("%")) {
 284  0
                 relativeCells = true;
 285   
               }
 286   
             }
 287   
           }
 288   
           // advance to a free column
 289  0
           for (; rv.isFilled(col); col++);
 290  0
           int rowSpan = getRowsOccupied(cv);
 291  0
           if (rowSpan > 1) {
 292  0
             multiRowCells = true;
 293   
           }
 294  0
           int colSpan = getColumnsOccupied(cv);
 295  0
           if ((colSpan > 1) || (rowSpan > 1)) {
 296   
             // fill in the overflow entries for this cell
 297  0
             int rowLimit = row + rowSpan;
 298  0
             int colLimit = col + colSpan;
 299  0
             for (int i = row; i < rowLimit; i++) {
 300  0
               for (int j = col; j < colLimit; j++) {
 301  0
                 if (i != row || j != col) {
 302  0
                   addFill(i, j);
 303   
                 }
 304   
               }
 305   
             }
 306  0
             if (colSpan > 1) {
 307  0
               col += colSpan - 1;
 308   
             }
 309   
           }
 310   
         }
 311  0
         maxColumns = Math.max(maxColumns, col);
 312   
       }
 313   
 
 314   
       // setup the column layout/requirements
 315  0
       columnSpans = new int[maxColumns];
 316  0
       columnOffsets = new int[maxColumns];
 317  0
       columnRequirements = new SizeRequirements[maxColumns];
 318  0
       for (int i = 0; i < maxColumns; i++) {
 319  0
         columnRequirements[i] = new SizeRequirements();
 320  0
         columnRequirements[i].maximum = Integer.MAX_VALUE;
 321   
       }
 322  0
       gridValid = true;
 323   
     }
 324   
   }
 325   
 
 326   
   /**
 327   
    * Mark a grid location as filled in for a cells overflow.
 328   
    */
 329  0
   void addFill(int row, int col) {
 330  0
     RowView rv = getRow(row);
 331  0
     if (rv != null) {
 332  0
       rv.fillColumn(col);
 333   
     }
 334   
   }
 335   
 
 336   
   /**
 337   
    * Layout the columns to fit within the given target span.
 338   
    *
 339   
    * @param targetSpan the given span for total of all the table
 340   
    *  columns
 341   
    * @param reqs the requirements desired for each column.  This
 342   
    *  is the column maximum of the cells minimum, preferred, and
 343   
    *  maximum requested span
 344   
    * @param spans the return value of how much to allocated to
 345   
    *  each column
 346   
    * @param offsets the return value of the offset from the
 347   
    *  origin for each column
 348   
    * @return the offset from the origin and the span for each column
 349   
    *  in the offsets and spans parameters
 350   
    */
 351  0
   protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,
 352   
                                SizeRequirements[] reqs) {
 353   
     //System.out.println("layoutColumns offsets=");
 354  0
     colIterator.setLayoutArrays(offsets, spans, targetSpan);
 355   
     //System.out.println("call to calculateTiledLayout from SHTMLTableView.layoutColumns");
 356  0
     calculateTiledLayout(colIterator, targetSpan);
 357   
   }
 358   
 
 359   
   /**
 360   
    * Calculate the requirements for each column.  The calculation
 361   
    * is done as two passes over the table.  The table cells that
 362   
    * occupy a single column are scanned first to determine the
 363   
    * maximum of minimum, preferred, and maximum spans along the
 364   
    * give axis.  Table cells that span multiple columns are excluded
 365   
    * from the first pass.  A second pass is made to determine if
 366   
    * the cells that span multiple columns are satisfied.  If the
 367   
    * column requirements are not satisified, the needs of the
 368   
    * multi-column cell is mixed into the existing column requirements.
 369   
    * The calculation of the multi-column distribution is based upon
 370   
    * the proportions of the existing column requirements and taking
 371   
    * into consideration any constraining maximums.
 372   
    */
 373  0
   void calculateColumnRequirements(int axis) {
 374   
     // pass 1 - single column cells
 375  0
     boolean hasMultiColumn = false;
 376  0
     int nrows = getRowCount();
 377  0
     for (int i = 0; i < nrows; i++) {
 378  0
       RowView row = getRow(i);
 379  0
       int col = 0;
 380  0
       int ncells = row.getViewCount();
 381  0
       for (int cell = 0; cell < ncells; cell++, col++) {
 382  0
         View cv = row.getView(cell);
 383  0
         for (; row.isFilled(col); col++); // advance to a free column
 384  0
         int rowSpan = getRowsOccupied(cv);
 385  0
         int colSpan = getColumnsOccupied(cv);
 386  0
         if (colSpan == 1) {
 387  0
           checkSingleColumnCell(axis, col, cv);
 388   
         } else {
 389  0
           hasMultiColumn = true;
 390  0
           col += colSpan - 1;
 391   
         }
 392   
       }
 393   
     }
 394   
 
 395   
     // pass 2 - multi-column cells
 396  0
     if (hasMultiColumn) {
 397  0
       for (int i = 0; i < nrows; i++) {
 398  0
         RowView row = getRow(i);
 399  0
         int col = 0;
 400  0
         int ncells = row.getViewCount();
 401  0
         for (int cell = 0; cell < ncells; cell++, col++) {
 402  0
           View cv = row.getView(cell);
 403  0
           for (; row.isFilled(col); col++); // advance to a free column
 404  0
           int colSpan = getColumnsOccupied(cv);
 405  0
           if (colSpan > 1) {
 406  0
             checkMultiColumnCell(axis, col, colSpan, cv);
 407  0
             col += colSpan - 1;
 408   
           }
 409   
         }
 410   
       }
 411   
     }
 412   
   }
 413   
 
 414   
   /**
 415   
    * check the requirements of a table cell that spans a single column.
 416   
    */
 417  0
   void checkSingleColumnCell(int axis, int col, View v) {
 418  0
     SizeRequirements req = columnRequirements[col];
 419  0
     req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
 420  0
     req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
 421   
   }
 422   
 
 423   
   /**
 424   
    * check the requirements of a table cell that spans multiple
 425   
    * columns.
 426   
    */
 427  0
   void checkMultiColumnCell(int axis, int col, int ncols, View v) {
 428   
     // calculate the totals
 429  0
     long min = 0;
 430  0
     long pref = 0;
 431  0
     long max = 0;
 432  0
     for (int i = 0; i < ncols; i++) {
 433  0
       SizeRequirements req = columnRequirements[col + i];
 434  0
       min += req.minimum;
 435  0
       pref += req.preferred;
 436  0
       max += req.maximum;
 437   
     }
 438   
 
 439   
     // check if the minimum size needs adjustment.
 440  0
     int cmin = (int) v.getMinimumSpan(axis);
 441  0
     if (cmin > min) {
 442   
           /*
 443   
       * the columns that this cell spans need adjustment to fit
 444   
       * this table cell.... calculate the adjustments.
 445   
            */
 446  0
       SizeRequirements[] reqs = new SizeRequirements[ncols];
 447  0
       for (int i = 0; i < ncols; i++) {
 448  0
         reqs[i] = columnRequirements[col + i];
 449   
       }
 450  0
       int[] spans = new int[ncols];
 451  0
       int[] offsets = new int[ncols];
 452  0
       SizeRequirements.calculateTiledPositions(cmin, null, reqs,
 453   
           offsets, spans);
 454   
       // apply the adjustments
 455  0
       for (int i = 0; i < ncols; i++) {
 456  0
         SizeRequirements req = reqs[i];
 457  0
         req.minimum = Math.max(spans[i], req.minimum);
 458  0
         req.preferred = Math.max(req.minimum, req.preferred);
 459  0
         req.maximum = Math.max(req.preferred, req.maximum);
 460   
       }
 461   
     }
 462   
 
 463   
     // check if the preferred size needs adjustment.
 464  0
     int cpref = (int) v.getPreferredSpan(axis);
 465  0
     if (cpref > pref) {
 466   
           /*
 467   
       * the columns that this cell spans need adjustment to fit
 468   
       * this table cell.... calculate the adjustments.
 469   
            */
 470  0
       SizeRequirements[] reqs = new SizeRequirements[ncols];
 471  0
       for (int i = 0; i < ncols; i++) {
 472  0
         reqs[i] = columnRequirements[col + i];
 473   
       }
 474  0
       int[] spans = new int[ncols];
 475  0
       int[] offsets = new int[ncols];
 476  0
       SizeRequirements.calculateTiledPositions(cpref, null, reqs,
 477   
           offsets, spans);
 478   
       // apply the adjustments
 479  0
       for (int i = 0; i < ncols; i++) {
 480  0
         SizeRequirements req = reqs[i];
 481  0
         req.preferred = Math.max(spans[i], req.preferred);
 482  0
         req.maximum = Math.max(req.preferred, req.maximum);
 483   
       }
 484   
     }
 485   
 
 486   
   }
 487   
 
 488   
   // --- BoxView methods -----------------------------------------
 489   
 
 490   
   /**
 491   
    * Calculate the requirements for the minor axis.  This is called by
 492   
    * the superclass whenever the requirements need to be updated (i.e.
 493   
    * a preferenceChanged was messaged through this view).
 494   
    * <p>
 495   
    * This is implemented to calculate the requirements as the sum of the
 496   
    * requirements of the columns and then adjust it if the
 497   
    * CSS width or height attribute is specified and applicable to
 498   
    * the axis.
 499   
    */
 500  0
   protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
 501  0
     updateGrid();
 502   
 
 503   
     // calculate column requirements for each column
 504  0
     calculateColumnRequirements(axis);
 505   
 
 506   
 
 507   
     // the requirements are the sum of the columns.
 508  0
     if (r == null) {
 509  0
       r = new SizeRequirements();
 510   
     }
 511  0
     long min = 0;
 512  0
     long pref = 0;
 513  0
     int n = columnRequirements.length;
 514  0
     for (int i = 0; i < n; i++) {
 515  0
       SizeRequirements req = columnRequirements[i];
 516  0
       min += req.minimum;
 517  0
       pref += req.preferred;
 518   
     }
 519  0
     int adjust = (n - 1) * cellSpacing;
 520  0
     min += adjust;
 521  0
     pref += adjust;
 522  0
     r.minimum = (int) min;
 523  0
     r.preferred = (int) pref;
 524  0
     r.maximum = (int) pref;
 525   
 
 526   
 
 527  0
     AttributeSet attr = getAttributes();
 528   
       /*LengthVal cssWidth = (LengthVal)attr.getAttribute(
 529   
                                                   CSS.Attribute.WIDTH);*/
 530  0
     Object cssWidth = attr.getAttribute(CSS.Attribute.WIDTH);
 531   
 
 532  0
     if (SHTMLBlockView.spanSetFromAttributes(axis, r, cssWidth, null)) {
 533  0
       if (r.minimum < (int)min) {
 534   
         // The user has requested a smaller size than is needed to
 535   
         // show the table, override it.
 536  0
         r.maximum = r.minimum = r.preferred = (int) min;
 537   
       }
 538   
     }
 539  0
     totalColumnRequirements.minimum = r.minimum;
 540  0
     totalColumnRequirements.preferred = r.preferred;
 541  0
     totalColumnRequirements.maximum = r.maximum;
 542   
 
 543   
     // set the alignment
 544  0
     Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
 545  0
     if (o != null) {
 546   
       // set horizontal alignment
 547  0
       String ta = o.toString();
 548  0
       if (ta.equals("left")) {
 549  0
         r.alignment = 0;
 550  0
       } else if (ta.equals("center")) {
 551  0
         r.alignment = 0.5f;
 552  0
       } else if (ta.equals("right")) {
 553  0
         r.alignment = 1;
 554   
       } else {
 555  0
         r.alignment = 0;
 556   
       }
 557   
     } else {
 558  0
       r.alignment = 0;
 559   
     }
 560   
 
 561  0
     return r;
 562   
   }
 563   
 
 564   
   /**
 565   
    * Calculate the requirements for the major axis.  This is called by
 566   
    * the superclass whenever the requirements need to be updated (i.e.
 567   
    * a preferenceChanged was messaged through this view).
 568   
    * <p>
 569   
    * This is implemented to provide the superclass behavior adjusted for
 570   
    * multi-row table cells.
 571   
    */
 572  0
   protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
 573  0
     updateInsets();
 574  0
     rowIterator.updateAdjustments();
 575   
     //System.out.println("call to calculateTiledRequirements from SHTMLTableView.calculateMajorAxisRequirements");
 576  0
     r = calculateTiledRequirements(rowIterator, r);
 577  0
     r.maximum = r.preferred;
 578  0
     return r;
 579   
   }
 580   
 
 581   
   /**
 582   
    * Perform layout for the minor axis of the box (i.e. the
 583   
    * axis orthoginal to the axis that it represents).  The results
 584   
    * of the layout should be placed in the given arrays which represent
 585   
    * the allocations to the children along the minor axis.  This
 586   
    * is called by the superclass whenever the layout needs to be
 587   
    * updated along the minor axis.
 588   
    * <p>
 589   
    * This is implemented to call the
 590   
    * <a href="#layoutColumns">layoutColumns</a> method, and then
 591   
    * forward to the superclass to actually carry out the layout
 592   
    * of the tables rows.
 593   
    *
 594   
    * @param targetSpan the total span given to the view, which
 595   
    *  whould be used to layout the children
 596   
    * @param axis the axis being layed out
 597   
    * @param offsets the offsets from the origin of the view for
 598   
    *  each of the child views.  This is a return value and is
 599   
    *  filled in by the implementation of this method
 600   
    * @param spans the span of each child view;  this is a return
 601   
    *  value and is filled in by the implementation of this method
 602   
    * @return the offset and span for each child view in the
 603   
    *  offsets and spans parameters
 604   
    */
 605  0
   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
 606   
     // make grid is properly represented
 607  0
     updateGrid();
 608   
 
 609   
     // all of the row layouts are invalid, so mark them that way
 610  0
     int n = getRowCount();
 611  0
     for (int i = 0; i < n; i++) {
 612  0
       RowView row = getRow(i);
 613  0
       row.layoutChanged(axis);
 614   
     }
 615   
 
 616   
     // calculate column spans
 617  0
     layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
 618   
 
 619   
     // continue normal layout
 620  0
     super.layoutMinorAxis(targetSpan, axis, offsets, spans);
 621   
   }
 622   
 
 623   
 
 624   
   /**
 625   
    * Perform layout for the major axis of the box (i.e. the
 626   
    * axis that it represents).  The results
 627   
    * of the layout should be placed in the given arrays which represent
 628   
    * the allocations to the children along the minor axis.  This
 629   
    * is called by the superclass whenever the layout needs to be
 630   
    * updated along the minor axis.
 631   
    * <p>
 632   
    * This method is where the layout of the table rows within the
 633   
    * table takes place.  This method is implemented to call the use
 634   
    * the RowIterator and the CSS collapsing tile to layout
 635   
    * with border spacing and border collapsing capabilities.
 636   
    *
 637   
    * @param targetSpan the total span given to the view, which
 638   
    *  whould be used to layout the children
 639   
    * @param axis the axis being layed out
 640   
    * @param offsets the offsets from the origin of the view for
 641   
    *  each of the child views; this is a return value and is
 642   
    *  filled in by the implementation of this method
 643   
    * @param spans the span of each child view; this is a return
 644   
    *  value and is filled in by the implementation of this method
 645   
    * @return the offset and span for each child view in the
 646   
    *  offsets and spans parameters
 647   
    */
 648  0
   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
 649  0
     rowIterator.setLayoutArrays(offsets, spans);
 650   
     //System.out.println("call to calculateTiledLayout from SHTMLTableView.layoutMajorAxis");
 651  0
     calculateTiledLayout(rowIterator, targetSpan);
 652   
 
 653  0
     if (captionIndex != -1) {
 654   
       // place the caption
 655  0
       View caption = getView(captionIndex);
 656  0
       int h = (int) caption.getPreferredSpan(Y_AXIS);
 657  0
       spans[captionIndex] = h;
 658  0
       short boxBottom = (short) painter.getInset(BOTTOM, this);
 659  0
       if (boxBottom != getBottomInset()) {
 660  0
         offsets[captionIndex] = targetSpan + boxBottom;
 661   
       } else {
 662  0
         offsets[captionIndex] = - getTopInset();
 663   
       }
 664   
     }
 665   
   }
 666   
 
 667   
   /**
 668   
    * Fetches the child view that represents the given position in
 669   
    * the model.  This is implemented to walk through the children
 670   
    * looking for a range that contains the given position.  In this
 671   
    * view the children do not necessarily have a one to one mapping
 672   
    * with the child elements.
 673   
    *
 674   
    * @param pos  the search position >= 0
 675   
    * @param a  the allocation to the table on entry, and the
 676   
    *   allocation of the view containing the position on exit
 677   
    * @return  the view representing the given position, or
 678   
    *   null if there isn't one
 679   
    */
 680  0
   protected View getViewAtPosition(int pos, Rectangle a) {
 681  0
     int n = getViewCount();
 682  0
     for (int i = 0; i < n; i++) {
 683  0
       View v = getView(i);
 684  0
       int p0 = v.getStartOffset();
 685  0
       int p1 = v.getEndOffset();
 686  0
       if ((pos >= p0) && (pos < p1)) {
 687   
         // it's in this view.
 688  0
         if (a != null) {
 689  0
           childAllocation(i, a);
 690   
         }
 691  0
         return v;
 692   
       }
 693   
     }
 694  0
     if (pos == getEndOffset()) {
 695  0
       View v = getView(n - 1);
 696  0
       if (a != null) {
 697  0
         this.childAllocation(n - 1, a);
 698   
       }
 699  0
       return v;
 700   
     }
 701  0
     return null;
 702   
   }
 703   
 
 704   
   // --- View methods ---------------------------------------------
 705   
 
 706   
   /**
 707   
    * Fetches the attributes to use when rendering.  This is
 708   
    * implemented to multiplex the attributes specified in the
 709   
    * model with a StyleSheet.
 710   
    */
 711  0
   public AttributeSet getAttributes() {
 712  0
     if (attr == null) {
 713  0
       StyleSheet sheet = getStyleSheet();
 714  0
       attr = sheet.getViewAttributes(this);
 715   
     }
 716  0
     return attr;
 717   
   }
 718   
 
 719   
   /**
 720   
    * Renders using the given rendering surface and area on that
 721   
    * surface.  This is implemented to delegate to the css box
 722   
    * painter to paint the border and background prior to the
 723   
    * interior.  The superclass culls rendering the children
 724   
    * that don't directly intersect the clip and the row may
 725   
    * have cells hanging from a row above in it.  The table
 726   
    * does not use the superclass rendering behavior and instead
 727   
    * paints all of the rows and lets the rows cull those
 728   
    * cells not intersecting the clip region.
 729   
    *
 730   
    * @param g the rendering surface to use
 731   
    * @param allocation the allocated region to render into
 732   
    * @see View#paint
 733   
    */
 734  0
   public void paint(Graphics g, Shape allocation) {
 735   
     // paint the border
 736  0
     Rectangle a = allocation.getBounds();
 737  0
     setSize(a.width, a.height);
 738  0
     if (captionIndex != -1) {
 739   
       // adjust the border for the caption
 740  0
       short top = (short) painter.getInset(TOP, this);
 741  0
       short bottom = (short) painter.getInset(BOTTOM, this);
 742  0
       if (top != getTopInset()) {
 743  0
         int h = getTopInset() - top;
 744  0
         a.y += h;
 745  0
         a.height -= h;
 746   
       } else {
 747  0
         a.height -= getBottomInset() - bottom;
 748   
       }
 749   
     }
 750   
     //System.out.println("SHTMLTableView paint a.x=" + a.x + " a.y=" + a.y + "a.width=" + a.width + " a.height=" + a.height);
 751  0
     painter.paint(g, a.x, a.y, a.width, a.height, this);
 752   
 
 753   
     // paint interior
 754  0
     int n = getViewCount();
 755  0
     for (int i = 0; i < n; i++) {
 756  0
       View v = getView(i);
 757  0
       v.paint(g, getChildAllocation(i, allocation));
 758   
     }
 759   
     //super.paint(g, a);
 760   
   }
 761   
 
 762   
   /**
 763   
    * Establishes the parent view for this view.  This is
 764   
    * guaranteed to be called before any other methods if the
 765   
    * parent view is functioning properly.
 766   
    * <p>
 767   
    * This is implemented
 768   
    * to forward to the superclass as well as call the
 769   
    * <a href="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
 770   
    * method to set the paragraph properties from the css
 771   
    * attributes.  The call is made at this time to ensure
 772   
    * the ability to resolve upward through the parents
 773   
    * view attributes.
 774   
    *
 775   
    * @param parent the new parent, or null if the view is
 776   
    *  being removed from a parent it was previously added
 777   
    *  to
 778   
    */
 779  0
   public void setParent(View parent) {
 780  0
     super.setParent(parent);
 781  0
     if (parent != null) {
 782  0
       setPropertiesFromAttributes();
 783   
     }
 784   
   }
 785   
 
 786   
   /**
 787   
    * Fetches the ViewFactory implementation that is feeding
 788   
    * the view hierarchy.
 789   
    * This replaces the ViewFactory with an implementation that
 790   
    * calls through to the createTableRow and createTableCell
 791   
    * methods.   If the element given to the factory isn't a
 792   
    * table row or cell, the request is delegated to the factory
 793   
    * produced by the superclass behavior.
 794   
    *
 795   
    * @return the factory, null if none
 796   
    */
 797  0
   public ViewFactory getViewFactory() {
 798  0
     return this;
 799   
   }
 800   
 
 801   
   /**
 802   
    * Gives notification that something was inserted into
 803   
    * the document in a location that this view is responsible for.
 804   
    * This replaces the ViewFactory with an implementation that
 805   
    * calls through to the createTableRow and createTableCell
 806   
    * methods.   If the element given to the factory isn't a
 807   
    * table row or cell, the request is delegated to the factory
 808   
    * passed as an argument.
 809   
    *
 810   
    * @param e the change information from the associated document
 811   
    * @param a the current allocation of the view
 812   
    * @param f the factory to use to rebuild if the view has children
 813   
    * @see View#insertUpdate
 814   
    */
 815  0
   public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
 816  0
     super.insertUpdate(e, a, this);
 817   
   }
 818   
 
 819   
   /**
 820   
    * Gives notification that something was removed from the document
 821   
    * in a location that this view is responsible for.
 822   
    * This replaces the ViewFactory with an implementation that
 823   
    * calls through to the createTableRow and createTableCell
 824   
    * methods.   If the element given to the factory isn't a
 825   
    * table row or cell, the request is delegated to the factory
 826   
    * passed as an argument.
 827   
    *
 828   
    * @param e the change information from the associated document
 829   
    * @param a the current allocation of the view
 830   
    * @param f the factory to use to rebuild if the view has children
 831   
    * @see View#removeUpdate
 832   
    */
 833  0
   public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
 834  0
     super.removeUpdate(e, a, this);
 835   
   }
 836   
 
 837   
   /**
 838   
    * Gives notification from the document that attributes were changed
 839   
    * in a location that this view is responsible for.
 840   
    * This replaces the ViewFactory with an implementation that
 841   
    * calls through to the createTableRow and createTableCell
 842   
    * methods.   If the element given to the factory isn't a
 843   
    * table row or cell, the request is delegated to the factory
 844   
    * passed as an argument.
 845   
    *
 846   
    * @param e the change information from the associated document
 847   
    * @param a the current allocation of the view
 848   
    * @param f the factory to use to rebuild if the view has children
 849   
    * @see View#changedUpdate
 850   
    */
 851  0
   public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
 852  0
     super.changedUpdate(e, a, this);
 853   
   }
 854   
 
 855  0
   protected void forwardUpdate(DocumentEvent.ElementChange ec,
 856   
                                DocumentEvent e, Shape a, ViewFactory f) {
 857  0
     super.forwardUpdate(ec, e, a, f);
 858   
     // A change in any of the table cells usually effects the whole table,
 859   
     // so redraw it all!
 860  0
     if (a != null) {
 861  0
       Component c = getContainer();
 862  0
       if (c != null) {
 863  0
         Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
 864   
                           a.getBounds();
 865  0
         c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 866   
       }
 867   
     }
 868   
   }
 869   
 
 870   
   /**
 871   
    * Change the child views.  This is implemented to
 872   
    * provide the superclass behavior and invalidate the
 873   
    * grid so that rows and columns will be recalculated.
 874   
    */
 875  0
   public void replace(int offset, int length, View[] views) {
 876  0
     super.replace(offset, length, views);
 877  0
     invalidateGrid();
 878   
   }
 879   
 
 880   
   // --- ViewFactory methods ------------------------------------------
 881   
 
 882   
   /**
 883   
    * The table itself acts as a factory for the various
 884   
    * views that actually represent pieces of the table.
 885   
    * All other factory activity is delegated to the factory
 886   
    * returned by the parent of the table.
 887   
    */
 888  0
   public View create(Element elem) {
 889  0
     Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
 890  0
     if (o instanceof HTML.Tag) {
 891  0
       HTML.Tag kind = (HTML.Tag) o;
 892  0
       if (kind == HTML.Tag.TR) {
 893  0
         return createTableRow(elem);
 894  0
       } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) {
 895  0
         return new CellView(elem);
 896  0
       } else if (kind == HTML.Tag.CAPTION) {
 897  0
         return new javax.swing.text.html.ParagraphView(elem);
 898   
       }
 899   
     }
 900   
     // default is to delegate to the normal factory
 901  0
     View p = getParent();
 902  0
     if (p != null) {
 903  0
       ViewFactory f = p.getViewFactory();
 904  0
       if (f != null) {
 905  0
         return f.create(elem);
 906   
       }
 907   
     }
 908  0
     return null;
 909   
   }
 910   
 
 911   
   // ---- variables ----------------------------------------------------
 912   
 
 913   
   private AttributeSet attr;
 914   
   private StyleSheet.BoxPainter painter;
 915   
 
 916   
   private int cellSpacing;
 917   
 
 918   
   /**
 919   
    * The index of the caption view if there is a caption.
 920   
    * This has a value of -1 if there is no caption.  The
 921   
    * caption lives in the inset area of the table, and is
 922   
    * updated with each time the grid is recalculated.
 923   
    */
 924   
   private int captionIndex;
 925   
 
 926   
   /**
 927   
    * Do any of the table cells contain a relative size
 928   
    * specification?  This is updated with each call to
 929   
    * updateGrid().  If this is true, the ColumnIterator
 930   
    * will do extra work to calculate relative cell
 931   
    * specifications.
 932   
    */
 933   
   private boolean relativeCells;
 934   
 
 935   
   /**
 936   
    * Do any of the table cells span multiple rows?  If
 937   
    * true, the RowRequirementIterator will do additional
 938   
    * work to adjust the requirements of rows spanned by
 939   
    * a single table cell.  This is updated with each call to
 940   
    * updateGrid().
 941   
    */
 942   
   private boolean multiRowCells;
 943   
 
 944   
   int[] columnSpans;
 945   
   int[] columnOffsets;
 946   
   /**
 947   
    * SizeRequirements for all the columns.
 948   
    */
 949   
   SizeRequirements totalColumnRequirements;
 950   
   SizeRequirements[] columnRequirements;
 951   
 
 952   
   RowIterator rowIterator = new RowIterator();
 953   
   ColumnIterator colIterator = new ColumnIterator();
 954   
 
 955   
   Vector rows;
 956   
 
 957   
   boolean gridValid;
 958   
   static final private BitSet EMPTY = new BitSet();
 959   
 
 960   
   class ColumnIterator implements LayoutIterator {
 961   
 
 962   
     /**
 963   
      * Disable percentage adjustments which should only apply
 964   
      * when calculating layout, not requirements.
 965   
      */
 966  0
     void disablePercentages() {
 967  0
       percentages = null;
 968   
     }
 969   
 
 970   
     /**
 971   
      * Update percentage adjustments if they are needed.
 972   
      */
 973  0
     private void updatePercentages(int span) {
 974  0
       if (relativeCells) {
 975  0
         percentages = new int[columnRequirements.length];
 976   
 
 977  0
         int nrows = getRowCount();
 978  0
         for (int rowIndex = 0; rowIndex < nrows; rowIndex++) {
 979  0
           RowView row = getRow(rowIndex);
 980  0
           int col = 0;
 981  0
           int ncells = row.getViewCount();
 982  0
           for (int cell = 0; cell < ncells; cell++, col++) {
 983  0
             View cv = row.getView(cell);
 984  0
             for (; row.isFilled(col); col++); // advance to a free column
 985  0
             int rowSpan = getRowsOccupied(cv);
 986  0
             int colSpan = getColumnsOccupied(cv);
 987   
 
 988  0
             AttributeSet a = cv.getAttributes();
 989   
                       /*LengthVal lv = (LengthVal)
 990   
                           a.getAttribute(CSS.Attribute.WIDTH);*/
 991  0
             Object lv = a.getAttribute(CSS.Attribute.WIDTH);
 992  0
             if ((lv != null) /*&& (lv.isPercentage())*/) {
 993  0
               if(lv.toString().trim().endsWith("%")) {
 994   
                 // add a percentage requirement
 995   
                 //System.out.println("lv.toString=" + lv.toString());
 996   
                 //System.out.println("lv val=" + Util.getPtValue(lv.toString()));
 997   
                 //System.out.println("span=" + span);
 998   
                 //System.out.println("colSpan=" + colSpan);
 999   
                 //System.out.println("len=" + ((int) (/*lv.getValue(span)*/ (Util.getPtValue(lv.toString()) * new Integer(span).floatValue()) / new Integer(colSpan).floatValue() + 0.5f)));
 1000  0
                 int len = (int) (/*lv.getValue(span)*/ (Util.getPtValue(lv.toString()) * new Integer(span).floatValue()) / new Integer(colSpan).floatValue() + 0.5f);
 1001  0
                 for (int i = 0; i < colSpan; i++) {
 1002  0
                   percentages[col+i] = Math.max(percentages[col+i], len);
 1003   
                 }
 1004   
               }
 1005   
             }
 1006  0
             col += colSpan - 1;
 1007   
           }
 1008   
         }
 1009   
       } else {
 1010  0
         percentages = null;
 1011   
       }
 1012   
     }
 1013   
 
 1014   
     /**
 1015   
      * Set the layout arrays to use for holding layout results
 1016   
      */
 1017  0
     public void setLayoutArrays(int offsets[], int spans[], int targetSpan) {
 1018  0
       this.offsets = offsets;
 1019  0
       this.spans = spans;
 1020  0
       updatePercentages(targetSpan);
 1021   
     }
 1022   
 
 1023   
     // --- RequirementIterator methods -------------------
 1024   
 
 1025  0
     public int getCount() {
 1026  0
       return columnRequirements.length;
 1027   
     }
 1028   
 
 1029  0
     public void setIndex(int i) {
 1030  0
       col = i;
 1031   
     }
 1032   
 
 1033  0
     public void setOffset(int offs) {
 1034  0
       offsets[col] = offs;
 1035   
     }
 1036   
 
 1037  0
     public int getOffset() {
 1038  0
       return offsets[col];
 1039   
     }
 1040   
 
 1041  0
     public void setSpan(int span) {
 1042  0
       spans[col] = span;
 1043   
     }
 1044   
 
 1045  0
     public int getSpan() {
 1046  0
       return spans[col];
 1047   
     }
 1048   
 
 1049  0
     public float getMinimumSpan(float parentSpan) {
 1050  0
       if ((percentages != null) && (percentages[col] != 0)) {
 1051  0
         return Math.max(percentages[col], columnRequirements[col].minimum);
 1052   
       }
 1053  0
       return columnRequirements[col].minimum;
 1054   
     }
 1055   
 
 1056  0
     public float getPreferredSpan(float parentSpan) {
 1057  0
       if ((percentages != null) && (percentages[col] != 0)) {
 1058  0
         return Math.max(percentages[col], columnRequirements[col].preferred);
 1059   
       }
 1060  0
       return columnRequirements[col].preferred;
 1061   
     }
 1062   
 
 1063  0
     public float getMaximumSpan(float parentSpan) {
 1064  0
       if ((percentages != null) && (percentages[col] != 0)) {
 1065  0
         return Math.max(percentages[col], columnRequirements[col].preferred);
 1066   
       }
 1067  0
       return columnRequirements[col].maximum;
 1068   
     }
 1069   
 
 1070  0
     public float getLeadingCollapseSpan() {
 1071  0
       return cellSpacing;
 1072   
     }
 1073   
 
 1074  0
     public float getTrailingCollapseSpan() {
 1075  0
       return cellSpacing;
 1076   
     }
 1077   
 
 1078   
     /**
 1079   
      * Current column index
 1080   
      */
 1081   
     private int col;
 1082   
 
 1083   
     /**
 1084   
      * percentage values (may be null since there
 1085   
      * might not be any).
 1086   
      */
 1087   
     private int[] percentages;
 1088   
 
 1089   
     private int[] offsets;
 1090   
     private int[] spans;
 1091   
   }
 1092   
 
 1093   
   class RowIterator implements LayoutIterator {
 1094   
 
 1095  0
     RowIterator() {
 1096   
     }
 1097   
 
 1098  0
     void updateAdjustments() {
 1099  0
       int axis = Y_AXIS;
 1100  0
       if (multiRowCells) {
 1101   
         // adjust requirements of multi-row cells
 1102  0
         int n = getRowCount();
 1103  0
         adjustments = new int[n];
 1104  0
         for (int i = 0; i < n; i++) {
 1105  0
           RowView rv = getRow(i);
 1106  0
           if (rv.multiRowCells == true) {
 1107  0
             int ncells = rv.getViewCount();
 1108  0
             for (int j = 0; j < ncells; j++) {
 1109  0
               View v = rv.getView(j);
 1110  0
               int nrows = getRowsOccupied(v);
 1111  0
               if (nrows > 1) {
 1112  0
                 int spanNeeded = (int) v.getPreferredSpan(axis);
 1113  0
                 adjustMultiRowSpan(spanNeeded, nrows, i);
 1114   
               }
 1115   
             }
 1116   
           }
 1117   
         }
 1118   
       } else {
 1119  0
         adjustments = null;
 1120   
       }
 1121   
     }
 1122   
 
 1123   
     /**
 1124   
      * Fixup preferences to accomodate a multi-row table cell
 1125   
      * if not already covered by existing preferences.  This is
 1126   
      * a no-op if not all of the rows needed (to do this check/fixup)
 1127   
      * have arrived yet.
 1128   
      */
 1129  0
     void adjustMultiRowSpan(int spanNeeded, int nrows, int rowIndex) {
 1130  0
       if ((rowIndex + nrows) > getCount()) {
 1131   
         // rows are missing (could be a bad rowspan specification)
 1132   
         // or not all the rows have arrived.  Do the best we can with
 1133   
         // the current set of rows.
 1134  0
         nrows = getCount() - rowIndex;
 1135  0
         if (nrows < 1) {
 1136  0
           return;
 1137   
         }
 1138   
       }
 1139  0
       int span = 0;
 1140  0
       for (int i = 0; i < nrows; i++) {
 1141  0
         RowView rv = getRow(rowIndex + i);
 1142  0
         span += rv.getPreferredSpan(Y_AXIS);
 1143   
       }
 1144  0
       if (spanNeeded > span) {
 1145  0
         int adjust = (spanNeeded - span);
 1146  0
         int rowAdjust = adjust / nrows;
 1147  0
         int firstAdjust = rowAdjust + (adjust - (rowAdjust * nrows));
 1148  0
         RowView rv = getRow(rowIndex);
 1149  0
         adjustments[rowIndex] = Math.max(adjustments[rowIndex],
 1150   
             firstAdjust);
 1151  0
         for (int i = 1; i < nrows; i++) {
 1152  0
           adjustments[rowIndex + i] = Math.max(
 1153   
           adjustments[rowIndex + i], rowAdjust);
 1154   
         }
 1155   
       }
 1156   
     }
 1157   
 
 1158  0
     void setLayoutArrays(int[] offsets, int[] spans) {
 1159  0
       this.offsets = offsets;
 1160  0
       this.spans = spans;
 1161   
     }
 1162   
 
 1163   
     // --- RequirementIterator methods -------------------
 1164   
 
 1165  0
     public void setOffset(int offs) {
 1166  0
       RowView rv = getRow(row);
 1167  0
       if (rv != null) {
 1168  0
         offsets[rv.viewIndex] = offs;
 1169   
       }
 1170   
     }
 1171   
 
 1172  0
     public int getOffset() {
 1173  0
       RowView rv = getRow(row);
 1174  0
       if (rv != null) {
 1175  0
         return offsets[rv.viewIndex];
 1176   
       }
 1177  0
       return 0;
 1178   
     }
 1179   
 
 1180  0
     public void setSpan(int span) {
 1181  0
       RowView rv = getRow(row);
 1182  0
       if (rv != null) {
 1183  0
         spans[rv.viewIndex] = span;
 1184   
       }
 1185   
     }
 1186   
 
 1187  0
     public int getSpan() {
 1188  0
       RowView rv = getRow(row);
 1189  0
       if (rv != null) {
 1190  0
         return spans[rv.viewIndex];
 1191   
       }
 1192  0
       return 0;
 1193   
     }
 1194   
 
 1195  0
     public int getCount() {
 1196  0
       return rows.size();
 1197   
     }
 1198   
 
 1199  0
     public void setIndex(int i) {
 1200  0
       row = i;
 1201   
     }
 1202   
 
 1203  0
     public float getMinimumSpan(float parentSpan) {
 1204  0
       return getPreferredSpan(parentSpan);
 1205   
     }
 1206   
 
 1207  0
     public float getPreferredSpan(float parentSpan) {
 1208  0
       RowView rv = getRow(row);
 1209  0
       if (rv != null) {
 1210  0
         int adjust = (adjustments != null) ? adjustments[row] : 0;
 1211  0
         adjust += 2 * cellSpacing;
 1212  0
         return rv.getPreferredSpan(SHTMLTableView.this.getAxis()) + adjust;
 1213   
       }
 1214  0
       return 0;
 1215   
     }
 1216   
 
 1217  0
     public float getMaximumSpan(float parentSpan) {
 1218  0
       return getPreferredSpan(parentSpan);
 1219   
     }
 1220   
 
 1221  0
     public float getLeadingCollapseSpan() {
 1222  0
       return cellSpacing;
 1223   
     }
 1224   
 
 1225  0
     public float getTrailingCollapseSpan() {
 1226  0
       return cellSpacing;
 1227   
     }
 1228   
 
 1229   
     /**
 1230   
      * Current row index
 1231   
      */
 1232   
     private int row;
 1233   
 
 1234   
     /**
 1235   
      * Adjustments to the row requirements to handle multi-row
 1236   
      * table cells.
 1237   
      */
 1238   
     private int[] adjustments;
 1239   
 
 1240   
     private int[] offsets;
 1241   
     private int[] spans;
 1242   
   }
 1243   
 
 1244   
   /**
 1245   
    * View of a row in a row-centric table.
 1246   
    */
 1247   
   public class RowView extends BoxView {
 1248   
 
 1249   
     /**
 1250   
      * Constructs a TableView for the given element.
 1251   
      *
 1252   
      * @param elem the element that this view is responsible for
 1253   
      */
 1254  0
     public RowView(Element elem) {
 1255  0
       super(elem, View.X_AXIS);
 1256  0
       fillColumns = new BitSet();
 1257  0
       RowView.this.setPropertiesFromAttributes();
 1258   
     }
 1259   
 
 1260  0
     void clearFilledColumns() {
 1261  0
       fillColumns.and(EMPTY);
 1262   
     }
 1263   
 
 1264  0
     void fillColumn(int col) {
 1265  0
       fillColumns.set(col);
 1266   
     }
 1267   
 
 1268  0
     boolean isFilled(int col) {
 1269  0
       return fillColumns.get(col);
 1270   
     }
 1271   
 
 1272   
     /**
 1273   
      * The number of columns present in this row.
 1274   
      */
 1275  0
     int getColumnCount() {
 1276  0
       int nfill = 0;
 1277  0
       int n = fillColumns.size();
 1278  0
       for (int i = 0; i < n; i++) {
 1279  0
         if (fillColumns.get(i)) {
 1280  0
           nfill ++;
 1281   
         }
 1282   
       }
 1283  0
       return getViewCount() + nfill;
 1284   
     }
 1285   
 
 1286   
     /**
 1287   
      * Fetches the attributes to use when rendering.  This is
 1288   
      * implemented to multiplex the attributes specified in the
 1289   
      * model with a StyleSheet.
 1290   
      */
 1291  0
     public AttributeSet getAttributes() {
 1292  0
       return attr;
 1293   
     }
 1294   
 
 1295  0
     protected StyleSheet getStyleSheet() {
 1296  0
       HTMLDocument doc = (HTMLDocument) getDocument();
 1297  0
       return doc.getStyleSheet();
 1298   
     }
 1299   
 
 1300   
     /**
 1301   
      * This is called by a child to indicate its
 1302   
      * preferred span has changed.  This is implemented to
 1303   
      * execute the superclass behavior and well as try to
 1304   
      * determine if a row with a multi-row cell hangs across
 1305   
      * this row.  If a multi-row cell covers this row it also
 1306   
      * needs to propagate a preferenceChanged so that it will
 1307   
      * recalculate the multi-row cell.
 1308   
      *
 1309   
      * @param child the child view
 1310   
      * @param width true if the width preference should change
 1311   
      * @param height true if the height preference should change
 1312   
      */
 1313  0
     public void preferenceChanged(View child, boolean width, boolean height) {
 1314  0
       super.preferenceChanged(child, width, height);
 1315  0
       if (SHTMLTableView.this.multiRowCells && height) {
 1316  0
         for (int i = rowIndex  - 1; i >= 0; i--) {
 1317  0
           RowView rv = SHTMLTableView.this.getRow(i);
 1318  0
           if (rv.multiRowCells) {
 1319  0
             rv.preferenceChanged(null, false, true);
 1320  0
             break;
 1321   
           }
 1322   
         }
 1323   
       }
 1324   
     }
 1325   
 
 1326   
     // The major axis requirements for a row are dictated by the column
 1327   
     // requirements. These methods use the value calculated by
 1328   
     // TableView.
 1329  0
     protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
 1330  0
       SizeRequirements req = new SizeRequirements();
 1331  0
       req.minimum = totalColumnRequirements.minimum;
 1332  0
       req.maximum = totalColumnRequirements.maximum;
 1333  0
       req.preferred = totalColumnRequirements.preferred;
 1334  0
       req.alignment = 0f;
 1335  0
       return req;
 1336   
     }
 1337   
 
 1338  0
     public float getMinimumSpan(int axis) {
 1339  0
       float value;
 1340   
 
 1341  0
       if (axis == View.X_AXIS) {
 1342  0
         value = totalColumnRequirements.minimum + getLeftInset() +
 1343   
                 getRightInset();
 1344   
       }
 1345   
       else {
 1346  0
         value = super.getMinimumSpan(axis);
 1347   
       }
 1348  0
       return value;
 1349   
     }
 1350   
 
 1351  0
     public float getMaximumSpan(int axis) {
 1352  0
       float value;
 1353   
 
 1354  0
       if (axis == View.X_AXIS) {
 1355   
         // We're flexible.
 1356  0
         value = (float)Integer.MAX_VALUE;
 1357   
       }
 1358   
       else {
 1359  0
         value = super.getMaximumSpan(axis);
 1360   
       }
 1361  0
       return value;
 1362   
     }
 1363   
 
 1364  0
     public float getPreferredSpan(int axis) {
 1365  0
       float value;
 1366   
 
 1367  0
       if (axis == View.X_AXIS) {
 1368  0
         value = totalColumnRequirements.preferred + getLeftInset() +
 1369   
                 getRightInset();
 1370   
       }
 1371   
       else {
 1372  0
         value = super.getPreferredSpan(axis);
 1373   
       }
 1374  0
       return value;
 1375   
     }
 1376   
 
 1377  0
     public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
 1378  0
       super.changedUpdate(e, a, f);
 1379  0
       int pos = e.getOffset();
 1380  0
       if (pos <= getStartOffset() && (pos + e.getLength()) >=
 1381   
           getEndOffset()) {
 1382  0
         RowView.this.setPropertiesFromAttributes();
 1383   
       }
 1384   
     }
 1385   
 
 1386   
     /**
 1387   
      * Renders using the given rendering surface and area on that
 1388   
      * surface.  This is implemented to delegate to the css box
 1389   
      * painter to paint the border and background prior to the
 1390   
      * interior.
 1391   
      *
 1392   
      * @param g the rendering surface to use
 1393   
      * @param allocation the allocated region to render into
 1394   
      * @see View#paint
 1395   
      */
 1396  0
     public void paint(Graphics g, Shape allocation) {
 1397  0
       Rectangle a = (Rectangle) allocation;
 1398  0
       painter.paint(g, a.x, a.y, a.width, a.height, this);
 1399  0
       super.paint(g, a);
 1400   
     }
 1401   
 
 1402   
     /**
 1403   
      * Change the child views.  This is implemented to
 1404   
      * provide the superclass behavior and invalidate the
 1405   
      * grid so that rows and columns will be recalculated.
 1406   
      */
 1407  0
     public void replace(int offset, int length, View[] views) {
 1408  0
       super.replace(offset, length, views);
 1409  0
       invalidateGrid();
 1410   
     }
 1411   
 
 1412   
     /**
 1413   
      * Calculate the height requirements of the table row.  The
 1414   
      * requirements of multi-row cells are not considered for this
 1415   
      * calculation.  The table itself will check and adjust the row
 1416   
      * requirements for all the rows that have multi-row cells spanning
 1417   
      * them.  This method updates the multi-row flag that indicates that
 1418   
      * this row and rows below need additional consideration.
 1419   
      */
 1420  0
     protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
 1421   
 //        return super.calculateMinorAxisRequirements(axis, r);
 1422  0
       long min = 0;
 1423  0
       long pref = 0;
 1424  0
       long max = 0;
 1425  0
       multiRowCells = false;
 1426  0
       int n = getViewCount();
 1427  0
       for (int i = 0; i < n; i++) {
 1428  0
         View v = getView(i);
 1429  0
         if (getRowsOccupied(v) > 1) {
 1430  0
           multiRowCells = true;
 1431  0
           max = Math.max((int) v.getMaximumSpan(axis), max);
 1432   
         } else {
 1433  0
           min = Math.max((int) v.getMinimumSpan(axis), min);
 1434  0
           pref = Math.max((int) v.getPreferredSpan(axis), pref);
 1435  0
           max = Math.max((int) v.getMaximumSpan(axis), max);
 1436   
         }
 1437   
       }
 1438   
 
 1439  0
       if (r == null) {
 1440  0
         r = new SizeRequirements();
 1441  0
         r.alignment = 0.5f;
 1442   
       }
 1443  0
       r.preferred = (int) pref;
 1444  0
       r.minimum = (int) min;
 1445  0
       r.maximum = (int) max;
 1446  0
       return r;
 1447   
     }
 1448   
 
 1449   
     /**
 1450   
      * Perform layout for the major axis of the box (i.e. the
 1451   
      * axis that it represents).  The results of the layout should
 1452   
      * be placed in the given arrays which represent the allocations
 1453   
      * to the children along the major axis.
 1454   
      * <p>
 1455   
      * This is re-implemented to give each child the span of the column
 1456   
      * width for the table, and to give cells that span multiple columns
 1457   
      * the multi-column span.
 1458   
      *
 1459   
      * @param targetSpan the total span given to the view, which
 1460   
      *  whould be used to layout the children
 1461   
      * @param axis the axis being layed out
 1462   
      * @param offsets the offsets from the origin of the view for
 1463   
      *  each of the child views; this is a return value and is
 1464   
      *  filled in by the implementation of this method
 1465   
      * @param spans the span of each child view; this is a return
 1466   
      *  value and is filled in by the implementation of this method
 1467   
      * @return the offset and span for each child view in the
 1468   
      *  offsets and spans parameters
 1469   
      */
 1470  0
     protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
 1471  0
       int col = 0;
 1472  0
       int ncells = getViewCount();
 1473  0
       for (int cell = 0; cell < ncells; cell++, col++) {
 1474  0
         View cv = getView(cell);
 1475  0
         for (; isFilled(col); col++); // advance to a free column
 1476  0
         int colSpan = getColumnsOccupied(cv);
 1477  0
         spans[cell] = columnSpans[col];
 1478  0
         offsets[cell] = columnOffsets[col];
 1479  0
         if (colSpan > 1) {
 1480  0
           int n = columnSpans.length;
 1481  0
           for (int j = 1; j < colSpan; j++) {
 1482   
             // Because the table may be only partially formed, some
 1483   
             // of the columns may not yet exist.  Therefore we check
 1484   
             // the bounds.
 1485  0
             if ((col+j) < n) {
 1486  0
               spans[cell] += columnSpans[col+j];
 1487   
             }
 1488   
           }
 1489  0
           col += colSpan - 1;
 1490   
         }
 1491   
       }
 1492   
     }
 1493   
 
 1494   
     /**
 1495   
      * Perform layout for the minor axis of the box (i.e. the
 1496   
      * axis orthoginal to the axis that it represents).  The results
 1497   
      * of the layout should be placed in the given arrays which represent
 1498   
      * the allocations to the children along the minor axis.  This
 1499   
      * is called by the superclass whenever the layout needs to be
 1500   
      * updated along the minor axis.
 1501   
      * <p>
 1502   
      * This is implemented to delegate to the superclass, then adjust
 1503   
      * the span for any cell that spans multiple rows.
 1504   
      *
 1505   
      * @param targetSpan the total span given to the view, which
 1506   
      *  whould be used to layout the children
 1507   
      * @param axis the axis being layed out
 1508   
      * @param offsets the offsets from the origin of the view for
 1509   
      *  each of the child views; this is a return value and is
 1510   
      *  filled in by the implementation of this method
 1511   
      * @param spans the span of each child view; this is a return
 1512   
      *  value and is filled in by the implementation of this method
 1513   
      * @return the offset and span for each child view in the
 1514   
      *  offsets and spans parameters
 1515   
      */
 1516  0
     protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
 1517  0
       super.layoutMinorAxis(targetSpan, axis, offsets, spans);
 1518  0
       int col = 0;
 1519  0
       int ncells = getViewCount();
 1520  0
       for (int cell = 0; cell < ncells; cell++, col++) {
 1521  0
         View cv = getView(cell);
 1522  0
         for (; isFilled(col); col++); // advance to a free column
 1523  0
         int colSpan = getColumnsOccupied(cv);
 1524  0
         int rowSpan = getRowsOccupied(cv);
 1525  0
         if (rowSpan > 1) {
 1526   
 
 1527  0
           int row0 = rowIndex;
 1528  0
           int row1 = Math.min(rowIndex + rowSpan - 1, getRowCount()-1);
 1529  0
           spans[cell] = getMultiRowSpan(row0, row1);
 1530   
         }
 1531  0
         if (colSpan > 1) {
 1532  0
           col += colSpan - 1;
 1533   
         }
 1534   
       }
 1535   
     }
 1536   
 
 1537   
     /**
 1538   
      * Determines the resizability of the view along the
 1539   
      * given axis.  A value of 0 or less is not resizable.
 1540   
      *
 1541   
      * @param axis may be either View.X_AXIS or View.Y_AXIS
 1542   
      * @return the resize weight
 1543   
      * @exception IllegalArgumentException for an invalid axis
 1544   
      */
 1545  0
     public int getResizeWeight(int axis) {
 1546  0
       return 1;
 1547   
     }
 1548   
 
 1549   
     /**
 1550   
      * Fetches the child view that represents the given position in
 1551   
      * the model.  This is implemented to walk through the children
 1552   
      * looking for a range that contains the given position.  In this
 1553   
      * view the children do not necessarily have a one to one mapping
 1554   
      * with the child elements.
 1555   
      *
 1556   
      * @param pos  the search position >= 0
 1557   
      * @param a  the allocation to the table on entry, and the
 1558   
      *   allocation of the view containing the position on exit
 1559   
      * @return  the view representing the given position, or
 1560   
      *   null if there isn't one
 1561   
      */
 1562  0
     protected View getViewAtPosition(int pos, Rectangle a) {
 1563  0
       int n = getViewCount();
 1564  0
       for (int i = 0; i < n; i++) {
 1565  0
         View v = getView(i);
 1566  0
         int p0 = v.getStartOffset();
 1567  0
         int p1 = v.getEndOffset();
 1568  0
         if ((pos >= p0) && (pos < p1)) {
 1569   
           // it's in this view.
 1570  0
           if (a != null) {
 1571  0
             childAllocation(i, a);
 1572   
           }
 1573  0
           return v;
 1574   
         }
 1575   
       }
 1576  0
       if (pos == getEndOffset()) {
 1577  0
         View v = getView(n - 1);
 1578  0
         if (a != null) {
 1579  0
           this.childAllocation(n - 1, a);
 1580   
         }
 1581  0
         return v;
 1582   
       }
 1583  0
       return null;
 1584   
     }
 1585   
 
 1586   
     /**
 1587   
      * Update any cached values that come from attributes.
 1588   
      */
 1589  0
     void setPropertiesFromAttributes() {
 1590  0
       StyleSheet sheet = getStyleSheet();
 1591  0
       attr = sheet.getViewAttributes(this);
 1592  0
       painter = sheet.getBoxPainter(attr);
 1593   
     }
 1594   
 
 1595   
     private StyleSheet.BoxPainter painter;
 1596   
     private AttributeSet attr;
 1597   
 
 1598   
     /** columns filled by multi-column or multi-row cells */
 1599   
     BitSet fillColumns;
 1600   
 
 1601   
     /**
 1602   
      * The row index within the overall grid
 1603   
      */
 1604   
     int rowIndex;
 1605   
 
 1606   
     /**
 1607   
      * The view index (for row index to view index conversion).
 1608   
      * This is set by the updateGrid method.
 1609   
      */
 1610   
     int viewIndex;
 1611   
 
 1612   
     /**
 1613   
      * Does this table row have cells that span multiple rows?
 1614   
      */
 1615   
     boolean multiRowCells;
 1616   
 
 1617   
   }
 1618   
 
 1619   
   /**
 1620   
    * Default view of an html table cell.  This needs to be moved
 1621   
    * somewhere else.
 1622   
    */
 1623   
   class CellView extends SHTMLBlockView {
 1624   
 
 1625   
     /**
 1626   
      * Constructs a TableCell for the given element.
 1627   
      *
 1628   
      * @param elem the element that this view is responsible for
 1629   
      */
 1630  0
     public CellView(Element elem) {
 1631  0
       super(elem, Y_AXIS);
 1632   
     }
 1633   
 
 1634   
       /*
 1635   
       public void paint(Graphics g, Shape allocation) {
 1636   
         Rectangle a = allocation.getBounds();
 1637   
     //System.out.println("SHTMLTableView.CellView paint a.x=" + a.x + " a.y=" + a.y + "a.width=" + a.width + " a.height=" + a.height);
 1638   
         super.paint(g, allocation);
 1639   
       }
 1640   
       */
 1641   
 
 1642   
       /**
 1643   
        * Perform layout for the major axis of the box (i.e. the
 1644   
        * axis that it represents).  The results of the layout should
 1645   
        * be placed in the given arrays which represent the allocations
 1646   
        * to the children along the major axis.  This is called by the
 1647   
        * superclass to recalculate the positions of the child views
 1648   
        * when the layout might have changed.
 1649   
        * <p>
 1650   
        * This is implemented to delegate to the superclass to
 1651   
        * tile the children.  If the target span is greater than
 1652   
        * was needed, the offsets are adjusted to align the children
 1653   
        * (i.e. position according to the html valign attribute).
 1654   
        *
 1655   
        * @param targetSpan the total span given to the view, which
 1656   
        *  whould be used to layout the children
 1657   
        * @param axis the axis being layed out
 1658   
        * @param offsets the offsets from the origin of the view for
 1659   
        *  each of the child views; this is a return value and is
 1660   
        *  filled in by the implementation of this method
 1661   
        * @param spans the span of each child view; this is a return
 1662   
        *  value and is filled in by the implementation of this method
 1663   
        * @return the offset and span for each child view in the
 1664   
        *  offsets and spans parameters
 1665   
        */
 1666  0
     protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
 1667  0
       super.layoutMajorAxis(targetSpan, axis, offsets, spans);
 1668   
 
 1669   
       // calculate usage
 1670  0
       int used = 0;
 1671  0
       int n = spans.length;
 1672  0
       for (int i = 0; i < n; i++) {
 1673  0
         used += spans[i];
 1674   
       }
 1675   
 
 1676   
       // calculate adjustments
 1677  0
       int adjust = 0;
 1678  0
       if (used < targetSpan) {
 1679   
         // PENDING(prinz) change to use the css alignment.
 1680  0
         String valign = (String) getElement().getAttributes().getAttribute(
 1681   
             HTML.Attribute.VALIGN);
 1682  0
         if (valign == null) {
 1683  0
           AttributeSet rowAttr = getElement().getParentElement().getAttributes();
 1684  0
           valign = (String) rowAttr.getAttribute(HTML.Attribute.VALIGN);
 1685   
         }
 1686  0
         if ((valign == null) || valign.equals("middle")) {
 1687  0
           adjust = (targetSpan - used) / 2;
 1688  0
         } else if (valign.equals("bottom")) {
 1689  0
           adjust = targetSpan - used;
 1690   
         }
 1691   
       }
 1692   
 
 1693   
       // make adjustments.
 1694  0
       if (adjust != 0) {
 1695  0
         for (int i = 0; i < n; i++) {
 1696  0
           offsets[i] += adjust;
 1697   
         }
 1698   
       }
 1699   
     }
 1700   
 
 1701   
     /**
 1702   
      * Calculate the requirements needed along the major axis.
 1703   
      * This is called by the superclass whenever the requirements
 1704   
      * need to be updated (i.e. a preferenceChanged was messaged
 1705   
      * through this view).
 1706   
      * <p>
 1707   
      * This is implemented to delegate to the superclass, but
 1708   
      * indicate the maximum size is very large (i.e. the cell
 1709   
      * is willing to expend to occupy the full height of the row).
 1710   
      *
 1711   
      * @param axis the axis being layed out.
 1712   
      * @param r the requirements to fill in.  If null, a new one
 1713   
      *  should be allocated.
 1714   
      */
 1715  0
     protected SizeRequirements calculateMajorAxisRequirements(int axis,
 1716   
         SizeRequirements r) {
 1717  0
       SizeRequirements req = super.calculateMajorAxisRequirements(axis, r);
 1718  0
       req.maximum = Integer.MAX_VALUE;
 1719  0
       return req;
 1720   
     }
 1721   
   }
 1722   
 
 1723   
     /* ------------------------------------------------------
 1724   
        start additional items from javax.swing.text.html.CSS
 1725   
        ------------------------------------------------------ */
 1726   
 
 1727   
        /**
 1728   
         * An iterator to express the requirements to use when computing
 1729   
         * layout.
 1730   
         *
 1731   
         * (copied from javax.swing.text.html.CSS)
 1732   
         */
 1733   
   interface LayoutIterator {
 1734   
     void setOffset(int offs);
 1735   
     int getOffset();
 1736   
     void setSpan(int span);
 1737   
     int getSpan();
 1738   
     int getCount();
 1739   
     void setIndex(int i);
 1740   
     float getMinimumSpan(float parentSpan);
 1741   
     float getPreferredSpan(float parentSpan);
 1742   
     float getMaximumSpan(float parentSpan);
 1743   
     //float getAlignment();
 1744   
     float getLeadingCollapseSpan();
 1745   
     float getTrailingCollapseSpan();
 1746   
   }
 1747   
 
 1748   
   /**
 1749   
    * Calculate a tiled layout for the given iterator.
 1750   
    * This should be done collapsing the neighboring
 1751   
    * margins to be a total of the maximum of the two
 1752   
    * neighboring margin areas as described in the CSS spec.
 1753   
    *
 1754   
    * (copied from javax.swing.text.html.CSS)
 1755   
    */
 1756  0
   static void calculateTiledLayout(LayoutIterator iter, int targetSpan) {
 1757   
     /*
 1758   
     * first pass, calculate the preferred sizes, adjustments needed because
 1759   
     * of margin collapsing, and the flexibility to adjust the sizes.
 1760   
      */
 1761  0
     long minimum = 0;
 1762  0
     long maximum = 0;
 1763  0
     long preferred = 0;
 1764  0
     int lastMargin = 0;
 1765  0
     int collapsed = 0;
 1766  0
     int n = iter.getCount();
 1767  0
     for (int i = 0; i < n; i++) {
 1768  0
       iter.setIndex(i);
 1769  0
       int margin0 = lastMargin;
 1770  0
       int margin1 = (int) iter.getLeadingCollapseSpan();
 1771   
       //iter.setOffset(Math.max(margin0, margin1));
 1772  0
       iter.setOffset((int) preferred); // don't know, why, but it works
 1773  0
       if (iter.getOffset() != 0) {
 1774   
         // There is a collapse area
 1775  0
         iter.setOffset(iter.getOffset() - margin0);
 1776  0
         collapsed += iter.getOffset();
 1777   
       }
 1778  0
       iter.setSpan( (int) iter.getPreferredSpan(targetSpan));
 1779  0
       preferred += iter.getSpan();
 1780  0
       minimum += iter.getMinimumSpan(targetSpan);
 1781  0
       maximum += iter.getMaximumSpan(targetSpan);
 1782   
 
 1783  0
       lastMargin = (int) iter.getTrailingCollapseSpan();
 1784   
     }
 1785   
   }
 1786   
 
 1787   
   /**
 1788   
    * Calculate the requirements needed to tile the requirements
 1789   
    * given by the iterator that would be tiled.  The calculation
 1790   
    * takes into consideration margin collapsing.
 1791   
    *
 1792   
    * (copied from javax.swing.text.html.CSS)
 1793   
    */
 1794   
 
 1795  0
   static SizeRequirements calculateTiledRequirements(LayoutIterator iter, SizeRequirements r) {
 1796   
     //System.out.println("claculateTiledRequirements");
 1797  0
     long minimum = 0;
 1798  0
     long maximum = 0;
 1799  0
     long preferred = 0;
 1800  0
     int lastMargin = 0;
 1801  0
     int collapsed = 0;
 1802  0
     int n = iter.getCount();
 1803  0
     for (int i = 0; i < n; i++) {
 1804  0
       iter.setIndex(i);
 1805  0
       int margin0 = lastMargin;
 1806  0
       int margin1 = (int) iter.getLeadingCollapseSpan();
 1807  0
       int offset = Math.max(margin0, margin1);
 1808  0
       if (offset != 0) {
 1809   
         // There is a collapse area
 1810  0
         collapsed += offset - margin0;
 1811   
       }
 1812  0
       preferred += (int) iter.getPreferredSpan(0);
 1813  0
       minimum += iter.getMinimumSpan(0);
 1814  0
       maximum += iter.getMaximumSpan(0);
 1815   
 
 1816  0
       lastMargin = (int) iter.getTrailingCollapseSpan();
 1817   
     }
 1818   
     // adjust for the collapsed area
 1819  0
     minimum -= collapsed;
 1820  0
     preferred -= collapsed;
 1821  0
     maximum -= collapsed;
 1822   
 
 1823   
     // set return value
 1824  0
     if (r == null) {
 1825  0
       r = new SizeRequirements();
 1826   
     }
 1827  0
     r.minimum = (minimum > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)minimum;
 1828  0
     r.preferred = (preferred > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) preferred;
 1829  0
     r.maximum = (maximum > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) maximum;
 1830  0
     return r;
 1831   
   }
 1832   
     /* ------------------------------------------------------
 1833   
        end additional items from javax.swing.text.html.CSS
 1834   
        ------------------------------------------------------ */
 1835   
 }