diff options
author | Roman Kennke <roman@kennke.org> | 2006-11-19 18:54:19 +0000 |
---|---|---|
committer | Roman Kennke <roman@kennke.org> | 2006-11-19 18:54:19 +0000 |
commit | b1d0c928622637949dfb9158cdc3f75851850992 (patch) | |
tree | 1f58e36b6ce4b8b2c93c6f234014f158488ecce7 | |
parent | dcde416ef391ce7365b8b05416697a26c8ea3139 (diff) | |
download | classpath-b1d0c928622637949dfb9158cdc3f75851850992.tar.gz |
2006-11-19 Roman Kennke <kennke@aicas.com>
* javax/swing/text/BoxView.java
(clipRect): New field.
(tmpRect): New field.
(layout): Reorganized code. Now uses layoutAxis() helper method.
(layoutAxis): New helper method.
(paint): Optimized by using cached Rectangle objects and
a binary search for child views inside the clip.
* javax/swing/text/CompositeView.java
(insideAllocation): Made private and initialized in constructor.
(getInsideAllocation): Removed initialization block for
insideAllocation field. Avoid unnecessary allocations.
* javax/swing/text/GlyphView.java
(DefaultGlyphPainter.paint): Only paint the actual glyphs here
The remaining stuff (background, underline and striking) is
done in the GlpyhView itself. Avoid unnecessary allocations.
(cached): A cached Segment instance.
(getText): Return cached segment.
(paint): Paint underline, strike and background here. Avoid
unecessary allocs.
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | javax/swing/text/BoxView.java | 167 | ||||
-rw-r--r-- | javax/swing/text/CompositeView.java | 17 | ||||
-rw-r--r-- | javax/swing/text/GlyphView.java | 122 |
4 files changed, 220 insertions, 108 deletions
@@ -1,5 +1,27 @@ 2006-11-19 Roman Kennke <kennke@aicas.com> + * javax/swing/text/BoxView.java + (clipRect): New field. + (tmpRect): New field. + (layout): Reorganized code. Now uses layoutAxis() helper method. + (layoutAxis): New helper method. + (paint): Optimized by using cached Rectangle objects and + a binary search for child views inside the clip. + * javax/swing/text/CompositeView.java + (insideAllocation): Made private and initialized in constructor. + (getInsideAllocation): Removed initialization block for + insideAllocation field. Avoid unnecessary allocations. + * javax/swing/text/GlyphView.java + (DefaultGlyphPainter.paint): Only paint the actual glyphs here + The remaining stuff (background, underline and striking) is + done in the GlpyhView itself. Avoid unnecessary allocations. + (cached): A cached Segment instance. + (getText): Return cached segment. + (paint): Paint underline, strike and background here. Avoid + unecessary allocs. + +2006-11-19 Roman Kennke <kennke@aicas.com> + * javax/swing/text/html/StyleSheet.java (getFontSize): Removed debug output. (ListPainter.tmpRect): New field. diff --git a/javax/swing/text/BoxView.java b/javax/swing/text/BoxView.java index 962d06219..902927980 100644 --- a/javax/swing/text/BoxView.java +++ b/javax/swing/text/BoxView.java @@ -282,6 +282,13 @@ public class BoxView } /** + * A Rectangle instance to be reused in the paint() method below. + */ + private final Rectangle tmpRect = new Rectangle(); + + private Rectangle clipRect = new Rectangle(); + + /** * Renders the <code>Element</code> that is associated with this * <code>View</code>. * @@ -290,26 +297,93 @@ public class BoxView */ public void paint(Graphics g, Shape a) { - Rectangle alloc; - if (a instanceof Rectangle) - alloc = (Rectangle) a; - else - alloc = a.getBounds(); - - int x = alloc.x + getLeftInset(); - int y = alloc.y + getTopInset(); + // Try to avoid allocation if possible (almost all cases). + Rectangle alloc = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + + // This returns a cached instance. + alloc = getInsideAllocation(alloc); + + // The following algorithm optimizes painting of a BoxView by taking + // advantage of the layout order of the box children. + // + // 1. It first searches a child that which's allocation is inside the clip. + // This is accomplished by an efficient binary search. This assumes + // that the children of the BoxView are laid out in the same order + // as their index within the view. This is true for the BoxView, but + // might not be the case for all subclasses. + // 2. Starting from the found view, it paints the children in both + // directions until the first view is hit that is outside the clip. + + // First we search a child view that is inside the clip. + + // Fetch the clip rect and calculate the center point of it. + clipRect = g.getClipBounds(clipRect); + int cX = clipRect.x + clipRect.width / 2; + int cY = clipRect.y + clipRect.height / 2; + + int viewCount = getViewCount(); + int up = viewCount; + int low = 0; + int mid = (up - low) / 2; + View start = getView(mid); + + int newMid; + // Use another cached instance here to avoid allocations during + // painting. + tmpRect.setBounds(alloc); + // This modifies tmpRect. + childAllocation(mid, tmpRect); + while (! clipRect.intersects(tmpRect)) + { + if (isBefore(cX, cY, tmpRect)) + { + up = mid; + newMid = (up - low) / 2 + low; + mid = (newMid == mid) ? newMid - 1 : newMid; + } + else + { + low = mid; + newMid = (up - low) / 2 + low; + mid = (newMid == mid) ? newMid + 1 : newMid; + } + if (mid >= 0 && mid < viewCount) + { + start = getView(mid); + tmpRect.setBounds(alloc); + childAllocation(mid, tmpRect); + } + else + break; + } - Rectangle clip = g.getClipBounds(); - Rectangle tmp = new Rectangle(); - int count = getViewCount(); - for (int i = 0; i < count; ++i) + if (mid >= 0 && mid < viewCount) { - 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); + // Ok, we found one view that is inside the clip rect. Now paint the + // children before it that are inside the clip. + boolean inClip = true; + for (int i = mid - 1; i >= 0 && inClip; i--) + { + start = getView(i); + tmpRect.setBounds(alloc); + childAllocation(i, tmpRect); + inClip = clipRect.intersects(tmpRect); + if (inClip) + paintChild(g, tmpRect, i); + } + + // Now paint the found view and all views after it that lie inside the + // clip. + inClip = true; + for (int i = mid; i < viewCount && inClip; i++) + { + start = getView(i); + tmpRect.setBounds(alloc); + childAllocation(i, tmpRect); + inClip = clipRect.intersects(tmpRect); + if (inClip) + paintChild(g, tmpRect, i); + } } } @@ -742,49 +816,32 @@ public class BoxView */ protected void layout(int width, int height) { - int[] newSpan = new int[]{ width, height }; - int count = getViewCount(); - - // Update minor axis as appropriate. We need to first update the minor - // axis layout because that might affect the children's preferences along - // the major axis. - int minorAxis = myAxis == X_AXIS ? Y_AXIS : X_AXIS; - if ((! isLayoutValid(minorAxis)) || newSpan[minorAxis] != span[minorAxis]) - { - layoutValid[minorAxis] = false; - span[minorAxis] = newSpan[minorAxis]; - layoutMinorAxis(span[minorAxis], minorAxis, offsets[minorAxis], - spans[minorAxis]); - - // Update the child view's sizes. - for (int i = 0; i < count; ++i) - { - getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); - } - layoutValid[minorAxis] = true; - } - + layoutAxis(X_AXIS, width); + layoutAxis(Y_AXIS, height); + } - // Update major axis as appropriate. - if ((! isLayoutValid(myAxis)) || newSpan[myAxis] != span[myAxis]) + private void layoutAxis(int axis, int s) + { + if (span[axis] != s) + layoutValid[axis] = false; + if (! layoutValid[axis]) { - layoutValid[myAxis] = false; - span[myAxis] = newSpan[myAxis]; - layoutMajorAxis(span[myAxis], myAxis, offsets[myAxis], - spans[myAxis]); + span[axis] = s; + updateRequirements(axis); + if (axis == myAxis) + layoutMajorAxis(span[axis], axis, offsets[axis], spans[axis]); + else + layoutMinorAxis(span[axis], axis, offsets[axis], spans[axis]); + layoutValid[axis] = true; - // Update the child view's sizes. - for (int i = 0; i < count; ++i) + // Push out child layout. + int viewCount = getViewCount(); + for (int i = 0; i < viewCount; i++) { - getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); + View v = getView(i); + v.setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); } - layoutValid[myAxis] = true; } - - if (layoutValid[myAxis] == false) - System.err.println("WARNING: Major axis layout must be valid after layout"); - if (layoutValid[minorAxis] == false) - System.err.println("Minor axis layout must be valid after layout"); } /** diff --git a/javax/swing/text/CompositeView.java b/javax/swing/text/CompositeView.java index d4467f314..ac81e544f 100644 --- a/javax/swing/text/CompositeView.java +++ b/javax/swing/text/CompositeView.java @@ -68,7 +68,7 @@ public abstract class CompositeView * initialized in {@link #getInsideAllocation} and reused and modified in * {@link #childAllocation(int, Rectangle)}. */ - Rectangle insideAllocation; + private final Rectangle insideAllocation = new Rectangle(); /** * The insets of this <code>CompositeView</code>. This is initialized @@ -527,20 +527,13 @@ public abstract class CompositeView if (a == null) return null; - Rectangle alloc = a.getBounds(); + // Try to avoid allocation of Rectangle here. + Rectangle alloc = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + // Initialize the inside allocation rectangle. This is done inside // a synchronized block in order to avoid multiple threads creating // this instance simultanously. - Rectangle inside; - synchronized(this) - { - inside = insideAllocation; - if (inside == null) - { - inside = new Rectangle(); - insideAllocation = inside; - } - } + Rectangle inside = insideAllocation; inside.x = alloc.x + left; inside.y = alloc.y + top; inside.width = alloc.width - left - right; diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java index c654cee46..e2303bbc9 100644 --- a/javax/swing/text/GlyphView.java +++ b/javax/swing/text/GlyphView.java @@ -278,44 +278,27 @@ public class GlyphView extends View implements TabableView, Cloneable public void paint(GlyphView view, Graphics g, Shape a, int p0, int p1) { - Color oldColor = g.getColor(); - int height = (int) getHeight(view); + updateFontMetrics(view); + Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + TabExpander tabEx = view.getTabExpander(); Segment txt = view.getText(p0, p1); - Rectangle bounds = a.getBounds(); - TabExpander tabEx = null; - View parent = view.getParent(); - if (parent instanceof TabExpander) - tabEx = (TabExpander) parent; - - int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(), - 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(); - 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.x + width, - bounds.y + strikeHeight); - } - if (view.isUnderline()) + + // Find out the X location at which we have to paint. + int x = r.x; + int p = view.getStartOffset(); + if (p != p0) { - int lineHeight = (int) getAscent(view); - g.drawLine(bounds.x, bounds.y + lineHeight, bounds.x + width, - bounds.y + lineHeight); + int width = Utilities.getTabbedTextWidth(txt, fontMetrics,x, tabEx, + p); + x += width; } - g.setColor(oldColor); + // Find out Y location. + int y = r.y + fontMetrics.getHeight() - fontMetrics.getDescent(); + + // Render the thing. + g.setFont(fontMetrics.getFont()); + Utilities.drawTabbedText(txt, x, y, g, tabEx, p0); + } /** @@ -565,11 +548,29 @@ public class GlyphView extends View implements TabableView, Cloneable int p0 = getStartOffset(); int p1 = getEndOffset(); + Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); Container c = getContainer(); - // Paint layered highlights if there are any. + + Color fg = getForeground(); + JTextComponent tc = null; if (c instanceof JTextComponent) { - JTextComponent tc = (JTextComponent) c; + tc = (JTextComponent) c; + if (! tc.isEnabled()) + fg = tc.getDisabledTextColor(); + } + Color bg = getBackground(); + if (bg != null) + { + g.setColor(bg); + System.err.println("fill background: " + bg); + g.fillRect(r.x, r.y, r.width, r.height); + } + + + // Paint layered highlights if there are any. + if (tc != null) + { Highlighter h = tc.getHighlighter(); if (h instanceof LayeredHighlighter) { @@ -578,7 +579,45 @@ public class GlyphView extends View implements TabableView, Cloneable } } - getGlyphPainter().paint(this, g, a, p0, p1); + g.setColor(fg); + glyphPainter.paint(this, g, a, p0, p1); + boolean underline = isUnderline(); + boolean striked = isStrikeThrough(); + if (underline || striked) + { + View parent = getParent(); + // X coordinate. + if (parent != null && parent.getEndOffset() == p1) + { + // Strip whitespace. + Segment s = getText(p0, p1); + while (s.count > 0 && Character.isWhitespace(s.array[s.count - 1])) + { + p1--; + s.count--; + } + } + int x0 = r.x; + int p = getStartOffset(); + TabExpander tabEx = getTabExpander(); + if (p != p0) + x0 += (int) glyphPainter.getSpan(this, p, p0, tabEx, x0); + int x1 = x0 + (int) glyphPainter.getSpan(this, p0, p1, tabEx, x0); + // Y coordinate. + int y = r.y + r.height - (int) glyphPainter.getDescent(this); + if (underline) + { + int yTmp = y; + yTmp += 1; + g.drawLine(x0, yTmp, x1, yTmp); + } + if (striked) + { + int yTmp = y; + yTmp -= (int) glyphPainter.getAscent(this); + g.drawLine(x0, yTmp, x1, yTmp); + } + } } @@ -743,6 +782,8 @@ public class GlyphView extends View implements TabableView, Cloneable return offs; } + private Segment cached = new Segment(); + /** * Returns the text segment that this view is responsible for. * @@ -753,10 +794,9 @@ public class GlyphView extends View implements TabableView, Cloneable */ public Segment getText(int p0, int p1) { - Segment txt = new Segment(); try { - getDocument().getText(p0, p1 - p0, txt); + getDocument().getText(p0, p1 - p0, cached); } catch (BadLocationException ex) { @@ -767,7 +807,7 @@ public class GlyphView extends View implements TabableView, Cloneable throw ae; } - return txt; + return cached; } /** |