diff options
author | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-11-13 00:29:48 +0000 |
---|---|---|
committer | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-11-13 00:29:48 +0000 |
commit | 2a2b91f336fe4f6c2a314db2bc4cdffff6cf5a61 (patch) | |
tree | 21df1df36e4070dbe32198f06ea33964e82a998b /javax | |
parent | 237bdd93058f891ae4567cf4e051c5831bd4646b (diff) | |
download | classpath-2a2b91f336fe4f6c2a314db2bc4cdffff6cf5a61.tar.gz |
2006-11-13 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD-->generics from 2006/11/04-2006/11/12.
Diffstat (limited to 'javax')
21 files changed, 1936 insertions, 365 deletions
diff --git a/javax/swing/JLabel.java b/javax/swing/JLabel.java index 3e0f28ed7..721287b21 100644 --- a/javax/swing/JLabel.java +++ b/javax/swing/JLabel.java @@ -431,11 +431,11 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * Creates a new vertically and horizontally centered * JLabel object with no text and the given icon. * - * @param image The icon to use with the label. + * @param image The icon to use with the label, <code>null</code> permitted. */ public JLabel(Icon image) { - this("", image, CENTER); + this(null, image, CENTER); } /** @@ -443,19 +443,21 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * given icon and horizontal alignment. By default, the text is TRAILING * the image. * - * @param image The icon to use with the label. - * @param horizontalAlignment The horizontal alignment of the label. + * @param image The icon to use with the label, <code>null</code> premitted. + * @param horizontalAlignment The horizontal alignment of the label, must be + * either <code>CENTER</code>, <code>LEFT</code>, <code>RIGHT</code>, + * <code>LEADING</code> or <code>TRAILING</code>. */ public JLabel(Icon image, int horizontalAlignment) { - this("", image, horizontalAlignment); + this(null, image, horizontalAlignment); } /** * Creates a new horizontally leading and vertically centered JLabel * object with no icon and the given text. * - * @param text The text to use with the label. + * @param text The text to use with the label, <code>null</code> permitted. */ public JLabel(String text) { @@ -466,8 +468,10 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * Creates a new vertically centered JLabel object with no icon and the * given text and horizontal alignment. * - * @param text The text to use with the label. - * @param horizontalAlignment The horizontal alignment of the label. + * @param text The text to use with the label, <code>null</code> permitted. + * @param horizontalAlignment The horizontal alignment of the label, must be + * either <code>CENTER</code>, <code>LEFT</code>, <code>RIGHT</code>, + * <code>LEADING</code> or <code>TRAILING</code>. */ public JLabel(String text, int horizontalAlignment) { @@ -478,12 +482,21 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * Creates a new vertically centered JLabel object with the given text, * icon, and horizontal alignment. * - * @param text The text to use with the label. - * @param icon The icon to use with the label. - * @param horizontalAlignment The horizontal alignment of the label. + * @param text The text to use with the label, <code>null</code> permitted. + * @param icon The icon to use with the label, <code>null</code> premitted. + * @param horizontalAlignment The horizontal alignment of the label, must be + * either <code>CENTER</code>, <code>LEFT</code>, <code>RIGHT</code>, + * <code>LEADING</code> or <code>TRAILING</code>. */ public JLabel(String text, Icon icon, int horizontalAlignment) { + if (horizontalAlignment != SwingConstants.LEFT + && horizontalAlignment != SwingConstants.RIGHT + && horizontalAlignment != SwingConstants.CENTER + && horizontalAlignment != SwingConstants.LEADING + && horizontalAlignment != SwingConstants.TRAILING) + throw new IllegalArgumentException(); + this.text = text; this.icon = icon; this.horizontalAlignment = horizontalAlignment; diff --git a/javax/swing/JTree.java b/javax/swing/JTree.java index c6f08b49c..332ec7424 100644 --- a/javax/swing/JTree.java +++ b/javax/swing/JTree.java @@ -1230,8 +1230,32 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public void treeNodesRemoved(TreeModelEvent ev) { - // TODO: The API docs suggest that this method should do something - // but I cannot really see what has to be done here ... + if (ev != null) + { + TreePath parent = ev.getTreePath(); + Object[] children = ev.getChildren(); + TreeSelectionModel sm = getSelectionModel(); + if (children != null) + { + TreePath path; + Vector toRemove = new Vector(); + // Collect items that we must remove. + for (int i = children.length - 1; i >= 0; i--) + { + path = parent.pathByAddingChild(children[i]); + if (nodeStates.containsKey(path)) + toRemove.add(path); + // Clear selection while we are at it. + if (sm != null) + removeDescendantSelectedPaths(path, true); + } + if (toRemove.size() > 0) + removeDescendantToggledPaths(toRemove.elements()); + TreeModel model = getModel(); + if (model == null || model.isLeaf(parent.getLastPathComponent())) + nodeStates.remove(parent); + } + } } /** @@ -1243,9 +1267,38 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public void treeStructureChanged(TreeModelEvent ev) { - // Set state of new path. - TreePath path = ev.getTreePath(); - setExpandedState(path, isExpanded(path)); + if (ev != null) + { + TreePath parent = ev.getTreePath(); + if (parent != null) + { + if (parent.getPathCount() == 1) + { + // We have a new root, clear everything. + clearToggledPaths(); + Object root = treeModel.getRoot(); + if (root != null && treeModel.isLeaf(root)) + nodeStates.put(parent, Boolean.TRUE); + } + else if (nodeStates.containsKey(parent)) + { + Vector toRemove = new Vector(); + boolean expanded = isExpanded(parent); + toRemove.add(parent); + removeDescendantToggledPaths(toRemove.elements()); + if (expanded) + { + TreeModel model = getModel(); + if (model != null + || model.isLeaf(parent.getLastPathComponent())) + collapsePath(parent); + else + nodeStates.put(parent, Boolean.TRUE); + } + } + removeDescendantSelectedPaths(parent, false); + } + } } } @@ -1399,8 +1452,10 @@ public class JTree extends JComponent implements Scrollable, Accessible * This contains the state of all nodes in the tree. Al/ entries map the * TreePath of a note to to its state. Valid states are EXPANDED and * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED. + * + * This is package private to avoid accessor methods. */ - private Hashtable nodeStates = new Hashtable(); + Hashtable nodeStates = new Hashtable(); protected transient TreeCellEditor cellEditor; @@ -2201,20 +2256,35 @@ public class JTree extends JComponent implements Scrollable, Accessible public void setSelectionPath(TreePath path) { + clearSelectionPathStates(); selectionModel.setSelectionPath(path); } public void setSelectionPaths(TreePath[] paths) { + clearSelectionPathStates(); selectionModel.setSelectionPaths(paths); } + + /** + * This method, and all calls to it, should be removed once the + * DefaultTreeModel fires events properly. Maintenance of the nodeStates + * table should really be done in the TreeModelHandler. + */ + private void clearSelectionPathStates() + { + TreePath[] oldPaths = selectionModel.getSelectionPaths(); + if (oldPaths != null) + for (int i = 0; i < oldPaths.length; i++) + nodeStates.remove(oldPaths[i]); + } public void setSelectionRow(int row) { TreePath path = getPathForRow(row); if (path != null) - selectionModel.setSelectionPath(path); + setSelectionPath(path); } public void setSelectionRows(int[] rows) @@ -2289,11 +2359,13 @@ public class JTree extends JComponent implements Scrollable, Accessible public void removeSelectionPath(TreePath path) { + clearSelectionPathStates(); selectionModel.removeSelectionPath(path); } public void removeSelectionPaths(TreePath[] paths) { + clearSelectionPathStates(); selectionModel.removeSelectionPaths(paths); } @@ -2302,7 +2374,7 @@ public class JTree extends JComponent implements Scrollable, Accessible TreePath path = getPathForRow(row); if (path != null) - selectionModel.removeSelectionPath(path); + removeSelectionPath(path); } public void removeSelectionRows(int[] rows) diff --git a/javax/swing/text/ComponentView.java b/javax/swing/text/ComponentView.java index 555120396..8de4de60f 100644 --- a/javax/swing/text/ComponentView.java +++ b/javax/swing/text/ComponentView.java @@ -397,7 +397,24 @@ public class ComponentView extends View { public void run() { - setParentImpl(); + Document doc = getDocument(); + try + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + setParentImpl(); + Container host = getContainer(); + if (host != null) + { + preferenceChanged(null, true, true); + host.repaint(); + } + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } } }); } diff --git a/javax/swing/text/CompositeView.java b/javax/swing/text/CompositeView.java index ab587a9e1..d4467f314 100644 --- a/javax/swing/text/CompositeView.java +++ b/javax/swing/text/CompositeView.java @@ -134,7 +134,7 @@ public abstract class CompositeView public void setParent(View parent) { super.setParent(parent); - if (parent != null && ((children == null) || children.length == 0)) + if (parent != null && numChildren == 0) loadChildren(getViewFactory()); } diff --git a/javax/swing/text/FlowView.java b/javax/swing/text/FlowView.java index cee5bb126..9609f3fc8 100644 --- a/javax/swing/text/FlowView.java +++ b/javax/swing/text/FlowView.java @@ -189,7 +189,7 @@ public abstract class FlowView extends BoxView // Then remove all views from the flow view. fv.removeAll(); - + for (int rowIndex = 0; start < end; rowIndex++) { View row = fv.createRow(); @@ -318,8 +318,8 @@ public abstract class FlowView extends BoxView int rowIndex) { View logicalView = getLogicalView(fv); - // FIXME: Handle the bias thing correctly. - int index = logicalView.getViewIndex(startOffset, Position.Bias.Forward); + int index = logicalView.getViewIndex(startOffset, + Position.Bias.Forward); View retVal = logicalView.getView(index); if (retVal.getStartOffset() != startOffset) retVal = retVal.createFragment(startOffset, retVal.getEndOffset()); @@ -603,6 +603,7 @@ public abstract class FlowView extends BoxView { super(element, axis); strategy = sharedStrategy; + layoutSpan = Short.MAX_VALUE; } /** @@ -651,7 +652,7 @@ public abstract class FlowView extends BoxView */ public int getFlowStart(int index) { - return getLeftInset(); // TODO: Is this correct? + return 0; } /** @@ -678,8 +679,8 @@ public abstract class FlowView extends BoxView if (layoutPool == null) { layoutPool = new LogicalView(getElement()); - layoutPool.setParent(this); } + layoutPool.setParent(this); // Initialize the flow strategy. strategy.insertUpdate(this, null, null); } @@ -696,21 +697,17 @@ public abstract class FlowView extends BoxView protected void layout(int width, int height) { int flowAxis = getFlowAxis(); + int span; if (flowAxis == X_AXIS) - { - if (layoutSpan != width) - { - layoutChanged(Y_AXIS); - layoutSpan = width; - } - } + span = (int) width; else + span = (int) height; + + if (layoutSpan != span) { - if (layoutSpan != height) - { - layoutChanged(X_AXIS); - layoutSpan = height; - } + layoutChanged(flowAxis); + layoutChanged(getAxis()); + layoutSpan = span; } if (! isLayoutValid(flowAxis)) diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java index cb7f8f05d..35c8dd5d7 100644 --- a/javax/swing/text/GlyphView.java +++ b/javax/swing/text/GlyphView.java @@ -252,6 +252,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ static class DefaultGlyphPainter extends GlyphPainter { + FontMetrics fontMetrics; + /** * Returns the full height of the rendered text. * @@ -259,9 +261,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ public float getHeight(GlyphView view) { - Font font = view.getFont(); - FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font); - float height = metrics.getHeight(); + updateFontMetrics(view); + float height = fontMetrics.getHeight(); return height; } @@ -341,16 +342,16 @@ public class GlyphView extends View implements TabableView, Cloneable Shape a) throws BadLocationException { + updateFontMetrics(view); Element el = view.getElement(); - Font font = view.getFont(); - FontMetrics fm = view.getContainer().getFontMetrics(font); Segment txt = view.getText(el.getStartOffset(), pos); Rectangle bounds = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); TabExpander expander = view.getTabExpander(); - int width = Utilities.getTabbedTextWidth(txt, fm, bounds.x, expander, + int width = Utilities.getTabbedTextWidth(txt, fontMetrics, bounds.x, + expander, view.getStartOffset()); - int height = fm.getHeight(); + int height = fontMetrics.getHeight(); Rectangle result = new Rectangle(bounds.x + width, bounds.y, 0, height); return result; @@ -375,10 +376,10 @@ public class GlyphView extends View implements TabableView, Cloneable public float getSpan(GlyphView view, int p0, int p1, TabExpander te, float x) { - Font font = view.getFont(); - FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font); + updateFontMetrics(view); Segment txt = view.getText(p0, p1); - int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0); + int span = Utilities.getTabbedTextWidth(txt, fontMetrics, (int) x, te, + p0); return span; } @@ -395,9 +396,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ public float getAscent(GlyphView v) { - Font font = v.getFont(); - FontMetrics fm = v.getContainer().getFontMetrics(font); - return fm.getAscent(); + updateFontMetrics(v); + return fontMetrics.getAscent(); } /** @@ -413,9 +413,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ public float getDescent(GlyphView v) { - Font font = v.getFont(); - FontMetrics fm = v.getContainer().getFontMetrics(font); - return fm.getDescent(); + updateFontMetrics(v); + return fontMetrics.getDescent(); } /** @@ -430,16 +429,10 @@ public class GlyphView extends View implements TabableView, Cloneable */ public int getBoundedPosition(GlyphView v, int p0, float x, float len) { + updateFontMetrics(v); TabExpander te = v.getTabExpander(); Segment txt = v.getText(p0, v.getEndOffset()); - Font font = v.getFont(); - Container c = v.getContainer(); - FontMetrics fm; - if (c != null) - fm = c.getFontMetrics(font); - else - fm = Toolkit.getDefaultToolkit().getFontMetrics(font); - int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x, + int pos = Utilities.getTabbedTextOffset(txt, fontMetrics, (int) x, (int) (x + len), te, p0, false); return pos + p0; } @@ -458,9 +451,33 @@ public class GlyphView extends View implements TabableView, Cloneable public int viewToModel(GlyphView v, float x, float y, Shape a, Bias[] biasRet) { - Rectangle b = a.getBounds(); - int pos = getBoundedPosition(v, v.getStartOffset(), b.x, x - b.x); - return pos + v.getStartOffset(); + Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + int p0 = v.getStartOffset(); + int p1 = v.getEndOffset(); + TabExpander te = v.getTabExpander(); + Segment s = v.getText(p0, p1); + int offset = Utilities.getTabbedTextOffset(s, fontMetrics, r.x, (int) x, + te, p0); + int ret = p0 + offset; + if (ret == p1) + ret--; + biasRet[0] = Position.Bias.Forward; + return ret; + } + + private void updateFontMetrics(GlyphView v) + { + Font font = v.getFont(); + if (fontMetrics == null || ! font.equals(fontMetrics.getFont())) + { + Container c = v.getContainer(); + FontMetrics fm; + if (c != null) + fm = c.getFontMetrics(font); + else + fm = Toolkit.getDefaultToolkit().getFontMetrics(font); + fontMetrics = fm; + } } } diff --git a/javax/swing/text/ParagraphView.java b/javax/swing/text/ParagraphView.java index 6a13b2a3e..fb4ac65d8 100644 --- a/javax/swing/text/ParagraphView.java +++ b/javax/swing/text/ParagraphView.java @@ -38,6 +38,9 @@ exception statement from your version. */ package javax.swing.text; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; import java.awt.Shape; import javax.swing.SizeRequirements; @@ -104,19 +107,6 @@ public class ParagraphView extends FlowView implements TabExpander } /** - * 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; - } - - /** * Overridden because child views are not necessarily laid out in model * order. */ diff --git a/javax/swing/text/View.java b/javax/swing/text/View.java index aafd76a4f..dc611fe49 100644 --- a/javax/swing/text/View.java +++ b/javax/swing/text/View.java @@ -92,7 +92,14 @@ public abstract class View implements SwingConstants { int numChildren = getViewCount(); for (int i = 0; i < numChildren; i++) - getView(i).setParent(null); + { + View child = getView(i); + // It is important that we only reset the parent on views that + // actually belong to us. In FlowView the child may already be + // reparented. + if (child.getParent() == this) + child.setParent(null); + } } this.parent = parent; @@ -262,7 +269,7 @@ public abstract class View implements SwingConstants public void removeAll() { - replace(0, getViewCount(), new View[0]); + replace(0, getViewCount(), null); } public void remove(int index) @@ -618,10 +625,12 @@ public abstract class View implements SwingConstants DocumentEvent ev, Shape shape) { if (ec != null && shape != null) - preferenceChanged(null, true, true); - Container c = getContainer(); - if (c != null) - c.repaint(); + { + preferenceChanged(null, true, true); + Container c = getContainer(); + if (c != null) + c.repaint(); + } } /** diff --git a/javax/swing/text/html/BlockView.java b/javax/swing/text/html/BlockView.java index 6274e7b17..d7519ef9a 100644 --- a/javax/swing/text/html/BlockView.java +++ b/javax/swing/text/html/BlockView.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.Length; + import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; @@ -55,7 +57,24 @@ import javax.swing.text.ViewFactory; */ public class BlockView extends BoxView { - + + /** + * The attributes for this view. + */ + private AttributeSet attributes; + + /** + * The box painter for this view. + */ + private StyleSheet.BoxPainter painter; + + /** + * The width and height as specified in the stylesheet, null if not + * specified. The first value is the X_AXIS, the second the Y_AXIS. You + * can index this directly by the X_AXIS and Y_AXIS constants. + */ + private Length[] cssSpans; + /** * Creates a new view that represents an html box. * This can be used for a number of elements. @@ -66,8 +85,9 @@ public class BlockView extends BoxView public BlockView(Element elem, int axis) { super(elem, axis); + cssSpans = new Length[2]; } - + /** * Creates the parent view for this. It is called before * any other methods, if the parent view is working properly. @@ -99,12 +119,27 @@ public class BlockView extends BoxView protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) { - SizeRequirements sr = super.calculateMajorAxisRequirements(axis, r); - // FIXME: adjust it if the CSS width or height attribute is specified - // and applicable - return sr; + if (r == null) + r = new SizeRequirements(); + + if (setCSSSpan(r, axis)) + { + // If we have set the span from CSS, then we need to adjust + // the margins. + SizeRequirements parent = super.calculateMajorAxisRequirements(axis, + null); + int margin = axis == X_AXIS ? getLeftInset() + getRightInset() + : getTopInset() + getBottomInset(); + r.minimum -= margin; + r.preferred -= margin; + r.maximum -= margin; + constrainSize(axis, r, parent); + } + else + r = super.calculateMajorAxisRequirements(axis, r); + return r; } - + /** * Calculates the requirements along the minor axis. * This is implemented to call the superclass and then @@ -118,12 +153,73 @@ public class BlockView extends BoxView protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { - SizeRequirements sr = super.calculateMinorAxisRequirements(axis, r); - // FIXME: adjust it if the CSS width or height attribute is specified - // and applicable. - return sr; + if (r == null) + r = new SizeRequirements(); + + if (setCSSSpan(r, axis)) + { + // If we have set the span from CSS, then we need to adjust + // the margins. + SizeRequirements parent = super.calculateMinorAxisRequirements(axis, + null); + int margin = axis == X_AXIS ? getLeftInset() + getRightInset() + : getTopInset() + getBottomInset(); + r.minimum -= margin; + r.preferred -= margin; + r.maximum -= margin; + constrainSize(axis, r, parent); + } + else + r = super.calculateMinorAxisRequirements(axis, r); + return r; } - + + /** + * Sets the span on the SizeRequirements object according to the + * according CSS span value, when it is set. + * + * @param r the size requirements + * @param axis the axis + * + * @return <code>true</code> when the CSS span has been set, + * <code>false</code> otherwise + */ + private boolean setCSSSpan(SizeRequirements r, int axis) + { + boolean ret = false; + Length span = cssSpans[axis]; + // We can't set relative CSS spans here because we don't know + // yet about the allocated span. Instead we use the view's + // normal requirements. + if (span != null && ! span.isPercentage()) + { + r.minimum = (int) span.getValue(); + r.preferred = (int) span.getValue(); + r.maximum = (int) span.getValue(); + ret = true; + } + return ret; + } + + /** + * Constrains the <code>r</code> requirements according to + * <code>min</code>. + * + * @param axis the axis + * @param r the requirements to constrain + * @param min the constraining requirements + */ + private void constrainSize(int axis, SizeRequirements r, + SizeRequirements min) + { + if (min.minimum > r.minimum) + { + r.minimum = min.minimum; + r.preferred = min.minimum; + r.maximum = Math.max(r.maximum, min.maximum); + } + } + /** * Lays out the box along the minor axis (the axis that is * perpendicular to the axis that it represents). The results @@ -142,10 +238,40 @@ public class BlockView extends BoxView protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - // FIXME: Not implemented. - super.layoutMinorAxis(targetSpan, axis, offsets, spans); + int viewCount = getViewCount(); + CSS.Attribute spanAtt = axis == X_AXIS ? CSS.Attribute.WIDTH + : CSS.Attribute.HEIGHT; + for (int i = 0; i < viewCount; i++) + { + View view = getView(i); + int min = (int) view.getMinimumSpan(axis); + int max; + // Handle CSS span value of child. + AttributeSet atts = view.getAttributes(); + Length length = (Length) atts.getAttribute(spanAtt); + if (length != null) + { + min = Math.max((int) length.getValue(targetSpan), min); + max = min; + } + else + max = (int) view.getMaximumSpan(axis); + + if (max < targetSpan) + { + // Align child. + float align = view.getAlignment(axis); + offsets[i] = (int) ((targetSpan - max) * align); + spans[i] = max; + } + else + { + offsets[i] = 0; + spans[i] = Math.max(min, targetSpan); + } + } } - + /** * Paints using the given graphics configuration and shape. * This delegates to the css box painter to paint the @@ -156,11 +282,8 @@ public class BlockView extends BoxView */ public void paint(Graphics g, Shape a) { - Rectangle rect = (Rectangle) a; - // FIXME: not fully implemented - getStyleSheet().getBoxPainter(getAttributes()).paint(g, rect.x, rect.y, - rect.width, - rect.height, this); + Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + painter.paint(g, rect.x, rect.y, rect.width, rect.height, this); super.paint(g, a); } @@ -171,7 +294,9 @@ public class BlockView extends BoxView */ public AttributeSet getAttributes() { - return getStyleSheet().getViewAttributes(this); + if (attributes == null) + attributes = getStyleSheet().getViewAttributes(this); + return attributes; } /** @@ -206,8 +331,11 @@ public class BlockView extends BoxView if (getViewCount() == 0) return 0.0F; float prefHeight = getPreferredSpan(Y_AXIS); - float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS); - return (firstRowHeight / 2.F) / prefHeight; + View first = getView(0); + float firstRowHeight = first.getPreferredSpan(Y_AXIS); + return prefHeight != 0 ? (firstRowHeight * first.getAlignment(Y_AXIS)) + / prefHeight + : 0; } throw new IllegalArgumentException("Invalid Axis"); } @@ -227,7 +355,8 @@ public class BlockView extends BoxView // If more elements were added, then need to set the properties for them int currPos = ev.getOffset(); - if (currPos <= getStartOffset() && (currPos + ev.getLength()) >= getEndOffset()) + if (currPos <= getStartOffset() + && (currPos + ev.getLength()) >= getEndOffset()) setPropertiesFromAttributes(); } @@ -284,9 +413,27 @@ public class BlockView extends BoxView */ protected void setPropertiesFromAttributes() { - // FIXME: Not implemented (need to use StyleSheet). + // Fetch attributes. + StyleSheet ss = getStyleSheet(); + attributes = ss.getViewAttributes(this); + + // Fetch painter. + painter = ss.getBoxPainter(attributes); + + // Update insets. + if (attributes != null) + { + setInsets((short) painter.getInset(TOP, this), + (short) painter.getInset(LEFT, this), + (short) painter.getInset(BOTTOM, this), + (short) painter.getInset(RIGHT, this)); + } + + // Fetch width and height. + cssSpans[X_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.WIDTH); + cssSpans[Y_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.HEIGHT); } - + /** * Gets the default style sheet. * @@ -294,8 +441,7 @@ public class BlockView extends BoxView */ protected StyleSheet getStyleSheet() { - StyleSheet styleSheet = new StyleSheet(); - styleSheet.importStyleSheet(getClass().getResource(HTMLEditorKit.DEFAULT_CSS)); - return styleSheet; + HTMLDocument doc = (HTMLDocument) getDocument(); + return doc.getStyleSheet(); } } diff --git a/javax/swing/text/html/CSS.java b/javax/swing/text/html/CSS.java index 20a2debbc..6461dca9a 100644 --- a/javax/swing/text/html/CSS.java +++ b/javax/swing/text/html/CSS.java @@ -37,6 +37,7 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.BorderWidth; import gnu.javax.swing.text.html.css.CSSColor; import gnu.javax.swing.text.html.css.FontSize; import gnu.javax.swing.text.html.css.FontStyle; @@ -45,6 +46,9 @@ import gnu.javax.swing.text.html.css.Length; import java.io.Serializable; import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.swing.text.MutableAttributeSet; /** * Provides CSS attributes to be used by the HTML view classes. The constants @@ -394,6 +398,24 @@ public class CSS implements Serializable public static final Attribute WORD_SPACING = new Attribute("word-spacing", true, "normal"); + // Some GNU Classpath specific extensions. + static final Attribute BORDER_TOP_STYLE = + new Attribute("border-top-style", false, null); + static final Attribute BORDER_BOTTOM_STYLE = + new Attribute("border-bottom-style", false, null); + static final Attribute BORDER_LEFT_STYLE = + new Attribute("border-left-style", false, null); + static final Attribute BORDER_RIGHT_STYLE = + new Attribute("border-right-style", false, null); + static final Attribute BORDER_TOP_COLOR = + new Attribute("border-top-color", false, null); + static final Attribute BORDER_BOTTOM_COLOR = + new Attribute("border-bottom-color", false, null); + static final Attribute BORDER_LEFT_COLOR = + new Attribute("border-left-color", false, null); + static final Attribute BORDER_RIGHT_COLOR = + new Attribute("border-right-color", false, null); + /** * The attribute string. */ @@ -484,14 +506,44 @@ public class CSS implements Serializable o = new FontWeight(v); else if (att == Attribute.FONT_STYLE) o = new FontStyle(v); - else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR) + else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR + || att == Attribute.BORDER_COLOR + || att == Attribute.BORDER_TOP_COLOR + || att == Attribute.BORDER_BOTTOM_COLOR + || att == Attribute.BORDER_LEFT_COLOR + || att == Attribute.BORDER_RIGHT_COLOR) o = new CSSColor(v); else if (att == Attribute.MARGIN || att == Attribute.MARGIN_BOTTOM || att == Attribute.MARGIN_LEFT || att == Attribute.MARGIN_RIGHT - || att == Attribute.MARGIN_TOP) + || att == Attribute.MARGIN_TOP || att == Attribute.WIDTH + || att == Attribute.HEIGHT) o = new Length(v); + else if (att == Attribute.BORDER_WIDTH || att == Attribute.BORDER_TOP_WIDTH + || att == Attribute.BORDER_LEFT_WIDTH + || att == Attribute.BORDER_RIGHT_WIDTH + || att == Attribute.BORDER_BOTTOM_WIDTH) + o = new BorderWidth(v); else o = v; return o; } + + static void addInternal(MutableAttributeSet atts, Attribute a, String v) + { + if (a == Attribute.BACKGROUND) + parseBackgroundShorthand(atts, v); + } + + private static void parseBackgroundShorthand(MutableAttributeSet atts, + String v) + { + StringTokenizer tokens = new StringTokenizer(v, " "); + while (tokens.hasMoreElements()) + { + String token = tokens.nextToken(); + if (CSSColor.isValidColor(token)) + atts.addAttribute(Attribute.BACKGROUND_COLOR, + getValue(Attribute.BACKGROUND_COLOR, token)); + } + } } diff --git a/javax/swing/text/html/CSSBorder.java b/javax/swing/text/html/CSSBorder.java new file mode 100644 index 000000000..540955494 --- /dev/null +++ b/javax/swing/text/html/CSSBorder.java @@ -0,0 +1,420 @@ +/* CSSBorder.java -- A border for rendering CSS border styles + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +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.html; + +import gnu.javax.swing.text.html.css.BorderWidth; +import gnu.javax.swing.text.html.css.CSSColor; +import gnu.javax.swing.text.html.css.Length; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.border.Border; +import javax.swing.text.AttributeSet; + +/** + * A border implementation to render CSS border styles. + */ +class CSSBorder + implements Border +{ + + /** + * The CSS border styles. + */ + + private static final int STYLE_NOT_SET = -1; + private static final int STYLE_NONE = 0; + private static final int STYLE_HIDDEN = 1; + private static final int STYLE_DOTTED = 2; + private static final int STYLE_DASHED = 3; + private static final int STYLE_SOLID = 4; + private static final int STYLE_DOUBLE = 5; + private static final int STYLE_GROOVE = 6; + private static final int STYLE_RIDGE = 7; + private static final int STYLE_INSET = 8; + private static final int STYLE_OUTSET = 9; + + /** + * The left insets. + */ + private int left; + + /** + * The right insets. + */ + private int right; + + /** + * The top insets. + */ + private int top; + + /** + * The bottom insets. + */ + private int bottom; + + /** + * The border style on the left. + */ + private int leftStyle; + + /** + * The border style on the right. + */ + private int rightStyle; + + /** + * The border style on the top. + */ + private int topStyle; + + /** + * The color for the top border. + */ + private Color topColor; + + /** + * The color for the bottom border. + */ + private Color bottomColor; + + /** + * The color for the left border. + */ + private Color leftColor; + + /** + * The color for the right border. + */ + private Color rightColor; + + /** + * The border style on the bottom. + */ + private int bottomStyle; + + /** + * Creates a new CSS border and fetches its attributes from the specified + * attribute set. + * + * @param atts the attribute set that contains the border spec + */ + CSSBorder(AttributeSet atts) + { + // Determine the border styles. + int style = getBorderStyle(atts, CSS.Attribute.BORDER_STYLE); + if (style == STYLE_NOT_SET) + style = STYLE_NONE; // Default to none. + topStyle = bottomStyle = leftStyle = rightStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_TOP_STYLE); + if (style != STYLE_NOT_SET) + topStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_BOTTOM_STYLE); + if (style != STYLE_NOT_SET) + bottomStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_LEFT_STYLE); + if (style != STYLE_NOT_SET) + leftStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_RIGHT_STYLE); + if (style != STYLE_NOT_SET) + rightStyle = style; + + // Determine the border colors. + Color color = getBorderColor(atts, CSS.Attribute.BORDER_COLOR); + if (color == null) + color = Color.BLACK; + topColor = bottomColor = leftColor = rightColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_TOP_COLOR); + if (color != null) + topColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_BOTTOM_COLOR); + if (color != null) + bottomColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_LEFT_COLOR); + if (color != null) + leftColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_RIGHT_COLOR); + if (color != null) + rightColor = color; + + // Determine the border widths. + int width = getBorderWidth(atts, CSS.Attribute.BORDER_WIDTH); + if (width == -1) + width = 0; + top = bottom = left = right = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_TOP_WIDTH); + if (width >= 0) + top = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_BOTTOM_WIDTH); + if (width >= 0) + bottom = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_LEFT_WIDTH); + if (width >= 0) + left = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_RIGHT_WIDTH); + if (width >= 0) + right = width; + } + + /** + * Determines the border style for a given CSS attribute. + * + * @param atts the attribute set + * @param key the CSS key + * + * @return the border style according to the constants defined in this class + */ + private int getBorderStyle(AttributeSet atts, CSS.Attribute key) + { + int style = STYLE_NOT_SET; + Object o = atts.getAttribute(key); + if (o != null) + { + String cssStyle = o.toString(); + if (cssStyle.equals("none")) + style = STYLE_NONE; + else if (cssStyle.equals("hidden")) + style = STYLE_HIDDEN; + else if (cssStyle.equals("dotted")) + style = STYLE_DOTTED; + else if (cssStyle.equals("dashed")) + style = STYLE_DASHED; + else if (cssStyle.equals("solid")) + style = STYLE_SOLID; + else if (cssStyle.equals("double")) + style = STYLE_DOUBLE; + else if (cssStyle.equals("groove")) + style = STYLE_GROOVE; + else if (cssStyle.equals("ridge")) + style = STYLE_RIDGE; + else if (cssStyle.equals("inset")) + style = STYLE_INSET; + else if (cssStyle.equals("outset")) + style = STYLE_OUTSET; + } + return style; + } + + /** + * Determines the border color for the specified key. + * + * @param atts the attribute set from which to fetch the color + * @param key the CSS key + * + * @return the border color + */ + private Color getBorderColor(AttributeSet atts, CSS.Attribute key) + { + Object o = atts.getAttribute(key); + Color color = null; + if (o instanceof CSSColor) + { + CSSColor cssColor = (CSSColor) o; + color = cssColor.getValue(); + } + return color; + } + + /** + * Returns the width for the specified key. + * + * @param atts the attributes to fetch the width from + * @param key the CSS key + * + * @return the width, or -1 of none has been set + */ + private int getBorderWidth(AttributeSet atts, CSS.Attribute key) + { + int width = -1; + Object o = atts.getAttribute(key); + if (o instanceof BorderWidth) + { + width = (int) ((BorderWidth) o).getValue(); + } + return width; + } + + /** + * Returns the border insets. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(top, left, bottom, right); + } + + /** + * CSS borders are generally opaque so return true here. + */ + public boolean isBorderOpaque() + { + return true; + } + + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) + { + // Top border. + paintBorderLine(g, x, y + top / 2, x + width, y + top / 2, topStyle, top, + topColor, false); + // Left border. + paintBorderLine(g, x + left / 2, y, x + left / 2, y + height, leftStyle, + left, leftColor, true); + // Bottom border. + paintBorderLine(g, x, y + height - bottom / 2, x + width, + y + height - bottom / 2, topStyle, bottom, bottomColor, + false); + // Right border. + paintBorderLine(g, x + width - right / 2, y, x + width - right / 2, + y + height, topStyle, right, rightColor, true); + + } + + private void paintBorderLine(Graphics g, int x1, int y1, int x2, int y2, + int style, int width, Color color, + boolean vertical) + { + switch (style) + { + case STYLE_DOTTED: + paintDottedLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_DASHED: + paintDashedLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_SOLID: + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_DOUBLE: + paintDoubleLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_GROOVE: + paintGrooveLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_RIDGE: + paintRidgeLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_OUTSET: + paintOutsetLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_INSET: + paintInsetLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_NONE: + case STYLE_HIDDEN: + default: + // Nothing to do in these cases. + } + } + + private void paintDottedLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintDashedLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintSolidLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + int x = Math.min(x1, x2); + int y = Math.min(y1, y1); + int w = Math.abs(x2 - x1); + int h = Math.abs(y2 - y1); + if (vertical) + { + w = width; + x -= width / 2; + } + else + { + h = width; + y -= width / 2; + } + g.setColor(color); + g.fillRect(x, y, w, h); + } + + private void paintDoubleLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintGrooveLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintRidgeLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintOutsetLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintInsetLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + +} diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index 2e2eb3abc..26e3fb4bc 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -39,10 +39,10 @@ exception statement from your version. */ package javax.swing.text.html; import gnu.classpath.NotImplementedException; -import gnu.javax.swing.text.html.parser.htmlAttributeSet; import java.io.IOException; import java.io.StringReader; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -571,6 +571,16 @@ public class HTMLDocument extends DefaultStyledDocument boolean inPreTag = false; /** + * True when we are inside a paragraph (P, H1-H6, P-IMPLIED). + */ + boolean inParagraph = false; + + /** + * True when we are currently inside an implied paragraph. + */ + boolean inImpliedParagraph = false; + + /** * This is true when we are inside a style tag. This will add text * content inside this style tag beeing parsed as CSS. * @@ -600,12 +610,6 @@ public class HTMLDocument extends DefaultStyledDocument */ Document textAreaDocument; - void print (String line) - { - if (debug) - System.out.println (line); - } - public class TagAction { /** @@ -813,6 +817,7 @@ public class HTMLDocument extends DefaultStyledDocument public void start(HTML.Tag t, MutableAttributeSet a) { blockOpen(t, a); + inParagraph = true; } /** @@ -822,6 +827,7 @@ public class HTMLDocument extends DefaultStyledDocument public void end(HTML.Tag t) { blockClose(t); + inParagraph = false; } } @@ -882,7 +888,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("AreaAction.start not implemented"); } /** @@ -893,7 +898,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("AreaAction.end not implemented"); } } @@ -942,7 +946,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("BaseAction.start not implemented"); } /** @@ -953,7 +956,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("BaseAction.end not implemented"); } } @@ -967,7 +969,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("HeadAction.start not implemented: "+t); super.start(t, a); } @@ -992,29 +993,71 @@ public class HTMLDocument extends DefaultStyledDocument } } - class LinkAction extends TagAction + class LinkAction extends HiddenAction { /** * This method is called when a start tag is seen for one of the types * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) - throws NotImplementedException { - // FIXME: Implement. - print ("LinkAction.start not implemented"); + super.start(t, a); + String type = (String) a.getAttribute(HTML.Attribute.TYPE); + if (type == null) + type = "text/css"; + if (type.equals("text/css")) + { + String rel = (String) a.getAttribute(HTML.Attribute.REL); + String media = (String) a.getAttribute(HTML.Attribute.MEDIA); + String title = (String) a.getAttribute(HTML.Attribute.TITLE); + if (media == null) + media = "all"; + else + media = media.toLowerCase(); + if (rel != null) + { + rel = rel.toLowerCase(); + if ((media.indexOf("all") != -1 + || media.indexOf("screen") != -1) + && (rel.equals("stylesheet"))) + { + String href = (String) a.getAttribute(HTML.Attribute.HREF); + URL url = null; + try + { + url = new URL(baseURL, href); + } + catch (MalformedURLException ex) + { + try + { + url = new URL(href); + } + catch (MalformedURLException ex2) + { + url = null; + } + } + if (url != null) + { + try + { + getStyleSheet().importStyleSheet(url); + } + catch (Exception ex) + { + // Don't let exceptions and runtime exceptions + // in CSS parsing disprupt the HTML parsing + // process. But inform the user/developer + // on the console about it. + ex.printStackTrace(); + } + } + } + } + } } - /** - * Called when an end tag is seen for one of the types of tags associated - * with this Action. - */ - public void end(HTML.Tag t) - throws NotImplementedException - { - // FIXME: Implement. - print ("LinkAction.end not implemented"); - } } class MapAction extends TagAction @@ -1027,7 +1070,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MapAction.start not implemented"); } /** @@ -1038,7 +1080,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MapAction.end not implemented"); } } @@ -1052,7 +1093,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MetaAction.start not implemented"); } /** @@ -1063,7 +1103,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MetaAction.end not implemented"); } } @@ -1098,7 +1137,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("TitleAction.start not implemented"); } /** @@ -1109,7 +1147,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("TitleAction.end not implemented"); } } @@ -1121,9 +1158,6 @@ public class HTMLDocument extends DefaultStyledDocument public HTMLReader(int offset, int popDepth, int pushDepth, HTML.Tag insertTag) { - print ("HTMLReader created with pop: "+popDepth - + " push: "+pushDepth + " offset: "+offset - + " tag: "+insertTag); this.insertTag = insertTag; this.offset = offset; this.popDepth = popDepth; @@ -1351,8 +1385,7 @@ public class HTMLDocument extends DefaultStyledDocument TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT); if (action != null) { - action.start(HTML.Tag.COMMENT, - htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET); + action.start(HTML.Tag.COMMENT, new SimpleAttributeSet()); action.end(HTML.Tag.COMMENT); } } @@ -1414,7 +1447,6 @@ public class HTMLDocument extends DefaultStyledDocument public void handleEndOfLineString(String eol) { // FIXME: Implement. - print ("HTMLReader.handleEndOfLineString not implemented yet"); } /** @@ -1475,7 +1507,9 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void blockOpen(HTML.Tag t, MutableAttributeSet attr) { - printBuffer(); + if (inImpliedParagraph) + blockClose(HTML.Tag.IMPLIED); + DefaultStyledDocument.ElementSpec element; parseStack.push(t); @@ -1485,7 +1519,6 @@ public class HTMLDocument extends DefaultStyledDocument element = new DefaultStyledDocument.ElementSpec(copy, DefaultStyledDocument.ElementSpec.StartTagType); parseBuffer.addElement(element); - printBuffer(); } /** @@ -1496,9 +1529,16 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void blockClose(HTML.Tag t) { - printBuffer(); DefaultStyledDocument.ElementSpec element; + if (inImpliedParagraph) + { + inImpliedParagraph = false; + inParagraph = false; + if (t != HTML.Tag.IMPLIED) + blockClose(HTML.Tag.IMPLIED); + } + // If the previous tag is a start tag then we insert a synthetic // content tag. DefaultStyledDocument.ElementSpec prev; @@ -1519,7 +1559,6 @@ public class HTMLDocument extends DefaultStyledDocument element = new DefaultStyledDocument.ElementSpec(null, DefaultStyledDocument.ElementSpec.EndTagType); parseBuffer.addElement(element); - printBuffer(); if (parseStack.size() > 0) parseStack.pop(); } @@ -1550,6 +1589,13 @@ public class HTMLDocument extends DefaultStyledDocument protected void addContent(char[] data, int offs, int length, boolean generateImpliedPIfNecessary) { + if (generateImpliedPIfNecessary && (! inParagraph) && (! inPreTag)) + { + blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); + inParagraph = true; + inImpliedParagraph = true; + } + AbstractDocument.AttributeContext ctx = getAttributeContext(); DefaultStyledDocument.ElementSpec element; AttributeSet attributes = null; @@ -1566,10 +1612,8 @@ public class HTMLDocument extends DefaultStyledDocument DefaultStyledDocument.ElementSpec.ContentType, data, offs, length); - printBuffer(); // Add the element to the buffer parseBuffer.addElement(element); - printBuffer(); if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold()) { @@ -1592,29 +1636,25 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a) { + if (t != HTML.Tag.FRAME && ! inParagraph && ! inImpliedParagraph) + { + blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); + inParagraph = true; + inImpliedParagraph = true; + } + a.addAttribute(StyleConstants.NameAttribute, t); - // Migrate from the rather htmlAttributeSet to the faster, lighter and - // unchangeable alternative implementation. - AttributeSet copy = a.copyAttributes(); - // The two spaces are required because some special elements like HR // must be broken. At least two characters are needed to break into the // two parts. DefaultStyledDocument.ElementSpec spec = - new DefaultStyledDocument.ElementSpec(copy, + new DefaultStyledDocument.ElementSpec(a.copyAttributes(), DefaultStyledDocument.ElementSpec.ContentType, new char[] {' ', ' '}, 0, 2 ); parseBuffer.add(spec); } - void printBuffer() - { - print ("\n*********BUFFER**********"); - for (int i = 0; i < parseBuffer.size(); i ++) - print (" "+parseBuffer.get(i)); - print ("***************************"); - } } /** diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java index c541a4d34..85d5221d3 100644 --- a/javax/swing/text/html/HTMLEditorKit.java +++ b/javax/swing/text/html/HTMLEditorKit.java @@ -82,7 +82,7 @@ import javax.swing.text.html.parser.ParserDelegator; /* Move these imports here after javax.swing.text.html to make it compile with jikes. */ import gnu.javax.swing.text.html.parser.GnuParserDelegator; -import gnu.javax.swing.text.html.parser.HTML_401Swing; +import gnu.javax.swing.text.html.parser.HTML_401F; /** * @author Lillian Angel (langel at redhat dot com) @@ -646,15 +646,12 @@ public class HTMLEditorKit else if (tag.equals(HTML.Tag.IMG)) view = new ImageView(element); - // FIXME: Uncomment when the views have been implemented else if (tag.equals(HTML.Tag.CONTENT)) view = new InlineView(element); else if (tag == HTML.Tag.HEAD) view = new NullView(element); else if (tag.equals(HTML.Tag.TABLE)) view = new javax.swing.text.html.TableView(element); - else if (tag.equals(HTML.Tag.TD)) - view = new ParagraphView(element); else if (tag.equals(HTML.Tag.HR)) view = new HRuleView(element); else if (tag.equals(HTML.Tag.BR)) @@ -663,10 +660,11 @@ public class HTMLEditorKit || tag.equals(HTML.Tag.TEXTAREA)) view = new FormView(element); - /* else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) view = new ListView(element); + // FIXME: Uncomment when the views have been implemented + /* else if (tag.equals(HTML.Tag.OBJECT)) view = new ObjectView(element); else if (tag.equals(HTML.Tag.FRAMESET)) @@ -973,7 +971,7 @@ public class HTMLEditorKit { if (parser == null) { - parser = new GnuParserDelegator(HTML_401Swing.getInstance()); + parser = new GnuParserDelegator(HTML_401F.getInstance()); } return parser; } diff --git a/javax/swing/text/html/HTMLWriter.java b/javax/swing/text/html/HTMLWriter.java index 16e9a7163..44119c732 100644 --- a/javax/swing/text/html/HTMLWriter.java +++ b/javax/swing/text/html/HTMLWriter.java @@ -608,28 +608,8 @@ public class HTMLWriter closeOutUnwantedEmbeddedTags(attrSet); - // NOTE: 20061030 - fchoong - GNU CP uses a different implimentation of - // the IMPLIED tag. - boolean fg_gnu_cp_implied_tag = false; - - if (matchNameAttribute(attrSet, HTML.Tag.P)) - { - //writeAllAttributes(attrSet); - - Enumeration attrNameEnum = attrSet.getAttributeNames(); - - while (attrNameEnum.hasMoreElements()) - { - Object key = attrNameEnum.nextElement(); - Object value = attrSet.getAttribute(key); - - if (key.equals("_implied_") && value.toString().equals("true")) - fg_gnu_cp_implied_tag = true; - } // while(attrNameEnum.hasMoreElements()) - } // if(matchNameAttribute(attrSet, HTML.Tag.P)) - // handle the tag - if (synthesizedElement(paramElem) || fg_gnu_cp_implied_tag) + if (synthesizedElement(paramElem)) { if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) { @@ -640,8 +620,7 @@ public class HTMLWriter { comment(currElem); } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) - else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED) - || fg_gnu_cp_implied_tag) // NOTE: GNU CP specific + else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) { int child_elem_count = currElem.getElementCount(); @@ -782,28 +761,8 @@ public class HTMLWriter if (fg_is_fragment_parent_elem || (fg_pass_start_elem && fg_pass_end_elem == false) || fg_is_start_and_end_elem) { - // NOTE: 20061030 - fchoong - GNU CP uses a different implimentation of - // the IMPLIED tag. - boolean fg_gnu_cp_implied_tag = false; - - if (matchNameAttribute(attrSet, HTML.Tag.P)) - { - //writeAllAttributes(attrSet); - - Enumeration attrNameEnum = attrSet.getAttributeNames(); - - while (attrNameEnum.hasMoreElements()) - { - Object key = attrNameEnum.nextElement(); - Object value = attrSet.getAttribute(key); - - if (key.equals("_implied_") && value.toString().equals("true")) - fg_gnu_cp_implied_tag = true; - } // while(attrNameEnum.hasMoreElements()) - } // if(matchNameAttribute(attrSet, HTML.Tag.P)) - // handle the tag - if (synthesizedElement(paramElem) || fg_gnu_cp_implied_tag) + if (synthesizedElement(paramElem)) { if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) { @@ -862,8 +821,7 @@ public class HTMLWriter { comment(currElem); } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) - else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED) - || fg_gnu_cp_implied_tag) // NOTE: GNU CP specific + else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) { int child_elem_count = currElem.getElementCount(); diff --git a/javax/swing/text/html/InlineView.java b/javax/swing/text/html/InlineView.java index 31eaa129c..6b134ae39 100644 --- a/javax/swing/text/html/InlineView.java +++ b/javax/swing/text/html/InlineView.java @@ -38,13 +38,17 @@ exception statement from your version. */ package javax.swing.text.html; +import java.awt.FontMetrics; import java.awt.Shape; +import java.text.BreakIterator; import javax.swing.event.DocumentEvent; import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.LabelView; +import javax.swing.text.Segment; import javax.swing.text.View; import javax.swing.text.ViewFactory; @@ -65,6 +69,18 @@ public class InlineView private AttributeSet attributes; /** + * The span of the longest word in this view. + * + * @see #getLongestWord() + */ + private float longestWord; + + /** + * Indicates if we may wrap or not. + */ + private boolean nowrap; + + /** * Creates a new <code>InlineView</code> that renders the specified element. * * @param element the element for this view @@ -144,8 +160,13 @@ public class InlineView public int getBreakWeight(int axis, float pos, float len) { - // FIXME: Implement this. - return super.getBreakWeight(axis, pos, len); + int weight; + if (nowrap) { if (getText(getStartOffset(), getEndOffset()).toString().contains("Web")) + System.err.println("Web NOWRAP"); + weight = BadBreakWeight;} + else + weight = super.getBreakWeight(axis, pos, len); + return weight; } public View breakView(int axis, int offset, float pos, float len) @@ -190,7 +211,12 @@ public class InlineView b = true; setSuperscript(b); - // TODO: Handle white-space: nowrap property. + // Fetch nowrap setting. + o = atts.getAttribute(CSS.Attribute.WHITE_SPACE); + if (o != null && o.equals("nowrap")) + nowrap = true; + else + nowrap = false; } /** @@ -207,4 +233,74 @@ public class InlineView styleSheet = ((HTMLDocument) doc).getStyleSheet(); return styleSheet; } + + /** + * Returns the minimum span for the specified axis. This returns the + * width of the longest word for the X axis and the super behaviour for + * the Y axis. This is a slight deviation from the reference implementation. + * IMO this should improve rendering behaviour so that an InlineView never + * gets smaller than the longest word in it. + */ + public float getMinimumSpan(int axis) + { + float min = super.getMinimumSpan(axis); + if (axis == X_AXIS) + min = Math.max(getLongestWord(), min); + return min; + } + + /** + * Returns the span of the longest word in this view. + * + * @return the span of the longest word in this view + */ + private float getLongestWord() + { + if (longestWord == -1) + longestWord = calculateLongestWord(); + return longestWord; + } + + /** + * Calculates the span of the longest word in this view. + * + * @return the span of the longest word in this view + */ + private float calculateLongestWord() + { + float span = 0; + try + { + Document doc = getDocument(); + int p0 = getStartOffset(); + int p1 = getEndOffset(); + Segment s = new Segment(); + doc.getText(p0, p1 - p0, s); + BreakIterator iter = BreakIterator.getWordInstance(); + iter.setText(s); + int wordStart = p0; + int wordEnd = p0; + int start = iter.first(); + for (int end = iter.next(); end != BreakIterator.DONE; + start = end, end = iter.next()) + { + if ((end - start) > (wordEnd - wordStart)) + { + wordStart = start; + wordEnd = end; + } + } + if (wordEnd - wordStart > 0) + { + FontMetrics fm = getFontMetrics(); + int offset = s.offset + wordStart - s.getBeginIndex(); + span = fm.charsWidth(s.array, offset, wordEnd - wordStart); + } + } + catch (BadLocationException ex) + { + // Return 0. + } + return span; + } } diff --git a/javax/swing/text/html/ListView.java b/javax/swing/text/html/ListView.java index c07d3598c..3e809bbd2 100644 --- a/javax/swing/text/html/ListView.java +++ b/javax/swing/text/html/ListView.java @@ -94,9 +94,6 @@ public class ListView public void paint(Graphics g, Shape allocation) { super.paint(g, allocation); - // FIXME: Why is this overridden? I think that painting would be done - // by the superclass and the stylesheet... Maybe find out when this - // stuff is implemented properly. } /** diff --git a/javax/swing/text/html/ParagraphView.java b/javax/swing/text/html/ParagraphView.java index 951f70b60..e3f2817be 100644 --- a/javax/swing/text/html/ParagraphView.java +++ b/javax/swing/text/html/ParagraphView.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.Length; + import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; @@ -71,6 +73,16 @@ public class ParagraphView private StyleSheet.BoxPainter painter; /** + * The width as specified in the stylesheet or null if not specified. + */ + private Length cssWidth; + + /** + * The height as specified in the stylesheet or null if not specified. + */ + private Length cssHeight; + + /** * Creates a new ParagraphView for the specified element. * * @param element the element @@ -116,29 +128,34 @@ public class ParagraphView super.setPropertiesFromAttributes(); // Fetch CSS attributes. - AttributeSet atts = getAttributes(); - Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN); - if (o != null) + attributes = getAttributes(); + if (attributes != null) { - String align = o.toString(); - if (align.equals("left")) - setJustification(StyleConstants.ALIGN_LEFT); - else if (align.equals("right")) - setJustification(StyleConstants.ALIGN_RIGHT); - else if (align.equals("center")) - setJustification(StyleConstants.ALIGN_CENTER); - else if (align.equals("justify")) - setJustification(StyleConstants.ALIGN_JUSTIFIED); - } + super.setPropertiesFromAttributes(); + Object o = attributes.getAttribute(CSS.Attribute.TEXT_ALIGN); + if (o != null) + { + String align = o.toString(); + if (align.equals("left")) + setJustification(StyleConstants.ALIGN_LEFT); + else if (align.equals("right")) + setJustification(StyleConstants.ALIGN_RIGHT); + else if (align.equals("center")) + setJustification(StyleConstants.ALIGN_CENTER); + else if (align.equals("justify")) + setJustification(StyleConstants.ALIGN_JUSTIFIED); + } - // Fetch StyleSheet's box painter. - painter = getStyleSheet().getBoxPainter(atts); - setInsets((short) painter.getInset(TOP, this), - (short) painter.getInset(LEFT, this), - (short) painter.getInset(BOTTOM, this), - (short) painter.getInset(RIGHT, this)); + // Fetch StyleSheet's box painter. + painter = getStyleSheet().getBoxPainter(attributes); + setInsets((short) painter.getInset(TOP, this), + (short) painter.getInset(LEFT, this), + (short) painter.getInset(BOTTOM, this), + (short) painter.getInset(RIGHT, this)); - // TODO: Handle CSS width and height attributes somehow. + cssWidth = (Length) attributes.getAttribute(CSS.Attribute.WIDTH); + cssHeight = (Length) attributes.getAttribute(CSS.Attribute.WIDTH); + } } /** @@ -169,8 +186,66 @@ public class ParagraphView protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { - // FIXME: Implement the above specified behaviour. - return super.calculateMinorAxisRequirements(axis, r); + r = super.calculateMinorAxisRequirements(axis, r); + if (setCSSSpan(r, axis)) + { + // If we have set the span from CSS, then we need to adjust + // the margins. + SizeRequirements parent = super.calculateMinorAxisRequirements(axis, + null); + int margin = axis == X_AXIS ? getLeftInset() + getRightInset() + : getTopInset() + getBottomInset(); + r.minimum -= margin; + r.preferred -= margin; + r.maximum -= margin; + } + else + { + float min = 0; + int n = getLayoutViewCount(); + for (int i = 0; i < n; i++) + min = Math.max(getLayoutView(i).getMinimumSpan(axis), min); + r.minimum = (int) min; + r.preferred = Math.max(r.preferred, r.minimum); + r.maximum = Math.max(r.maximum, r.preferred); + } + return r; + } + + /** + * Sets the span on the SizeRequirements object according to the + * according CSS span value, when it is set. + * + * @param r the size requirements + * @param axis the axis + * + * @return <code>true</code> when the CSS span has been set, + * <code>false</code> otherwise + */ + private boolean setCSSSpan(SizeRequirements r, int axis) + { + boolean ret = false; + if (axis == X_AXIS) + { + if (cssWidth != null && ! cssWidth.isPercentage()) + { + r.minimum = (int) cssWidth.getValue(); + r.preferred = (int) cssWidth.getValue(); + r.maximum = (int) cssWidth.getValue(); + ret = true; + } + } + else + { + if (cssHeight != null && ! cssWidth.isPercentage()) + { + r.minimum = (int) cssHeight.getValue(); + r.preferred = (int) cssHeight.getValue(); + r.maximum = (int) cssHeight.getValue(); + ret = true; + } + } + return ret; } /** diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java index 703a3864a..add22e01c 100644 --- a/javax/swing/text/html/StyleSheet.java +++ b/javax/swing/text/html/StyleSheet.java @@ -45,21 +45,27 @@ import gnu.javax.swing.text.html.css.FontSize; import gnu.javax.swing.text.html.css.FontStyle; import gnu.javax.swing.text.html.css.FontWeight; import gnu.javax.swing.text.html.css.Length; +import gnu.javax.swing.text.html.css.Selector; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.StringTokenizer; +import javax.swing.border.Border; import javax.swing.event.ChangeListener; import javax.swing.text.AttributeSet; import javax.swing.text.Element; @@ -86,7 +92,7 @@ import javax.swing.text.View; * * The rules are stored as named styles, and other information is stored to * translate the context of an element to a rule. - * + * * @author Lillian Angel (langel@redhat.com) */ public class StyleSheet extends StyleContext @@ -101,21 +107,35 @@ public class StyleSheet extends StyleContext implements CSSParserCallback { /** - * The selector for which the rules are currently parsed. + * The current style. + */ + private CSSStyle style; + + /** + * The precedence of the stylesheet to be parsed. */ - private String[] selector; + private int precedence; + + /** + * Creates a new CSS parser. This parser parses a CSS stylesheet with + * the specified precedence. + * + * @param prec the precedence, according to the constants defined in + * CSSStyle + */ + CSSStyleSheetParserCallback(int prec) + { + precedence = prec; + } /** * Called at the beginning of a statement. * * @param sel the selector */ - public void startStatement(String sel) + public void startStatement(Selector sel) { - StringTokenizer tokens = new StringTokenizer(sel); - selector = new String[tokens.countTokens()]; - for (int index = 0; tokens.hasMoreTokens(); index++) - selector[index] = tokens.nextToken(); + style = new CSSStyle(precedence, sel); } /** @@ -123,7 +143,8 @@ public class StyleSheet extends StyleContext */ public void endStatement() { - selector = null; + css.add(style); + style = null; } /** @@ -134,23 +155,13 @@ public class StyleSheet extends StyleContext */ public void declaration(String property, String value) { - for (int i = 0; i < selector.length; i++) - { - CSSStyle style = (CSSStyle) css.get(selector[i]); - if (style == null) - { - style = new CSSStyle(); - css.put(selector[i], style); - } - CSS.Attribute cssAtt = CSS.getAttribute(property); - Object val = CSS.getValue(cssAtt, value); - if (cssAtt != null) - style.addAttribute(cssAtt, val); - // else // For debugging only. - // System.err.println("no mapping for: " + property); - } + CSS.Attribute cssAtt = CSS.getAttribute(property); + Object val = CSS.getValue(cssAtt, value); + CSS.addInternal(style, cssAtt, value); + if (cssAtt != null) + style.addAttribute(cssAtt, val); } - + } /** @@ -158,9 +169,33 @@ public class StyleSheet extends StyleContext */ private class CSSStyle extends SimpleAttributeSet - implements Style + implements Style, Comparable { + static final int PREC_UA = 400000; + static final int PREC_NORM = 300000; + static final int PREC_AUTHOR_NORMAL = 200000; + static final int PREC_AUTHOR_IMPORTANT = 100000; + static final int PREC_USER_IMPORTANT = 0; + + /** + * The priority of this style when matching CSS selectors. + */ + private int precedence; + + /** + * The selector for this rule. + * + * This is package private to avoid accessor methods. + */ + Selector selector; + + CSSStyle(int prec, Selector sel) + { + precedence = prec; + selector = sel; + } + public String getName() { // TODO: Implement this for correctness. @@ -176,6 +211,17 @@ public class StyleSheet extends StyleContext { // TODO: Implement this for correctness. } + + /** + * Sorts the rule according to the style's precedence and the + * selectors specificity. + */ + public int compareTo(Object o) + { + CSSStyle other = (CSSStyle) o; + return other.precedence + other.selector.getSpecificity() + - precedence - selector.getSpecificity(); + } } @@ -192,7 +238,7 @@ public class StyleSheet extends StyleContext * Maps element names (selectors) to AttributSet (the corresponding style * information). */ - HashMap css = new HashMap(); + ArrayList css = new ArrayList(); /** * Maps selectors to their resolved styles. @@ -371,14 +417,17 @@ public class StyleSheet extends StyleContext // the default.css. int count = tags.length; ArrayList styles = new ArrayList(); - for (int i = 0; i < count; i++) + for (Iterator i = css.iterator(); i.hasNext();) { - Style style = (Style) css.get(tags[i]); - if (style != null) + CSSStyle style = (CSSStyle) i.next(); + if (style.selector.matches(tags, classes, ids)) styles.add(style); - // FIXME: Handle ID and CLASS attributes. } + + // Sort selectors. + Collections.sort(styles); Style[] styleArray = new Style[styles.size()]; + styleArray = (Style[]) styles.toArray(styleArray); Style resolved = new MultiStyle(selector, (Style[]) styles.toArray(styleArray)); resolvedStyles.put(selector, resolved); @@ -395,9 +444,15 @@ public class StyleSheet extends StyleContext */ public Style getRule(String selector) { - // FIXME: This is a very rudimentary implementation. Should - // be extended to conform to the CSS spec. - return (Style) css.get(selector); + Selector sel = new Selector(selector); + CSSStyle best = null; + for (Iterator i = css.iterator(); i.hasNext();) + { + CSSStyle style = (CSSStyle) i.next(); + if (style.compareTo(best) < 0) + best = style; + } + return best; } /** @@ -408,7 +463,8 @@ public class StyleSheet extends StyleContext */ public void addRule(String rule) { - CSSStyleSheetParserCallback cb = new CSSStyleSheetParserCallback(); + CSSStyleSheetParserCallback cb = + new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL); // FIXME: Handle ref. StringReader in = new StringReader(rule); CSSParser parser = new CSSParser(in, cb); @@ -419,7 +475,7 @@ public class StyleSheet extends StyleContext catch (IOException ex) { // Shouldn't happen. And if, then we - assert false; + System.err.println("IOException while parsing stylesheet: " + ex.getMessage()); } } @@ -451,7 +507,8 @@ public class StyleSheet extends StyleContext public void loadRules(Reader in, URL ref) throws IOException { - CSSStyleSheetParserCallback cb = new CSSStyleSheetParserCallback(); + CSSStyleSheetParserCallback cb = + new CSSStyleSheetParserCallback(CSSStyle.PREC_UA); // FIXME: Handle ref. CSSParser parser = new CSSParser(in, cb); parser.parse(); @@ -543,13 +600,26 @@ public class StyleSheet extends StyleContext /** * Imports a style sheet from the url. The rules are directly added to the - * receiver. + * receiver. This is usually called when a <link> tag is resolved in an + * HTML document. * - * @param url - the URL to import the StyleSheet from. + * @param url the URL to import the StyleSheet from */ public void importStyleSheet(URL url) { - // FIXME: Not implemented + try + { + InputStream in = url.openStream(); + Reader r = new BufferedReader(new InputStreamReader(in)); + CSSStyleSheetParserCallback cb = + new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL); + CSSParser parser = new CSSParser(r, cb); + parser.parse(); + } + catch (IOException ex) + { + // We can't do anything about it I guess. + } } /** @@ -585,6 +655,7 @@ public class StyleSheet extends StyleContext String value) { Object val = CSS.getValue(key, value); + CSS.addInternal(attr, key, value); attr.addAttribute(key, val); } @@ -615,11 +686,31 @@ public class StyleSheet extends StyleContext */ public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) { - // FIXME: Really convert HTML to CSS here. AttributeSet cssAttr = htmlAttrSet.copyAttributes(); - MutableAttributeSet cssStyle = addStyle(null, null); - cssStyle.addAttributes(cssAttr); - return cssStyle; + + // The HTML align attribute maps directly to the CSS text-align attribute. + Object o = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.TEXT_ALIGN, o); + + // The HTML width attribute maps directly to CSS width. + o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH, + CSS.getValue(CSS.Attribute.WIDTH, o.toString())); + + // The HTML height attribute maps directly to CSS height. + o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT, + CSS.getValue(CSS.Attribute.HEIGHT, o.toString())); + + o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap"); + + // TODO: Add more mappings. + return cssAttr; } /** @@ -802,7 +893,7 @@ public class StyleSheet extends StyleContext */ public BoxPainter getBoxPainter(AttributeSet a) { - return new BoxPainter(a); + return new BoxPainter(a, this); } /** @@ -813,7 +904,7 @@ public class StyleSheet extends StyleContext */ public ListPainter getListPainter(AttributeSet a) { - return new ListPainter(a); + return new ListPainter(a, this); } /** @@ -920,17 +1011,42 @@ public class StyleSheet extends StyleContext public static class BoxPainter extends Object implements Serializable { + /** + * The left inset. + */ private float leftInset; + + /** + * The right inset. + */ private float rightInset; + + /** + * The top inset. + */ private float topInset; + + /** + * The bottom inset. + */ private float bottomInset; /** + * The border of the box. + */ + private Border border; + + /** + * The background color. + */ + private Color background; + + /** * Package-private constructor. * * @param as - AttributeSet for painter */ - BoxPainter(AttributeSet as) + BoxPainter(AttributeSet as, StyleSheet ss) { Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT); if (l != null) @@ -944,6 +1060,13 @@ public class StyleSheet extends StyleContext l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM); if (l != null) bottomInset = l.getValue(); + + // Determine border. + border = new CSSBorder(as); + + // Determine background. + background = ss.getBackground(as); + } @@ -965,15 +1088,23 @@ public class StyleSheet extends StyleContext { case View.TOP: inset = topInset; + if (border != null) + inset += border.getBorderInsets(null).top; break; case View.BOTTOM: inset = bottomInset; + if (border != null) + inset += border.getBorderInsets(null).bottom; break; case View.LEFT: inset = leftInset; + if (border != null) + inset += border.getBorderInsets(null).left; break; case View.RIGHT: inset = rightInset; + if (border != null) + inset += border.getBorderInsets(null).right; break; default: inset = 0.0F; @@ -994,7 +1125,16 @@ public class StyleSheet extends StyleContext */ public void paint(Graphics g, float x, float y, float w, float h, View v) { - // FIXME: Not implemented. + + if (background != null) + { + g.setColor(background); + g.fillRect((int) x, (int) y, (int) w, (int) h); + } + if (border != null) + { + border.paintBorder(null, g, (int) x, (int) y, (int) w, (int) h); + } } } @@ -1005,24 +1145,36 @@ public class StyleSheet extends StyleContext * * @author Lillian Angel (langel@redhat.com) */ - public static class ListPainter extends Object implements Serializable + public static class ListPainter implements Serializable { - + /** * Attribute set for painter */ - AttributeSet as; - + private AttributeSet attributes; + + /** + * The associated style sheet. + */ + private StyleSheet styleSheet; + + /** + * The bullet type. + */ + private String type; + /** * Package-private constructor. * * @param as - AttributeSet for painter */ - ListPainter(AttributeSet as) + ListPainter(AttributeSet as, StyleSheet ss) { - this.as = as; + attributes = as; + styleSheet = ss; + type = (String) as.getAttribute(CSS.Attribute.LIST_STYLE_TYPE); } - + /** * Paints the CSS list decoration according to the attributes given. * @@ -1037,7 +1189,19 @@ public class StyleSheet extends StyleContext public void paint(Graphics g, float x, float y, float w, float h, View v, int item) { - // FIXME: Not implemented. + // FIXME: This is a very simplistic list rendering. We still need + // to implement different bullet types (see type field) and custom + // bullets via images. + View itemView = v.getView(item); + AttributeSet viewAtts = itemView.getAttributes(); + Object tag = viewAtts.getAttribute(StyleConstants.NameAttribute); + // Only paint something here when the child view is an LI tag + // and the calling view is some of the list tags then). + if (tag != null && tag == HTML.Tag.LI) + { + g.setColor(Color.BLACK); + g.fillOval((int) x - 15, (int) (h / 2 - 3 + y), 6, 6); + } } } diff --git a/javax/swing/text/html/TableView.java b/javax/swing/text/html/TableView.java index c2edc8cdd..2bd11ffcf 100644 --- a/javax/swing/text/html/TableView.java +++ b/javax/swing/text/html/TableView.java @@ -38,49 +38,185 @@ exception statement from your version. */ package javax.swing.text.html; -import javax.swing.text.Document; +import gnu.javax.swing.text.html.css.Length; + +import javax.swing.SizeRequirements; +import javax.swing.text.AttributeSet; +import javax.swing.text.BoxView; import javax.swing.text.Element; +import javax.swing.text.StyleConstants; import javax.swing.text.View; import javax.swing.text.ViewFactory; /** - * A conrete implementation of TableView that renders HTML tables. - * - * @author Roman Kennke (kennke@aicas.com) + * A view implementation that renders HTML tables. + * + * This is basically a vertical BoxView that contains the rows of the table + * and the rows are horizontal BoxViews that contain the actual columns. */ class TableView - extends javax.swing.text.TableView + extends BoxView + implements ViewFactory { + /** * Represents a single table row. */ - public class RowView extends TableRow + class RowView + extends BlockView { /** - * Creates a new instance of the <code>RowView</code>. + * Creates a new RowView. * - * @param el the element for which to create a row view + * @param el the element for the row view + */ + RowView(Element el) + { + super(el, X_AXIS); + } + + /** + * Overridden to make rows not resizable along the Y axis. + */ + public float getMaximumSpan(int axis) + { + float span; + if (axis == Y_AXIS) + span = super.getPreferredSpan(axis); + else + span = super.getMaximumSpan(axis); + return span; + } + + /** + * Calculates the overall size requirements for the row along the + * major axis. This will be the sum of the column requirements. + */ + protected SizeRequirements calculateMajorAxisRequirements(int axis, + SizeRequirements r) + { + if (r == null) + r = new SizeRequirements(); + r.minimum = totalColumnRequirements.minimum; + r.preferred = totalColumnRequirements.preferred; + r.maximum = totalColumnRequirements.maximum; + r.alignment = 0.0F; + return r; + } + + /** + * Lays out the columns in this row. */ - public RowView(Element el) + protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, + int spans[]) { - super(el); + int numCols = offsets.length; + int realColumn = 0; + for (int i = 0; i < numCols; i++) + { + View v = getView(i); + if (v instanceof CellView) + { + CellView cv = (CellView) v; + offsets[i] = columnOffsets[realColumn]; + spans[i] = 0; + for (int j = 0; j < cv.colSpan; j++, realColumn++) + { + spans[i] += columnSpans[realColumn]; + } + } + } } - + } + /** - * Get the associated style sheet from the document. - * - * @return the associated style sheet. + * A view that renders HTML table cells (TD and TH tags). */ - protected StyleSheet getStyleSheet() + class CellView + extends BlockView + { + + /** + * The number of columns that this view spans. + */ + int colSpan; + + /** + * Creates a new CellView for the specified element. + * + * @param el the element for which to create the colspan + */ + CellView(Element el) { - Document d = getElement().getDocument(); - if (d instanceof HTMLDocument) - return ((HTMLDocument) d).getStyleSheet(); - else - return null; - } + super(el, Y_AXIS); + } + + /** + * Overridden to fetch the columnSpan attibute. + */ + protected void setPropertiesFromAttributes() + { + super.setPropertiesFromAttributes(); + colSpan = 1; + AttributeSet atts = getAttributes(); + Object o = atts.getAttribute(HTML.Attribute.COLSPAN); + if (o != null) + { + try + { + colSpan = Integer.parseInt(o.toString()); + } + catch (NumberFormatException ex) + { + // Couldn't parse the colspan, assume 1. + colSpan = 1; + } + } + } } + + /** + * The attributes of this view. + */ + private AttributeSet attributes; + + /** + * The column requirements. + */ + private SizeRequirements[] columnRequirements; + + /** + * The overall requirements across all columns. + * + * Package private to avoid accessor methods. + */ + SizeRequirements totalColumnRequirements; + + /** + * The column layout, offsets. + * + * Package private to avoid accessor methods. + */ + int[] columnOffsets; + + /** + * The column layout, spans. + * + * Package private to avoid accessor methods. + */ + int[] columnSpans; + + /** + * The widths of the columns that have been explicitly specified. + */ + Length[] columnWidths; + + /** + * Indicates if the grid setup is ok. + */ + private boolean gridValid; + /** * Creates a new HTML table view for the specified element. * @@ -88,50 +224,424 @@ class TableView */ public TableView(Element el) { - super(el); + super(el, Y_AXIS); + totalColumnRequirements = new SizeRequirements(); } - + /** - * Get the associated style sheet from the document. - * - * @return the associated style sheet. + * Implementation of the ViewFactory interface for creating the + * child views correctly. */ - protected StyleSheet getStyleSheet() + public View create(Element elem) { - Document d = getElement().getDocument(); - if (d instanceof HTMLDocument) - return ((HTMLDocument) d).getStyleSheet(); - else - return null; - } - + View view = null; + AttributeSet atts = elem.getAttributes(); + Object name = atts.getAttribute(StyleConstants.NameAttribute); + if (name instanceof HTML.Tag) + { + HTML.Tag tag = (HTML.Tag) name; + if (tag == HTML.Tag.TR) + view = new RowView(elem); + else if (tag == HTML.Tag.TD || tag == HTML.Tag.TH) + view = new CellView(elem); + else if (tag == HTML.Tag.CAPTION) + view = new ParagraphView(elem); + } + + // If we haven't mapped the element, then fall back to the standard + // view factory. + if (view == null) + { + View parent = getParent(); + if (parent != null) + { + ViewFactory vf = parent.getViewFactory(); + if (vf != null) + view = vf.create(elem); + } + } + return view; + } + /** - * Creates a view for a table row. - * - * @param el the element that represents the table row - * @return a view for rendering the table row - * (and instance of {@link RowView}). + * Returns this object as view factory so that we get our TR, TD, TH + * and CAPTION subelements created correctly. */ - protected TableRow createTableRow(Element el) + public ViewFactory getViewFactory() { - return new RowView(el); - } - + return this; + } + /** - * Loads the children of the Table. This completely bypasses the ViewFactory - * and creates instances of TableRow instead. + * Returns the attributes of this view. This is overridden to provide + * the attributes merged with the CSS stuff. + */ + public AttributeSet getAttributes() + { + if (attributes == null) + attributes = getStyleSheet().getViewAttributes(this); + return attributes; + } + + /** + * Returns the stylesheet associated with this view. * - * @param vf ignored + * @return the stylesheet associated with this view */ - protected void loadChildren(ViewFactory vf) + private StyleSheet getStyleSheet() { - Element el = getElement(); - int numChildren = el.getElementCount(); - View[] rows = new View[numChildren]; - for (int i = 0; i < numChildren; ++i) + HTMLDocument doc = (HTMLDocument) getDocument(); + return doc.getStyleSheet(); + } + + /** + * Overridden to calculate the size requirements according to the + * columns distribution. + */ + protected SizeRequirements calculateMinorAxisRequirements(int axis, + SizeRequirements r) + { + updateGrid(); + calculateColumnRequirements(); + + // Calculate the horizontal requirements according to the superclass. + // This will return the maximum of the row's widths. + r = super.calculateMinorAxisRequirements(axis, r); + + // Try to set the CSS width if it fits. + AttributeSet atts = getAttributes(); + Length l = (Length) atts.getAttribute(CSS.Attribute.WIDTH); + if (l != null) + { + int width = (int) l.getValue(); + if (r.minimum < width) + r.minimum = width; + } + + // Apply the alignment. + Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN); + r.alignment = 0.0F; + if (o != null) { - rows[i] = createTableRow(el.getElement(i)); + String al = o.toString(); + if (al.equals("left")) + r.alignment = 0.0F; + else if (al.equals("center")) + r.alignment = 0.5F; + else if (al.equals("right")) + r.alignment = 1.0F; } - replace(0, getViewCount(), rows); + + return r; + } + + /** + * Overridden to perform the table layout before calling the super + * implementation. + */ + protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, + int[] spans) + { + updateGrid(); + layoutColumns(targetSpan); + super.layoutMinorAxis(targetSpan, axis, offsets, spans); + } + + /** + * Calculates the size requirements for the columns. + */ + private void calculateColumnRequirements() + { + int numRows = getViewCount(); + totalColumnRequirements.minimum = 0; + totalColumnRequirements.preferred = 0; + totalColumnRequirements.maximum = 0; + + // In this first pass we find out a suitable total width to fit in + // all columns of all rows. + for (int r = 0; r < numRows; r++) + { + RowView rowView = (RowView) getView(r); + int numCols = rowView.getViewCount(); + + // We collect the normal (non-relative) column requirements in the + // total variable and the relative requirements in the relTotal + // variable. In the end we create the maximum of both to get the + // real requirements. + SizeRequirements total = new SizeRequirements(); + SizeRequirements relTotal = new SizeRequirements(); + float totalPercent = 0.F; + for (int c = 0; c < numCols; ) + { + View v = rowView.getView(c); + if (v instanceof CellView) + { + CellView cellView = (CellView) v; + int colSpan = cellView.colSpan; + if (colSpan > 1) + { + int cellMin = (int) cellView.getMinimumSpan(X_AXIS); + int cellPref = (int) cellView.getPreferredSpan(X_AXIS); + int cellMax = (int) cellView.getMaximumSpan(X_AXIS); + int currentMin = 0; + int currentPref = 0; + long currentMax = 0; + for (int i = 0; i < colSpan; i++) + { + SizeRequirements req = columnRequirements[c + i]; + currentMin += req.minimum; + currentPref += req.preferred; + currentMax += req.maximum; + } + int deltaMin = cellMin - currentMin; + int deltaPref = cellPref - currentPref; + int deltaMax = (int) (cellMax - currentMax); + // Distribute delta. + for (int i = 0; i < colSpan; i++) + { + SizeRequirements req = columnRequirements[c + i]; + if (deltaMin > 0) + req.minimum += deltaMin / colSpan; + if (deltaPref > 0) + req.preferred += deltaPref / colSpan; + if (deltaMax > 0) + req.maximum += deltaMax / colSpan; + if (columnWidths[c + i] == null + || ! columnWidths[c + i].isPercentage()) + { + total.minimum += req.minimum; + total.preferred += req.preferred; + total.maximum += req.maximum; + } + else + { + relTotal.minimum = + Math.max(relTotal.minimum, + (int) (req.minimum + * columnWidths[c + i].getValue())); + relTotal.preferred = + Math.max(relTotal.preferred, + (int) (req.preferred + * columnWidths[c + i].getValue())); + relTotal.maximum = + Math.max(relTotal.maximum, + (int) (req.maximum + * columnWidths[c + i].getValue())); + totalPercent += columnWidths[c + i].getValue(); + } + } + } + else + { + // Shortcut for colSpan == 1. + SizeRequirements req = columnRequirements[c]; + req.minimum = Math.max(req.minimum, + (int) cellView.getMinimumSpan(X_AXIS)); + req.preferred = Math.max(req.preferred, + (int) cellView.getPreferredSpan(X_AXIS)); + req.maximum = Math.max(req.maximum, + (int) cellView.getMaximumSpan(X_AXIS)); + if (columnWidths[c] == null + || ! columnWidths[c].isPercentage()) + { + total.minimum += columnRequirements[c].minimum; + total.preferred += columnRequirements[c].preferred; + total.maximum += columnRequirements[c].maximum; + } + else + { + relTotal.minimum = + Math.max(relTotal.minimum, + (int) (req.minimum + / columnWidths[c].getValue())); + relTotal.preferred = + Math.max(relTotal.preferred, + (int) (req.preferred + / columnWidths[c].getValue())); + relTotal.maximum = + Math.max(relTotal.maximum, + (int) (req.maximum + / columnWidths[c].getValue())); + totalPercent += columnWidths[c].getValue(); + } + } + c += colSpan; + } + else + c++; + } + + // Update the total requirements as follows: + // 1. Multiply the absolute requirements with 1 - totalPercent. This + // gives the total requirements based on the wishes of the absolute + // cells. + // 2. Take the maximum of this value and the total relative + // requirements. Now we should have enough space for whatever cell + // in this column. + // 3. Take the maximum of this value and the previous maximum value. + total.minimum *= 1.F / (1.F - totalPercent); + total.preferred *= 1.F / (1.F - totalPercent); + total.maximum *= 1.F / (1.F - totalPercent); + + int rowTotalMin = Math.max(total.minimum, relTotal.minimum); + int rowTotalPref = Math.max(total.preferred, relTotal.preferred); + int rowTotalMax = Math.max(total.maximum, relTotal.maximum); + totalColumnRequirements.minimum = + Math.max(totalColumnRequirements.minimum, rowTotalMin); + totalColumnRequirements.preferred = + Math.max(totalColumnRequirements.preferred, rowTotalPref); + totalColumnRequirements.maximum = + Math.max(totalColumnRequirements.maximum, rowTotalMax); + } + + // Now we know what we want and can fix up the actual relative + // column requirements. + int numCols = columnRequirements.length; + for (int i = 0; i < numCols; i++) + { + if (columnWidths[i] != null) + { + columnRequirements[i].minimum = (int) + columnWidths[i].getValue(totalColumnRequirements.minimum); + columnRequirements[i].preferred = (int) + columnWidths[i].getValue(totalColumnRequirements.preferred); + columnRequirements[i].maximum = (int) + columnWidths[i].getValue(totalColumnRequirements.maximum); + } + } + } + + /** + * Lays out the columns. + * + * @param targetSpan the target span into which the table is laid out + */ + private void layoutColumns(int targetSpan) + { + // Set the spans to the preferred sizes. Determine the space + // that we have to adjust the sizes afterwards. + long sumPref = 0; + int n = columnRequirements.length; + for (int i = 0; i < n; i++) + { + SizeRequirements col = columnRequirements[i]; + if (columnWidths[i] != null) + columnSpans[i] = (int) columnWidths[i].getValue(targetSpan); + else + columnSpans[i] = col.preferred; + sumPref += columnSpans[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++) + { + // Only adjust the width if we haven't set a column width here. + if (columnWidths[i] == null) + { + SizeRequirements col = columnRequirements[i]; + int span; + if (diff < 0) + { + span = col.minimum; + diffs[i] = columnSpans[i] - span; + } + else + { + span = col.maximum; + diffs[i] = span - columnSpans[i]; + } + total += span; + } + else + total += columnSpans[i]; + } + + 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++) + { + columnOffsets[i] = totalOffs; + if (diff != 0) + { + float adjust = factor * diffs[i]; + columnSpans[i] += Math.round(adjust); + } + // Avoid overflow here. + totalOffs = (int) Math.min((long) totalOffs + (long) columnSpans[i], + Integer.MAX_VALUE); + } + } + + /** + * Updates the arrays that contain the row and column data in response + * to a change to the table structure. + */ + private void updateGrid() + { + if (! gridValid) + { + int maxColumns = 0; + int numRows = getViewCount(); + for (int r = 0; r < numRows; r++) + { + RowView rowView = (RowView) getView(r); + int numCols = rowView.getViewCount(); + maxColumns = Math.max(numCols, maxColumns); + } + columnWidths = new Length[maxColumns]; + for (int r = 0; r < numRows; r++) + { + RowView rowView = (RowView) getView(r); + int numCols = rowView.getViewCount(); + int colIndex = 0; + for (int c = 0; c < numCols; c++) + { + View v = rowView.getView(c); + if (v instanceof CellView) + { + CellView cv = (CellView) v; + Object o = + cv.getAttributes().getAttribute(CSS.Attribute.WIDTH); + if (o != null && columnWidths[colIndex] == null + && o instanceof Length) + columnWidths[colIndex]= (Length) o; + colIndex += cv.colSpan; + } + } + } + columnRequirements = new SizeRequirements[maxColumns]; + for (int i = 0; i < maxColumns; i++) + columnRequirements[i] = new SizeRequirements(); + columnOffsets = new int[maxColumns]; + columnSpans = new int[maxColumns]; + + gridValid = true; + } + } + + /** + * Overridden to restrict the table width to the preferred size. + */ + public float getMaximumSpan(int axis) + { + float span; + if (axis == X_AXIS) + span = super.getPreferredSpan(axis); + else + span = super.getMaximumSpan(axis); + return span; } } diff --git a/javax/swing/text/html/parser/DocumentParser.java b/javax/swing/text/html/parser/DocumentParser.java index 062606d17..f717d69cb 100644 --- a/javax/swing/text/html/parser/DocumentParser.java +++ b/javax/swing/text/html/parser/DocumentParser.java @@ -38,13 +38,13 @@ exception statement from your version. */ package javax.swing.text.html.parser; -import gnu.javax.swing.text.html.parser.htmlAttributeSet; import javax.swing.text.html.parser.Parser; import java.io.IOException; import java.io.Reader; import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.html.HTMLEditorKit; /** @@ -117,7 +117,7 @@ public class DocumentParser protected final void handleStartTag(TagElement tag) { parser.handleStartTag(tag); - htmlAttributeSet attributes = gnu.getAttributes(); + SimpleAttributeSet attributes = gnu.getAttributes(); if (tag.fictional()) attributes.addAttribute(HTMLEditorKit.ParserCallback.IMPLIED, diff --git a/javax/swing/text/html/parser/ParserDelegator.java b/javax/swing/text/html/parser/ParserDelegator.java index 70636d929..cdd339b8f 100644 --- a/javax/swing/text/html/parser/ParserDelegator.java +++ b/javax/swing/text/html/parser/ParserDelegator.java @@ -38,13 +38,13 @@ exception statement from your version. */ package javax.swing.text.html.parser; import gnu.javax.swing.text.html.parser.HTML_401F; -import gnu.javax.swing.text.html.parser.htmlAttributeSet; import java.io.IOException; import java.io.Reader; import java.io.Serializable; import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit.ParserCallback; @@ -93,7 +93,7 @@ public class ParserDelegator protected final void handleStartTag(TagElement tag) { - htmlAttributeSet attributes = gnu.getAttributes(); + SimpleAttributeSet attributes = gnu.getAttributes(); if (tag.fictional()) attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE); |