This implements the BoxView baseline layout stuff correctly. This is
pretty straightforward, but different from the normal BoxView layout.
The baseline layout is needed by the Row view (the subclass of Paragraph
view, that renders single rows), as this naturally renders the glyphs on
the baseline.
Also, this fixes some other minor issues that are necessary for the HTML
view, especially the rendering and layout for subscript/superscript and
the colors for the glyphs.
2006-08-24 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/text/BoxView.java
(childReqs): Removed obsolete field.
(baselineLayout): Reimplemented for correct baseline layout.
(baselineRequirements): Reimplemented for correct baseline
layout.
(updateChildRequirements): Removed obsolete method.
* javax/swing/text/GlyphView.java
(DefaultGlyphPainter.getSpan): Removed unused statement.
(DefaultGlyphPainter.paint): Dont paint subscript/superscript
specially. The subscript/superscript layout is performed
via the alignment, the font is supplied by the StyleContext.
(breakView): Removed unused statements.
(getAlignment): Adjust alignment according to the
superscript/subscript setting.
(getFont): Reimplemented to fetch the font from the style
context, or from the document if the stylecontext is not
available.
(getPreferredSpan): Adjust span for superscript. Use switch
instead of if-else.
* javax/swing/text/LabelView.java
(setPropertiesFromAttributes): Fetch background and foreground
from document / style context.
(isSubscript): Resync properties if needed.
* javax/swing/text/ParagraphView.java
(Row.calculateMinorAxisRequirements): Overridden to perform
a baseline layout.
(Row.layoutMinorAxis): Overridden to perform a baseline layout.
/Roman
Index: javax/swing/text/BoxView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/BoxView.java,v
retrieving revision 1.21
diff -u -1 -2 -r1.21 BoxView.java
--- javax/swing/text/BoxView.java 10 Aug 2006 22:02:21 -0000 1.21
+++ javax/swing/text/BoxView.java 25 Aug 2006 11:19:18 -0000
@@ -83,29 +83,24 @@
/**
* The size requirements along the X_AXIS and Y_AXIS.
*/
private SizeRequirements[] requirements = new SizeRequirements[2];
/**
* The current span along X_AXIS or Y_AXIS.
*/
private int[] span = new int[2];
/**
- * The SizeRequirements of the child views along the X_AXIS and Y_AXIS.
- */
- private SizeRequirements[][] childReqs = new SizeRequirements[2][];
-
- /**
* Creates a new <code>BoxView</code> for the given
* <code>Element</code> and axis. Valid values for the axis are
* [EMAIL PROTECTED] View#X_AXIS} and [EMAIL PROTECTED] View#Y_AXIS}.
*
* @param element the element that is rendered by this BoxView
* @param axis the axis along which the box is laid out
*/
public BoxView(Element element, int axis)
{
super(element);
myAxis = axis;
layoutValid[0] = false;
@@ -364,98 +359,165 @@
{
updateRequirements(axis);
// 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)}.
+ * Calculates size requirements for a baseline layout. This is not
+ * used by the BoxView itself, but by subclasses that wish to perform
+ * a baseline layout, like the FlowView's rows.
*
* @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 baselineRequirements(int axis,
SizeRequirements sr)
{
- updateChildRequirements(axis);
-
- SizeRequirements res = sr;
- if (res == null)
- res = new SizeRequirements();
+ // Create new instance if sr == null.
+ if (sr == null)
+ sr = new SizeRequirements();
+ sr.alignment = 0.5F;
+
+ // Calculate overall ascent and descent.
+ int totalAscentMin = 0;
+ int totalAscentPref = 0;
+ int totalAscentMax = 0;
+ int totalDescentMin = 0;
+ int totalDescentPref = 0;
+ int totalDescentMax = 0;
+
+ int count = getViewCount();
+ for (int i = 0; i < count; i++)
+ {
+ View v = getView(i);
+ float align = v.getAlignment(axis);
+ int span = (int) v.getPreferredSpan(axis);
+ int ascent = (int) (align * span);
+ int descent = span - ascent;
+
+ totalAscentPref = Math.max(ascent, totalAscentPref);
+ totalDescentPref = Math.max(descent, totalDescentPref);
+ if (v.getResizeWeight(axis) > 0)
+ {
+ // If the view is resizable, then use the min and max size
+ // of the view.
+ span = (int) v.getMinimumSpan(axis);
+ ascent = (int) (align * span);
+ descent = span - ascent;
+ totalAscentMin = Math.max(ascent, totalAscentMin);
+ totalDescentMin = Math.max(descent, totalDescentMin);
+
+ span = (int) v.getMaximumSpan(axis);
+ ascent = (int) (align * span);
+ descent = span - ascent;
+ totalAscentMax = Math.max(ascent, totalAscentMax);
+ totalDescentMax = Math.max(descent, totalDescentMax);
+ }
+ else
+ {
+ // If the view is not resizable, use the preferred span.
+ totalAscentMin = Math.max(ascent, totalAscentMin);
+ totalDescentMin = Math.max(descent, totalDescentMin);
+ totalAscentMax = Math.max(ascent, totalAscentMax);
+ totalDescentMax = Math.max(descent, totalDescentMax);
+ }
+ }
- 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);
- }
- 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;
+ // Preferred overall span is the sum of the preferred ascent and descent.
+ // With overflow check.
+ sr.preferred = (int) Math.min((long) totalAscentPref
+ + (long) totalDescentPref,
+ Integer.MAX_VALUE);
+
+ // Align along the baseline.
+ if (sr.preferred > 0)
+ sr.alignment = (float) totalAscentPref / sr.preferred;
+
+ if (sr.alignment == 0)
+ {
+ // Nothing above the baseline, use the descent.
+ sr.minimum = totalDescentMin;
+ sr.maximum = totalDescentMax;
+ }
+ else if (sr.alignment == 1.0F)
+ {
+ // Nothing below the baseline, use the descent.
+ sr.minimum = totalAscentMin;
+ sr.maximum = totalAscentMax;
+ }
+ else
+ {
+ sr.minimum = Math.max((int) (totalAscentMin / sr.alignment),
+ (int) (totalDescentMin / (1.0F - sr.alignment)));
+ sr.maximum = Math.min((int) (totalAscentMax / sr.alignment),
+ (int) (totalDescentMax / (1.0F - sr.alignment)));
+ }
+ return sr;
}
/**
- * Calculates the layout of the children of this <code>BoxView</code> along
- * the specified axis.
+ * Calculates the baseline layout of the children of this
+ * <code>BoxView</code> along the specified axis.
+ *
+ * This is not used by the BoxView itself, but by subclasses that wish to
+ * perform a baseline layout, like the FlowView's rows.
*
* @param span the target span
* @param axis the axis that is examined
* @param offsets an empty array, filled with the offsets of the children
* @param spans an empty array, filled with the spans of the children
*/
protected void baselineLayout(int span, int axis, int[] offsets,
int[] spans)
{
- updateChildRequirements(axis);
- updateRequirements(axis);
+ int totalAscent = (int) (span * getAlignment(axis));
+ int totalDescent = span - totalAscent;
- // Calculate the spans and offsets using the SizeRequirements uility
- // methods.
- SizeRequirements.calculateAlignedPositions(span, requirements[axis],
- childReqs[axis], offsets, spans);
+ int count = getViewCount();
+ for (int i = 0; i < count; i++)
+ {
+ View v = getView(i);
+ float align = v.getAlignment(axis);
+ int viewSpan;
+ if (v.getResizeWeight(axis) > 0)
+ {
+ // If possible, then resize for best fit.
+ int min = (int) v.getMinimumSpan(axis);
+ int max = (int) v.getMaximumSpan(axis);
+ if (align == 0.0F)
+ viewSpan = Math.max(Math.min(max, totalDescent), min);
+ else if (align == 1.0F)
+ viewSpan = Math.max(Math.min(max, totalAscent), min);
+ else
+ {
+ int fit = (int) Math.min(totalAscent / align,
+ totalDescent / (1.0F - align));
+ viewSpan = Math.max(Math.min(max, fit), min);
+ }
+ }
+ else
+ viewSpan = (int) v.getPreferredSpan(axis);
+ offsets[i] = totalAscent - (int) (viewSpan * align);
+ spans[i] = viewSpan;
+ }
}
/**
* Calculates the size requirements of this <code>BoxView</code> along
* 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
@@ -979,50 +1041,24 @@
{
// FIXME: What to do here?
return super.viewToModel(x, y, a, bias);
}
protected boolean flipEastAndWestAtEnds(int position, Position.Bias bias)
{
// FIXME: What to do here?
return super.flipEastAndWestAtEnds(position, bias);
}
/**
- * Updates the child requirements along the specified axis. The requirements
- * are only updated if the layout for the specified axis is marked as
- * invalid.
- *
- * @param axis the axis to be updated
- */
- private void updateChildRequirements(int axis)
- {
- if (! isLayoutValid(axis))
- {
- int numChildren = getViewCount();
- if (childReqs[axis] == null || childReqs[axis].length != numChildren)
- childReqs[axis] = new SizeRequirements[numChildren];
- for (int i = 0; i < numChildren; ++i)
- {
- View child = getView(i);
- childReqs[axis][i] =
- new SizeRequirements((int) child.getMinimumSpan(axis),
- (int) child.getPreferredSpan(axis),
- (int) child.getMaximumSpan(axis),
- child.getAlignment(axis));
- }
- }
- }
-
- /**
* 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 (axis != Y_AXIS && axis != X_AXIS)
throw new IllegalArgumentException("Illegal axis: " + axis);
if (! requirementsValid[axis])
{
Index: javax/swing/text/GlyphView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/GlyphView.java,v
retrieving revision 1.19
diff -u -1 -2 -r1.19 GlyphView.java
--- javax/swing/text/GlyphView.java 11 Aug 2006 12:33:16 -0000 1.19
+++ javax/swing/text/GlyphView.java 25 Aug 2006 11:19:18 -0000
@@ -37,25 +37,24 @@
package javax.swing.text;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
-import java.text.BreakIterator;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.text.Position.Bias;
/**
* Renders a run of styled text. This [EMAIL PROTECTED] View} subclass paints the
* characters of the <code>Element</code> it is responsible for using
* the style information from that <code>Element</code>.
*
* @author Roman Kennke ([EMAIL PROTECTED])
*/
@@ -291,46 +290,37 @@
bounds.x, tabEx, txt.offset);
// Fill the background of the text run.
Color background = view.getBackground();
if (background != null)
{
g.setColor(background);
g.fillRect(bounds.x, bounds.y, width, height);
}
// Draw the actual text.
g.setColor(view.getForeground());
g.setFont(view.getFont());
int ascent = g.getFontMetrics().getAscent();
- if (view.isSuperscript())
- // TODO: Adjust font for superscripting.
- Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent - height / 2,
- g, tabEx, txt.offset);
- else if (view.isSubscript())
- // TODO: Adjust font for subscripting.
- Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent + height / 2,
- g, tabEx, txt.offset);
- else
- Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent, g, tabEx,
- txt.offset);
+ Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent, g, tabEx,
+ txt.offset);
if (view.isStrikeThrough())
{
int strikeHeight = (int) (getAscent(view) / 2);
- g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width,
+ g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.x + width,
bounds.y + strikeHeight);
}
if (view.isUnderline())
{
int lineHeight = (int) getAscent(view);
- g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width,
+ g.drawLine(bounds.x, bounds.y + lineHeight, bounds.x + width,
bounds.y + lineHeight);
}
g.setColor(oldColor);
}
/**
* Maps a position in the document into the coordinate space of the View.
* The output rectangle usually reflects the font height but has a width
* of zero.
*
* @param view the glyph view
* @param pos the position of the character in the model
@@ -376,25 +366,24 @@
* @param view the glyph view
* @param p0 the starting location in the document model
* @param p1 the end location in the document model
* @param te the tab expander to use
* @param x the location at which the view is located
*
* @return the span of the glyphs from location <code>p0</code> to
* location <code>p1</code>, possibly using TAB expansion
*/
public float getSpan(GlyphView view, int p0, int p1,
TabExpander te, float x)
{
- Element el = view.getElement();
Font font = view.getFont();
FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
Segment txt = view.getText(p0, p1);
int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0);
return span;
}
/**
* Returns the ascent of the text run that is rendered by this
* <code>GlyphPainter</code>.
*
* @param v the glyph view
@@ -565,37 +554,42 @@
* 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)
{
float span = 0;
checkPainter();
GlyphPainter painter = getGlyphPainter();
- if (axis == X_AXIS)
+ switch (axis)
{
- Element el = getElement();
+ case X_AXIS:
TabExpander tabEx = null;
View parent = getParent();
if (parent instanceof TabExpander)
tabEx = (TabExpander) parent;
span = painter.getSpan(this, getStartOffset(), getEndOffset(),
tabEx, 0.F);
+ break;
+ case Y_AXIS:
+ span = painter.getHeight(this);
+ if (isSuperscript())
+ span += span / 3;
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal axis");
}
- else
- span = painter.getHeight(this);
-
return span;
}
/**
* Maps a position in the document into the coordinate space of the View.
* The output rectangle usually reflects the font height but has a width
* of zero.
*
* @param pos the position of the character in the model
* @param a the area that is occupied by the view
* @param b either [EMAIL PROTECTED] Position.Bias#Forward} or
* [EMAIL PROTECTED] Position.Bias#Backward} depending on the preferred
@@ -753,34 +747,37 @@
return txt;
}
/**
* Returns the font for the text run for which this <code>GlyphView</code>
* is responsible.
*
* @return the font for the text run for which this <code>GlyphView</code>
* is responsible
*/
public Font getFont()
{
- Element el = getElement();
- AttributeSet atts = el.getAttributes();
- String family = StyleConstants.getFontFamily(atts);
- int size = StyleConstants.getFontSize(atts);
- int style = Font.PLAIN;
- if (StyleConstants.isBold(atts))
- style |= Font.BOLD;
- if (StyleConstants.isItalic(atts))
- style |= Font.ITALIC;
- Font font = new Font(family, style, size);
+ Document doc = getDocument();
+ Font font = null;
+ if (doc instanceof StyledDocument)
+ {
+ StyledDocument styledDoc = (StyledDocument) doc;
+ font = styledDoc.getFont(getAttributes());
+ }
+ else
+ {
+ Container c = getContainer();
+ if (c != null)
+ font = c.getFont();
+ }
return font;
}
/**
* Returns the foreground color which should be used to paint the text.
* This is fetched from the associated element's text attributes using
* [EMAIL PROTECTED] StyleConstants#getForeground}.
*
* @return the foreground color which should be used to paint the text
*/
public Color getForeground()
{
@@ -899,28 +896,26 @@
* @param pos the view position along the axis where the fragment starts
* @param len the desired length of the fragment view
*
* @return the fragment view, or <code>this</code> if breaking was not
* possible
*/
public View breakView(int axis, int p0, float pos, float len)
{
if (axis == Y_AXIS)
return this;
checkPainter();
- GlyphPainter painter = getGlyphPainter();
// Try to find a suitable line break.
- BreakIterator lineBreaker = BreakIterator.getLineInstance();
Segment txt = new Segment();
try
{
int start = getStartOffset();
int length = getEndOffset() - start;
getDocument().getText(start, length, txt);
}
catch (BadLocationException ex)
{
AssertionError err = new AssertionError("BadLocationException must not "
+ "be thrown here.");
err.initCause(ex);
@@ -1041,32 +1036,39 @@
fragment.endOffset = p1;
return fragment;
}
/**
* Returns the alignment of this view along the specified axis. For the Y
* axis this is <code>(height - descent) / height</code> for the used font,
* so that it is aligned along the baseline.
* For the X axis the superclass is called.
*/
public float getAlignment(int axis)
{
+ checkPainter();
float align;
if (axis == Y_AXIS)
{
- checkPainter();
GlyphPainter painter = getGlyphPainter();
float height = painter.getHeight(this);
float descent = painter.getDescent(this);
- align = (height - descent) / height;
+ float ascent = painter.getAscent(this);
+ if (isSuperscript())
+ align = 1.0F;
+ else if (isSubscript())
+ align = height > 0 ? (height - (descent + (ascent / 2))) / height
+ : 0;
+ else
+ align = height > 0 ? (height - descent) / height : 0;
}
else
align = super.getAlignment(axis);
return align;
}
/**
* Returns the model location that should be used to place a caret when
* moving the caret through the document.
*
* @param pos the current model location
Index: javax/swing/text/LabelView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/LabelView.java,v
retrieving revision 1.5
diff -u -1 -2 -r1.5 LabelView.java
--- javax/swing/text/LabelView.java 24 Aug 2006 16:17:09 -0000 1.5
+++ javax/swing/text/LabelView.java 25 Aug 2006 11:19:18 -0000
@@ -110,37 +110,37 @@
/**
* Loads the properties of this label view from the element's text
* attributes. This method is called from the constructor and the
* [EMAIL PROTECTED] #changedUpdate} method
*/
protected void setPropertiesFromAttributes()
{
AttributeSet atts = getAttributes();
// We cannot use StyleConstants.getBackground() here, because that returns
// BLACK as default (when background == null). What we need is the
// background setting of the text component instead, which is what we get
// when background == null anyway.
- background = (Color) atts.getAttribute(StyleConstants.Background);
- foreground = StyleConstants.getForeground(atts);
setStrikeThrough(StyleConstants.isStrikeThrough(atts));
setSubscript(StyleConstants.isSubscript(atts));
setSuperscript(StyleConstants.isSuperscript(atts));
setUnderline(StyleConstants.isUnderline(atts));
- // Determine the font.
+ // Determine the font and colors.
Document d = getDocument();
if (d instanceof StyledDocument)
{
StyledDocument doc = (StyledDocument) d;
font = doc.getFont(atts);
+ background = doc.getBackground(atts);
+ foreground = doc.getForeground(atts);
}
valid = true;
}
/**
* Receives notification when text attributes change in the chunk of
* text that this view is responsible for. This simply calls
* [EMAIL PROTECTED] #setPropertiesFromAttributes()}.
*
* @param e the document event
* @param a the allocation of this view
* @param vf the view factory to use for creating new views
@@ -246,24 +246,26 @@
underline = flag;
}
/**
* Returns <code>true</code> if the glyphs are rendered as subscript,
* <code>false</code> otherwise.
*
* @return <code>true</code> if the glyphs are rendered as subscript,
* <code>false</code> otherwise
*/
public boolean isSubscript()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return subscript;
}
/**
* Sets the subscript flag.
*
* @param flag <code>true</code> if the glyphs are rendered as subscript,
* <code>false</code> otherwise
*/
protected void setSubscript(boolean flag)
{
subscript = flag;
Index: javax/swing/text/ParagraphView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/ParagraphView.java,v
retrieving revision 1.10
diff -u -1 -2 -r1.10 ParagraphView.java
--- javax/swing/text/ParagraphView.java 12 Aug 2006 22:16:12 -0000 1.10
+++ javax/swing/text/ParagraphView.java 25 Aug 2006 11:19:18 -0000
@@ -31,24 +31,25 @@
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
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.Shape;
+import javax.swing.SizeRequirements;
import javax.swing.event.DocumentEvent;
/**
* A [EMAIL PROTECTED] FlowView} that flows it's children horizontally and boxes the rows
* vertically.
*
* @author Roman Kennke ([EMAIL PROTECTED])
*/
public class ParagraphView extends FlowView implements TabExpander
{
/**
* A specialized horizontal <code>BoxView</code> that represents exactly
@@ -98,24 +99,45 @@
{
int nviews = getViewCount();
for (int i = 0; i < nviews && index == -1; i++)
{
View child = getView(i);
if (pos >= child.getStartOffset() && pos < child.getEndOffset())
index = i;
}
}
return index;
}
+
+ /**
+ * Overridden to perform a baseline layout. The normal BoxView layout
+ * isn't completely suitable for rows.
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ baselineLayout(targetSpan, axis, offsets, spans);
+ }
+
+ /**
+ * Overridden to perform a baseline layout. The normal BoxView layout
+ * isn't completely suitable for rows.
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ return baselineRequirements(axis, r);
+ }
+
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;
/**