This patch fixes regressions in javax.swing.text wrt styled text. Most importantly this makes the BeanShell working again (yay), and as it seems it is much snappier now :-)

For the most part this is:
- Rewritten parts of BoxView to not use the SizeRequirements algorithms but instead implement their own. SizeRequirements behaves slightly different than BoxView should and seems rather inefficient for text components. - Rewritten BasicTextUI.damageRange() to use a much simpler approach. It does no special casing for half-lines etc. This just doesn't seems worth the effort. And at last, the RI also doesn't do this (override repaint() in a text component and observe how the RI calls repaint() for different damageRange parameters. It's always one solid rectangle instead of multiple 'optimized' rectangles). - BoxView.paint() is optimized to respect the clip and only paint what really needs painting. Should solve performance problems for larger text components. Also for plain text components in wrapping mode btw. Need to do the same for 'plain' plain text components still.
- Adjusted some alignments and pref/min/max size impls.

I have a set of test programs here that I'll convert into Mauve tests asap.

2006-08-05  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/plaf/basic/BasicTextUI.java
        (damageRange(JTextComponent,int,int)): Call damageRange() with
        correct biases, rather than null.
        (damageRange(JTextComponent,int,int,Bias,Bias)): Rewritten
        to use simpler modelToView() approach without much special
        casing. This seems not worth the effort and actually
        caused problems. Added locking of the document.
        * javax/swing/text/BoxView.java
        (requirementsValid): New field.
        (calculateMajorAxisRequirements): Rewritten without using
        SizeRequirements. The SizeRequirements algorithms are slightly
        different and too inefficient.
        (calculateMinorAxisRequirements): Rewritten without using
        SizeRequirements. The SizeRequirements algorithms are slightly
        different and too inefficient.
        (getAlignment): Simply return the alignment of the cached
        requirements.
        (getMaximumSpan): Add insets.
        (getMinimumSpan): Add insets.
        (getPreferredSpan): Add insets.
        (layoutMajorAxis): Rewritten without using
        SizeRequirements. The SizeRequirements algorithms are slightly
        different and too inefficient.
        (layoutMinorAxis): Rewritten without using
        SizeRequirements. The SizeRequirements algorithms are slightly
        different and too inefficient.
        (modelToView): Call setSize() rather than layout().
        (paint): Check clip for more efficient painting.
        (preferenceChanged): Invalidate requirements here.
        (replace): Invalidate requirements here.
        (updateRequirements): Update requirements only when requirements
        are marked invalid.
        * javax/swing/text/CompositeView.java
        (modelToView): Added some more checks and handling of corner cases.
        * javax/swing/text/FlowView.java
        (calculateMinorAxisRequirements): Set aligment to 0.5 and maximum
        span to Integer.MAX_VALUE. Limit preferredSize to minimumSize.
        * javax/swing/text/IconView.java
        (getAlignment): Implemented to return 1.0 for vertical alignment.
        * javax/swing/text/ParagraphView.java
        (Row.getMaximumSpan): Implemented to let Rows span the whole
        ParagraphView.
        (getAlignment): Fixed horizontal alignment and vertical alignment
        for empty paragraphs to be 0.5.

/Roman
Index: javax/swing/plaf/basic/BasicTextUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTextUI.java,v
retrieving revision 1.87
diff -u -1 -2 -r1.87 BasicTextUI.java
--- javax/swing/plaf/basic/BasicTextUI.java	21 Jun 2006 12:57:05 -0000	1.87
+++ javax/swing/plaf/basic/BasicTextUI.java	5 Aug 2006 12:12:01 -0000
@@ -74,25 +74,24 @@
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Caret;
 import javax.swing.text.DefaultCaret;
 import javax.swing.text.DefaultEditorKit;
 import javax.swing.text.DefaultHighlighter;
 import javax.swing.text.Document;
 import javax.swing.text.EditorKit;
 import javax.swing.text.Element;
 import javax.swing.text.Highlighter;
 import javax.swing.text.JTextComponent;
 import javax.swing.text.Keymap;
 import javax.swing.text.Position;
-import javax.swing.text.Utilities;
 import javax.swing.text.View;
 import javax.swing.text.ViewFactory;
 
 /**
  * The abstract base class from which the UI classes for Swings text
  * components are derived. This provides most of the functionality for
  * the UI classes.
  *
  * @author original author unknown
  * @author Roman Kennke ([EMAIL PROTECTED])
  */
 public abstract class BasicTextUI extends TextUI
@@ -1033,144 +1032,74 @@
   /**
    * Marks the specified range inside the text component's model as
    * damaged and queues a repaint request.
    *
    * @param t the text component
    * @param p0 the start location inside the document model of the range that
    *        is damaged
    * @param p1 the end location inside the document model of the range that
    *        is damaged
    */
   public void damageRange(JTextComponent t, int p0, int p1)
   {
-    damageRange(t, p0, p1, null, null);
+    damageRange(t, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
   }
 
   /**
    * Marks the specified range inside the text component's model as
    * damaged and queues a repaint request. This variant of this method
    * allows a [EMAIL PROTECTED] Position.Bias} object to be specified for the start
    * and end location of the range.
    *
    * @param t the text component
    * @param p0 the start location inside the document model of the range that
    *        is damaged
    * @param p1 the end location inside the document model of the range that
    *        is damaged
    * @param firstBias the bias for the start location
    * @param secondBias the bias for the end location
    */
   public void damageRange(JTextComponent t, int p0, int p1,
                           Position.Bias firstBias, Position.Bias secondBias)
   {
-    // Do nothing if the component cannot be properly displayed.
-    if (t.getWidth() == 0 || t.getHeight() == 0)
-      return;
-    
-    try
+    Rectangle alloc = getVisibleEditorRect();
+    if (alloc != null)
       {
-        // Limit p0 and p1 to sane values to prevent unfriendly
-        // BadLocationExceptions. This makes it possible for the highlighter
-        // to send us illegal values which can happen when a large number
-        // of selected characters are removed (eg. by pressing delete
-        // or backspace).
-        // The reference implementation does not throw an exception, too.
-        p0 = Math.min(p0, t.getDocument().getLength());
-        p1 = Math.min(p1, t.getDocument().getLength());
-
-        Rectangle l1 = modelToView(t, p0, firstBias);
-        Rectangle l2 = modelToView(t, p1, secondBias);
-        if (l1 == null || l2 == null)
+        Document doc = t.getDocument();
+
+        // Acquire lock here to avoid structural changes in between.
+        if (doc instanceof AbstractDocument)
+          ((AbstractDocument) doc).readLock();
+        try
           {
-            // Unable to determine the start or end of the selection.
-            t.repaint();
+            rootView.setSize(alloc.width, alloc.height);
+            Shape damage = rootView.modelToView(p0, firstBias, p1, secondBias,
+                                                alloc);
+            Rectangle r = damage instanceof Rectangle ? (Rectangle) damage
+                                                      : damage.getBounds();
+            textComponent.repaint(r.x, r.y, r.width, r.height);
           }
-        else if (l1.y == l2.y)
+        catch (BadLocationException ex)
           {
-            SwingUtilities.computeUnion(l2.x, l2.y, l2.width, l2.height, l1);
-            t.repaint(l1);
+            // Lets ignore this as it causes no serious problems.
+            // For debugging, comment this out.
+            // ex.printStackTrace();
           }
-        else
+        finally
           {
-            // The two rectangles lie on different lines and we need a
-            // different algorithm to calculate the damaged area:
-            // 1. The line of p0 is damaged from the position of p0
-            // to the right border.
-            // 2. All lines between the ones where p0 and p1 lie on
-            // are completely damaged. Use the allocation area to find
-            // out the bounds.
-            // 3. The final line is damaged from the left bound to the
-            // position of p1.
-            Insets insets = t.getInsets();
-
-            // Damage first line until the end.
-            l1.width = insets.right + t.getWidth() - l1.x;
-            t.repaint(l1);
-            
-            // Note: Utilities.getPositionBelow() may return the offset
-            // that was put in. In that case there is no next line and
-            // we should stop searching for one.
-            
-            int posBelow = Utilities.getPositionBelow(t, p0, l1.x);
-            int p1RowStart = Utilities.getRowStart(t, p1);
-            
-            if (posBelow != -1
-                && posBelow != p0
-                && Utilities.getRowStart(t, posBelow) != p1RowStart)
-              {
-                // Take the rectangle of the offset we just found and grow it
-                // to the maximum width. Retain y because this is our start
-                // height.
-                Rectangle grow = modelToView(t, posBelow);
-                grow.x = insets.left;
-                grow.width = t.getWidth() + insets.right;
-                
-                // Find further lines which have to be damaged completely.
-                int nextPosBelow = posBelow;
-                while (nextPosBelow != -1
-                       && posBelow != nextPosBelow
-                       && Utilities.getRowStart(t, nextPosBelow) != p1RowStart)
-                  {
-                    posBelow = nextPosBelow;
-                    nextPosBelow = Utilities.getPositionBelow(t, posBelow, 
-                                                              l1.x);
-                    
-                    if (posBelow == nextPosBelow)
-                      break;
-                  }
-                // Now posBelow is an offset on the last line which has to be 
-                // damaged completely. (newPosBelow is on the same line as p1)
-                 
-                // Retrieve the rectangle of posBelow and use its y and height
-                // value to calculate the final height of the multiple line
-                // spanning rectangle.
-                Rectangle end = modelToView(t, posBelow);
-                grow.height = end.y + end.height - grow.y;
-                
-                // Mark that area as damage.
-                t.repaint(grow);
-              }
-            
-            // Damage last line from its beginning to the position of p1.
-            l2.width += l2.x;
-            l2.x = insets.left;
-            t.repaint(l2);
+            // Release lock.
+            if (doc instanceof AbstractDocument)
+              ((AbstractDocument) doc).readUnlock();
           }
       }
-    catch (BadLocationException ex)
-      {
-        AssertionError err = new AssertionError("Unexpected bad location");
-        err.initCause(ex);
-        throw err;
-      }
   }
 
   /**
    * Returns the [EMAIL PROTECTED] EditorKit} used for the text component that is managed
    * by this UI.
    *
    * @param t the text component
    *
    * @return the [EMAIL PROTECTED] EditorKit} used for the text component that is managed
    *         by this UI
    */
   public EditorKit getEditorKit(JTextComponent t)
Index: javax/swing/text/BoxView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/BoxView.java,v
retrieving revision 1.19
diff -u -1 -2 -r1.19 BoxView.java
--- javax/swing/text/BoxView.java	1 Apr 2006 15:22:07 -0000	1.19
+++ javax/swing/text/BoxView.java	5 Aug 2006 12:12:01 -0000
@@ -58,24 +58,29 @@
 
   /**
    * The axis along which this <code>BoxView</code> is laid out.
    */
   private int myAxis;
 
   /**
    * Indicates if the layout is valid along X_AXIS or Y_AXIS.
    */
   private boolean[] layoutValid = new boolean[2];
 
   /**
+   * Indicates if the requirements for an axis are valid.
+   */
+  private boolean[] requirementsValid = new boolean[2];
+
+  /**
    * The spans along the X_AXIS and Y_AXIS.
    */
   private int[][] spans = new int[2][];
 
   /**
    * The offsets of the children along the X_AXIS and Y_AXIS.
    */
   private int[][] offsets = new int[2][];
 
   /**
    * The size requirements along the X_AXIS and Y_AXIS.
    */
@@ -256,101 +261,124 @@
     // The offsetsY cache.
     int[] newOffsetsY = new int[oldSize - length + numViews];
     System.arraycopy(offsets[Y_AXIS], 0, newOffsetsY, 0, offset);
     System.arraycopy(offsets[Y_AXIS], offset + length, newOffsetsY,
                      offset + numViews,
                      oldSize - (offset + length));
     offsets[Y_AXIS] = newOffsetsY;
 
     // Actually perform the replace.
     super.replace(offset, length, views);
 
     // Invalidate layout information.
-    layoutChanged(X_AXIS);
-    layoutChanged(Y_AXIS);
+    layoutValid[X_AXIS] = false;
+    requirementsValid[X_AXIS] = false;
+    layoutValid[Y_AXIS] = false;
+    requirementsValid[Y_AXIS] = false;
   }
 
   /**
    * Renders the <code>Element</code> that is associated with this
    * <code>View</code>.
    *
    * @param g the <code>Graphics</code> context to render to
    * @param a the allocated region for the <code>Element</code>
    */
   public void paint(Graphics g, Shape a)
   {
-    Rectangle inside = getInsideAllocation(a);
-    // TODO: Used for debugging.
-    //g.drawRect(inside.x, inside.y, inside.width, inside.height);
+    Rectangle alloc;
+    if (a instanceof Rectangle)
+      alloc = (Rectangle) a;
+    else
+      alloc = a.getBounds();
+
+    int x = alloc.x + getLeftInset();
+    int y = alloc.y + getTopInset();
 
-    Rectangle copy = new Rectangle(inside);
+    Rectangle clip = g.getClipBounds();
+    Rectangle tmp = new Rectangle();
     int count = getViewCount();
     for (int i = 0; i < count; ++i)
       {
-        copy.setBounds(inside);
-        childAllocation(i, copy);
-        if (!copy.isEmpty()
-            && g.hitClip(copy.x, copy.y, copy.width, copy.height))
-          paintChild(g, copy, i);
+        tmp.x = x + getOffset(X_AXIS, i);
+        tmp.y = y + getOffset(Y_AXIS, i);
+        tmp.width = getSpan(X_AXIS, i);
+        tmp.height = getSpan(Y_AXIS, i);
+        if (tmp.intersects(clip))
+          paintChild(g, tmp, i);
       }
   }
 
   /**
    * Returns the preferred span of the content managed by this
    * <code>View</code> along the specified <code>axis</code>.
    *
    * @param axis the axis
    *
    * @return the preferred span of this <code>View</code>.
    */
   public float getPreferredSpan(int axis)
   {
     updateRequirements(axis);
-    return requirements[axis].preferred;
+    // Add margin.
+    float margin;
+    if (axis == X_AXIS)
+      margin = getLeftInset() + getRightInset();
+    else
+      margin = getTopInset() + getBottomInset();
+    return requirements[axis].preferred + margin;
   }
 
   /**
    * Returns the maximum span of this view along the specified axis.
    * This returns <code>Integer.MAX_VALUE</code> for the minor axis
    * and the preferred span for the major axis.
    *
    * @param axis the axis
    *
    * @return the maximum span of this view along the specified axis
    */
   public float getMaximumSpan(int axis)
   {
-    float max;
-    if (axis == myAxis)
-      max = getPreferredSpan(axis);
+    updateRequirements(axis);
+    // Add margin.
+    float margin;
+    if (axis == X_AXIS)
+      margin = getLeftInset() + getRightInset();
     else
-      max = Integer.MAX_VALUE;
-    return max;
+      margin = getTopInset() + getBottomInset();
+    return requirements[axis].maximum + margin;
   }
 
   /**
    * Returns the minimum span of this view along the specified axis.
    * This calculates the minimum span using
    * [EMAIL PROTECTED] #calculateMajorAxisRequirements} or
    * [EMAIL PROTECTED] #calculateMinorAxisRequirements} (depending on the axis) and
    * returns the resulting minimum span.
    *
    * @param axis the axis
    *
    * @return the minimum span of this view along the specified axis
    */
   public float getMinimumSpan(int axis)
   {
     updateRequirements(axis);
-    return requirements[axis].minimum;
+    // Add margin.
+    float margin;
+    if (axis == X_AXIS)
+      margin = getLeftInset() + getRightInset();
+    else
+      margin = getTopInset() + getBottomInset();
+    return requirements[axis].minimum + margin;
   }
 
   /**
    * This method is obsolete and no longer in use. It is replaced by
    * [EMAIL PROTECTED] #calculateMajorAxisRequirements(int, SizeRequirements)} and
    * [EMAIL PROTECTED] #calculateMinorAxisRequirements(int, SizeRequirements)}.
    *
    * @param axis the axis that is examined
    * @param sr the <code>SizeRequirements</code> object to hold the result,
    *        if <code>null</code>, a new one is created
    *
    * @return the size requirements for this <code>BoxView</code> along
@@ -426,107 +454,82 @@
    * its major axis, that is the axis specified in the constructor.
    *
    * @param axis the axis that is examined
    * @param sr the <code>SizeRequirements</code> object to hold the result,
    *        if <code>null</code>, a new one is created
    *
    * @return the size requirements for this <code>BoxView</code> along
    *         the specified axis
    */
   protected SizeRequirements calculateMajorAxisRequirements(int axis,
                                                            SizeRequirements sr)
   {
-    updateChildRequirements(axis);
+    SizeRequirements res = sr;
+    if (res == null)
+      res = new SizeRequirements();
 
-    SizeRequirements result = sr;
-    if (result == null)
-      result = new SizeRequirements();
-
-    long minimum = 0;
-    long preferred = 0;
-    long maximum = 0;
-    for (int i = 0; i < children.length; i++)
-      {
-        minimum += childReqs[axis][i].minimum;
-        preferred += childReqs[axis][i].preferred;
-        maximum += childReqs[axis][i].maximum;
-      }
-    // Overflow check.
-    if (minimum > Integer.MAX_VALUE)
-      minimum = Integer.MAX_VALUE;
-    if (preferred > Integer.MAX_VALUE)
-      preferred = Integer.MAX_VALUE;
-    if (maximum > Integer.MAX_VALUE)
-      maximum = Integer.MAX_VALUE;
-
-    result.minimum = (int) minimum;
-    result.preferred = (int) preferred;
-    result.maximum = (int) maximum;
-    result.alignment = 0.5F;
-    return result;
+    float min = 0;
+    float pref = 0;
+    float max = 0;
+
+    int n = getViewCount();
+    for (int i = 0; i < n; i++)
+      {
+        View child = getView(i);
+        min += child.getMinimumSpan(axis);
+        pref = child.getPreferredSpan(axis);
+        max = child.getMaximumSpan(axis);
+      }
+
+    res.minimum = (int) min;
+    res.preferred = (int) pref;
+    res.maximum = (int) max;
+    res.alignment = 0.5F;
+
+    return res;
   }
 
   /**
    * Calculates the size requirements of this <code>BoxView</code> along
    * its minor axis, that is the axis opposite to the axis specified in the
    * constructor.
    *
    * @param axis the axis that is examined
    * @param sr the <code>SizeRequirements</code> object to hold the result,
    *        if <code>null</code>, a new one is created
    *
    * @return the size requirements for this <code>BoxView</code> along
    *         the specified axis
    */
   protected SizeRequirements calculateMinorAxisRequirements(int axis,
                                                             SizeRequirements sr)
   {
-    updateChildRequirements(axis);
-
     SizeRequirements res = sr;
     if (res == null)
       res = new SizeRequirements();
 
-    float minLeft = 0;
-    float minRight = 0;
-    float prefLeft = 0;
-    float prefRight = 0;
-    float maxLeft = 0;
-    float maxRight = 0;
-    for (int i = 0; i < childReqs[axis].length; i++)
-      {
-        float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment;
-        float myMinRight = childReqs[axis][i].minimum - myMinLeft;
-        minLeft = Math.max(myMinLeft, minLeft);
-        minRight = Math.max(myMinRight, minRight);
-        float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment;
-        float myPrefRight = childReqs[axis][i].preferred - myPrefLeft;
-        prefLeft = Math.max(myPrefLeft, prefLeft);
-        prefRight = Math.max(myPrefRight, prefRight);
-        float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment;
-        float myMaxRight = childReqs[axis][i].maximum - myMaxLeft;
-        maxLeft = Math.max(myMaxLeft, maxLeft);
-        maxRight = Math.max(myMaxRight, maxRight);
+    res.minimum = 0;
+    res.preferred = 0;
+    res.maximum = 0;
+    res.alignment = 0.5F;
+    int n = getViewCount();
+    for (int i = 0; i < n; i++)
+      {
+        View child = getView(i);
+        res.minimum = Math.max((int) child.getMinimumSpan(axis), res.minimum);
+        res.preferred = Math.max((int) child.getPreferredSpan(axis),
+                                 res.preferred);
+        res.maximum = Math.max((int) child.getMaximumSpan(axis), res.maximum);
       }
-    int minSize = (int) (minLeft + minRight);
-    int prefSize = (int) (prefLeft + prefRight);
-    int maxSize = (int) (maxLeft + maxRight);
-    float align = prefLeft / (prefRight + prefLeft);
-    if (Float.isNaN(align))
-      align = 0;
 
-    res.alignment = align;
-    res.maximum = maxSize;
-    res.preferred = prefSize;
-    res.minimum = minSize;
     return res;
   }
   
 
   /**
    * Returns <code>true</code> if the specified point lies before the
    * given <code>Rectangle</code>, <code>false</code> otherwise.
    *
    * &quot;Before&quot; is typically defined as being to the left or above.
    *
    * @param x the X coordinate of the point
    * @param y the Y coordinate of the point
@@ -688,55 +691,114 @@
   /**
    * Performs the layout along the major axis of a <code>BoxView</code>.
    *
    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
    *        to layout the children
    * @param axis the axis along which the layout is performed
    * @param offsets the array that holds the offsets of the children on exit
    * @param spans the array that holds the spans of the children on exit
    */
   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
                                  int[] spans)
   {
-    updateChildRequirements(axis);
-    updateRequirements(axis);
+    // Set the spans to the preferred sizes. Determine the space
+    // that we have to adjust the sizes afterwards.
+    long sumPref = 0;
+    int n = getViewCount();
+    for (int i = 0; i < n; i++)
+      {
+        View child = getView(i);
+        spans[i] = (int) child.getPreferredSpan(axis);
+        sumPref = spans[i];
+      }
+
+    // Try to adjust the spans so that we fill the targetSpan.
+    long diff = targetSpan - sumPref;
+    float factor = 0.0F;
+    int[] diffs = null;
+    if (diff != 0)
+      {
+        long total = 0;
+        diffs = new int[n];
+        for (int i = 0; i < n; i++)
+          {
+            View child = getView(i);
+            int span;
+            if (diff < 0)
+              {
+                span = (int) child.getMinimumSpan(axis);
+                diffs[i] = spans[i] - span;
+              }
+            else
+              {
+                span = (int) child.getMaximumSpan(axis);
+                diffs[i] = span - spans[i];
+              }
+            total += span;
+          }
 
-    // Calculate the spans and offsets using the SizeRequirements uility
-    // methods.
-    SizeRequirements.calculateTiledPositions(targetSpan, requirements[axis],
-                                             childReqs[axis],
-                                             offsets, spans);
+        float maxAdjust = Math.abs(total - sumPref);
+        factor = diff / maxAdjust;
+        factor = Math.min(factor, 1.0F);
+        factor = Math.max(factor, -1.0F);
+      }
 
+    // Actually perform adjustments.
+    int totalOffs = 0;
+    for (int i = 0; i < n; i++)
+      {
+        offsets[i] = totalOffs;
+        if (diff != 0)
+          {
+            float adjust = factor * diffs[i];
+            spans[i] += Math.round(adjust);
+          }
+        // Avoid overflow here.
+        totalOffs = (int) Math.min((long) totalOffs + (long) spans[i],
+                                    Integer.MAX_VALUE);
+      }
   }
 
   /**
    * Performs the layout along the minor axis of a <code>BoxView</code>.
    *
    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
    *        to layout the children
    * @param axis the axis along which the layout is performed
    * @param offsets the array that holds the offsets of the children on exit
    * @param spans the array that holds the spans of the children on exit
    */
   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
                                  int[] spans)
   {
-    updateChildRequirements(axis);
-    updateRequirements(axis);
-
-    // Calculate the spans and offsets using the SizeRequirements uility
-    // methods.
-    SizeRequirements.calculateAlignedPositions(targetSpan, requirements[axis],
-                                               childReqs[axis], offsets,
-                                               spans);
+    int count = getViewCount();
+    for (int i = 0; i < count; i++)
+      {
+        View child = getView(i);
+        int max = (int) child.getMaximumSpan(axis);
+        if (max < targetSpan)
+          {System.err.println("align: " + child);
+            // Align child when it can't be made as wide as the target span.
+            float align = child.getAlignment(axis);
+            offsets[i] = (int) ((targetSpan - max) * align);
+            spans[i] = max;
+          }
+        else
+          {
+            // Expand child to target width if possible.
+            int min = (int) child.getMinimumSpan(axis);
+            offsets[i] = 0;
+            spans[i] = Math.max(min, targetSpan);
+          }
+      }
   }
 
   /**
    * Returns <code>true</code> if the cached allocations for the children
    * are still valid, <code>false</code> otherwise.
    *
    * @return <code>true</code> if the cached allocations for the children
    *         are still valid, <code>false</code> otherwise
    */
   protected boolean isAllocationValid()
   {
     return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
@@ -813,65 +875,64 @@
   /**
    * Returns the alignment for this box view for the specified axis. The
    * axis that is tiled (the major axis) will be requested to be aligned
    * centered (0.5F). The minor axis alignment depends on the child view's
    * total alignment.
    *
    * @param axis the axis which is examined
    *
    * @return the alignment for this box view for the specified axis
    */
   public float getAlignment(int axis)
   {
-    float align;
-    if (axis == myAxis)
-      align = 0.5F;
-    else
-      {
-        updateRequirements(axis);
-        align = requirements[axis].alignment;
-      }
-    return align;
+     updateRequirements(axis);
+     return requirements[axis].alignment;
   }
   
   /**
    * Called by a child View when its preferred span has changed.
    * 
    * @param width indicates that the preferred width of the child changed.
    * @param height indicates that the preferred height of the child changed.
    * @param child the child View. 
    */
   public void preferenceChanged(View child, boolean width, boolean height)
   {
     if (width)
-      layoutValid[X_AXIS] = false;
+      {
+        layoutValid[X_AXIS] = false;
+        requirementsValid[X_AXIS] = false;
+      }
     if (height)
-      layoutValid[Y_AXIS] = false;
+      {
+        layoutValid[Y_AXIS] = false;
+        requirementsValid[Y_AXIS] = false;
+      }
     super.preferenceChanged(child, width, height);
   }
   
   /**
    * Maps the document model position <code>pos</code> to a Shape
    * in the view coordinate space.  This method overrides CompositeView's
    * method to make sure the children are allocated properly before
    * calling the super's behaviour.
    */
   public Shape modelToView(int pos, Shape a, Position.Bias bias)
       throws BadLocationException
   {
     // Make sure everything is allocated properly and then call super
     if (! isAllocationValid())
       {
         Rectangle bounds = a.getBounds();
-        layout(bounds.width, bounds.height);
+        setSize(bounds.width, bounds.height);
       }
     return super.modelToView(pos, a, bias);
   }
 
   /**
    * Returns the resize weight of this view. A value of <code>0</code> or less
    * means this view is not resizeable. Positive values make the view
    * resizeable. This implementation returns <code>0</code> for the major
    * axis and <code>1</code> for the minor axis of this box view.
    *
    * @param axis the axis
    *
@@ -954,23 +1015,24 @@
       }
   }
 
   /**
    * Updates the view's cached requirements along the specified axis if
    * necessary. The requirements are only updated if the layout for the
    * specified axis is marked as invalid.
    *
    * @param axis the axis
    */
   private void updateRequirements(int axis)
   {
-    if (! layoutValid[axis])
+    if (! requirementsValid[axis])
       {
         if (axis == myAxis)
           requirements[axis] = calculateMajorAxisRequirements(axis,
                                                            requirements[axis]);
         else
           requirements[axis] = calculateMinorAxisRequirements(axis,
                                                            requirements[axis]);
+        requirementsValid[axis] = true;
       }
   }
 }
Index: javax/swing/text/CompositeView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/CompositeView.java,v
retrieving revision 1.18
diff -u -1 -2 -r1.18 CompositeView.java
--- javax/swing/text/CompositeView.java	28 Apr 2006 10:26:31 -0000	1.18
+++ javax/swing/text/CompositeView.java	5 Aug 2006 12:12:02 -0000
@@ -208,43 +208,61 @@
    *        <code>Position.Bias.Forward</code>
    *
    * @return a rectangle that gives the location of the document position
    *         inside the view coordinate space
    *
    * @throws BadLocationException if <code>pos</code> is invalid
    * @throws IllegalArgumentException if b is not one of the above listed
    *         valid values
    */
   public Shape modelToView(int pos, Shape a, Position.Bias bias)
     throws BadLocationException
   {
-    int childIndex = getViewIndex(pos, bias);
-    if (childIndex == -1)
-      throw new BadLocationException("Position " + pos + " is not represented by view.", pos);
-      
-    Shape ret = null;
-
-    View child = getView(childIndex);
-    Shape childAlloc = getChildAllocation(childIndex, a);
-    
-    if (childAlloc == null)
-      ret = createDefaultLocation(a, bias);
-    
-    Shape result = child.modelToView(pos, childAlloc, bias);
-
-    if (result != null)
-      ret = result;
-    else
-      ret =  createDefaultLocation(a, bias);
+    boolean backward = bias == Position.Bias.Backward;
+    int testpos = backward ? Math.max(0, pos - 1) : pos;
 
+    Shape ret = null;
+    if (!backward || testpos >= getStartOffset())
+      {
+        int childIndex = getViewIndexAtPosition(testpos);
+        if (childIndex != -1 && childIndex < getViewCount())
+          {
+            View child = getView(childIndex);
+            if (child != null && testpos >= child.getStartOffset()
+                && testpos < child.getEndOffset())
+              {
+                Shape childAlloc = getChildAllocation(childIndex, a);
+                if (childAlloc != null)
+                  {
+                    ret = child.modelToView(pos, childAlloc, bias);
+                    // Handle corner case.
+                    if (ret == null && child.getEndOffset() == pos)
+                      {
+                        childIndex++;
+                        if (childIndex < getViewCount())
+                          {
+                            child = getView(childIndex);
+                            childAlloc = getChildAllocation(childIndex, a);
+                            ret = child.modelToView(pos, childAlloc, bias);
+                          }
+                      }
+                  }
+              }
+          }
+        else
+          {
+            throw new BadLocationException("Position " + pos
+                                           + " is not represented by view.", pos);
+          }    
+      }
     return ret;
   }
 
   /**
    * A helper method for [EMAIL PROTECTED] #modelToView(int, Position.Bias, int,
    * Position.Bias, Shape)}. This creates a default location when there is
    * no child view that can take responsibility for mapping the position to
    * view coordinates. Depending on the specified bias this will be the
    * left or right edge of this view's allocation.
    *
    * @param a the allocation for this view
    * @param bias the bias
Index: javax/swing/text/FlowView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/FlowView.java,v
retrieving revision 1.13
diff -u -1 -2 -r1.13 FlowView.java
--- javax/swing/text/FlowView.java	8 Jul 2006 19:46:44 -0000	1.13
+++ javax/swing/text/FlowView.java	5 Aug 2006 12:12:02 -0000
@@ -588,21 +588,23 @@
    * This is overridden and forwards the request to the logical view.
    *
    * @param axis the axis that is examined
    * @param r the <code>SizeRequirements</code> object to hold the result,
    *        if <code>null</code>, a new one is created
    *
    * @return the size requirements for this <code>BoxView</code> along
    *         the specified axis
    */
   protected SizeRequirements calculateMinorAxisRequirements(int axis,
                                                             SizeRequirements r)
   {
-    // We need to call super here so that the alignment is properly
-    // calculated.
-    SizeRequirements res = super.calculateMinorAxisRequirements(axis, r);
+    SizeRequirements res = r;
+    if (res == null)
+      res = new SizeRequirements();
     res.minimum = (int) layoutPool.getMinimumSpan(axis);
-    res.preferred = (int) layoutPool.getPreferredSpan(axis);
-    res.maximum = (int) layoutPool.getMaximumSpan(axis);
+    res.preferred = Math.max(res.minimum,
+                             (int) layoutPool.getMinimumSpan(axis));
+    res.maximum = Integer.MAX_VALUE;
+    res.alignment = 0.5F;
     return res;
   }
 }
Index: javax/swing/text/IconView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/IconView.java,v
retrieving revision 1.8
diff -u -1 -2 -r1.8 IconView.java
--- javax/swing/text/IconView.java	9 Feb 2006 23:13:11 -0000	1.8
+++ javax/swing/text/IconView.java	5 Aug 2006 12:12:02 -0000
@@ -35,25 +35,24 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing.text;
 
 import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.Shape;
 
 import javax.swing.Icon;
 import javax.swing.JTextPane;
-import javax.swing.SwingConstants;
 
 /**
  * A View that can render an icon. This view is created by the
  * [EMAIL PROTECTED] StyledEditorKit}'s view factory for all elements that have name
  * [EMAIL PROTECTED] StyleConstants#IconElementName}. This is usually created by
  * inserting an icon into <code>JTextPane</code> using
  * [EMAIL PROTECTED] JTextPane#insertIcon(Icon)}
  *
  * The icon is determined using the attribute
  * [EMAIL PROTECTED] StyleConstants#IconAttribute}, which's value must be an [EMAIL PROTECTED] Icon}.
  *
  * @author Roman Kennke ([EMAIL PROTECTED])
@@ -147,13 +146,30 @@
    * @return the position in the document that corresponds to the screen
    *         coordinates <code>x, y</code>
    */
   public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
   {
     // The element should only have one character position and it is clear
     // that this position is the position that best matches the given screen
     // coordinates, simply because this view has only this one position.
     Element el = getElement();
     return el.getStartOffset();
   }
 
+  /**
+   * Returns the alignment for this view. This will be 1.0 for the Y_AXIS,
+   * and the super behaviour for the X_AXIS.
+   *
+   * @param axis the axis for which to calculate the alignment
+   *
+   * @return the alignment
+   */
+  public float getAlignment(int axis)
+  {
+    float align;
+    if (axis == Y_AXIS)
+      align = 1.0F;
+    else
+      align = super.getAlignment(axis);
+    return align;
+  }
 }
Index: javax/swing/text/ParagraphView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/ParagraphView.java,v
retrieving revision 1.7
diff -u -1 -2 -r1.7 ParagraphView.java
--- javax/swing/text/ParagraphView.java	21 Feb 2006 13:56:15 -0000	1.7
+++ javax/swing/text/ParagraphView.java	5 Aug 2006 12:12:03 -0000
@@ -65,24 +65,37 @@
     }
 
     public float getAlignment(int axis)
     {
       float align;
       if (axis == X_AXIS)
         align = 0.0F; // TODO: Implement according to justification
       else
         align = super.getAlignment(axis);
       return align;
     }
 
+    /**
+     * Allows rows to span the whole parent view.
+     */
+    public float getMaximumSpan(int axis)
+    {
+      float max;
+      if (axis == X_AXIS)
+        max = Float.MAX_VALUE;
+      else
+        max = super.getMaximumSpan(axis);
+      return max;
+    }
+
     protected void loadChildren(ViewFactory vf)
     {
       // Do nothing here. The children are added while layouting.
     }
   }
 
   /**
    * The indentation of the first line of the paragraph.
    */
   protected int firstLineIndent;
 
   /**
@@ -131,33 +144,33 @@
    * For the X_AXIS the paragraph view will be aligned at it's left edge
    * (0.0F). For the Y_AXIS the paragraph view will be aligned at the
    * center of it's first row.
    *
    * @param axis the axis which is examined
    *
    * @return the alignment for this paragraph view for the specified axis
    */
   public float getAlignment(int axis)
   {
     float align;
     if (axis == X_AXIS)
-      align = super.getAlignment(axis);
+      align = 0.5F;
     else if (getViewCount() > 0)
       {
         float prefHeight = getPreferredSpan(Y_AXIS);
         float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS);
         align = (firstRowHeight / 2.F) / prefHeight;
       }
     else
-      align = 0.0F;
+      align = 0.5F;
     return align;
   }
 
   /**
    * Receives notification when some attributes of the displayed element
    * changes. This triggers a refresh of the cached attributes of this
    * paragraph.
    *
    * @param ev the document event
    * @param a the allocation of this view
    * @param fv the view factory to use for creating new child views
    */

Reply via email to