summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2006-12-03 17:06:05 +0000
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2006-12-03 17:06:05 +0000
commit995a16ee911442342a73cce6a4e1761cc8bd1f81 (patch)
tree9eb07e047ec678c09034c38c2ff728b622774a9b
parent306a965fe7e642bfb08eeeecfed9bd61ed857db9 (diff)
downloadclasspath-995a16ee911442342a73cce6a4e1761cc8bd1f81.tar.gz
2006-12-03 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD-->generics-branch for 2006/11/29 to 0.93 branch point.
-rw-r--r--.externalToolBuilders/ClasspathJar.launch4
-rw-r--r--ChangeLog236
-rw-r--r--gnu/java/awt/peer/gtk/BufferedImageGraphics.java72
-rw-r--r--gnu/java/awt/peer/gtk/CairoGraphics2D.java11
-rw-r--r--gnu/javax/swing/text/html/css/BorderStyle.java64
-rw-r--r--gnu/javax/swing/text/html/css/BorderWidth.java12
-rw-r--r--gnu/javax/swing/text/html/css/FontSize.java8
-rw-r--r--gnu/javax/swing/text/html/css/Length.java155
-rw-r--r--gnu/javax/swing/text/html/css/Selector.java17
-rw-r--r--gnu/javax/swing/text/html/parser/support/Parser.java40
-rw-r--r--include/gnu_java_awt_peer_gtk_GdkFontPeer.h16
-rw-r--r--java/beans/beancontext/BeanContextServicesSupport.java39
-rw-r--r--java/lang/Thread.java8
-rw-r--r--java/text/DecimalFormat.java172
-rw-r--r--javax/swing/text/ElementIterator.java203
-rw-r--r--javax/swing/text/html/BlockView.java17
-rw-r--r--javax/swing/text/html/CSS.java173
-rw-r--r--javax/swing/text/html/CSSBorder.java19
-rw-r--r--javax/swing/text/html/FormSubmitEvent.java123
-rw-r--r--javax/swing/text/html/FormView.java357
-rw-r--r--javax/swing/text/html/FrameSetView.java274
-rw-r--r--javax/swing/text/html/FrameView.java233
-rw-r--r--javax/swing/text/html/HTML.java10
-rw-r--r--javax/swing/text/html/HTMLDocument.java301
-rw-r--r--javax/swing/text/html/HTMLEditorKit.java123
-rw-r--r--javax/swing/text/html/ImageView.java56
-rw-r--r--javax/swing/text/html/InlineView.java2
-rw-r--r--javax/swing/text/html/ParagraphView.java7
-rw-r--r--javax/swing/text/html/StyleSheet.java178
-rw-r--r--javax/swing/text/html/TableView.java43
30 files changed, 2631 insertions, 342 deletions
diff --git a/.externalToolBuilders/ClasspathJar.launch b/.externalToolBuilders/ClasspathJar.launch
index e58a58b3a..269e62c0e 100644
--- a/.externalToolBuilders/ClasspathJar.launch
+++ b/.externalToolBuilders/ClasspathJar.launch
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="true"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;launchConfigurationWorkingSet factoryID=&quot;org.eclipse.ui.internal.WorkingSetFactory&quot; name=&quot;workingSet&quot;&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/classpath/install/share/classpath&quot; type=&quot;2&quot;/&gt;&#10;&lt;/launchConfigurationWorkingSet&gt;}"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-cf glibj.zip META-INF java gnu org javax vm"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;launchConfigurationWorkingSet editPageId=&quot;org.eclipse.ui.resourceWorkingSetPage&quot; factoryID=&quot;org.eclipse.ui.internal.WorkingSetFactory&quot; label=&quot;workingSet&quot; name=&quot;workingSet&quot;&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/classpath/install/share/classpath&quot; type=&quot;2&quot;/&gt;&#10;&lt;/launchConfigurationWorkingSet&gt;}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-cf glibj.zip META-INF java gnu org javax vm sun"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${build_project:install/share/classpath}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${system_path:jar}"/>
diff --git a/ChangeLog b/ChangeLog
index 9d587fd59..5acb9eae6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,239 @@
+2006-12-01 Mark Wielaard <mark@klomp.org>
+
+ * java/text/DecimalFormat.java (parse): Always increment parsing
+ index and adjust pos result.
+
+2006-12-01 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/HTML.java
+ (Attribute.DYNAMIC_CLASS): New field.
+ (Attribute.PSEUDO_CLASS): New field.
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.CharacterAction.start): Initialize anchor with link
+ pseudo attribute.
+ (updateSpecialClass): New helper method. Updates the dynamic
+ or pseudo class for anchor tags.
+ * javax/swing/text/html/HTMLEditorKit.java
+ (LinkController.lastAnchorElement): New field. For tracking
+ enter/exit of anchors.
+ (LinkController.activateLink): Set pseudo class to 'visited'.
+ (LinkController.mouseMoved): Added support for tracking
+ the 'hover' dynamic class.
+ * javax/swing/text/html/InlineView.java
+ (changedUpdate): Fetch new properties.
+ * javax/swing/text/html/StyleSheet.java
+ (attributeSetToMap): New helper method.
+ (getRule): Also append dynamic and pseudo class to key.
+ (resolveStyle): Resolve style based generally on all attributes.
+ * javax/swing/text/html/TableView.java
+ (RowView.layoutMajorAxis): Make sure the grid is valid.
+ (updateGrid): Made package private.
+ * gnu/javax/swing/text/html/css/Selector.java
+ (calculateSpecificity): Added support for dynamic and pseudo classes.
+ (matches): Changed to operate on general attributes.
+ Added support for dynamic and pseudo classes.
+
+2006-12-01 Mario Torre <neugens@limasoftware.net>
+
+ * java/text/DecimalFormat.java (formatInternal): move the formatting of
+ fractional portion in a separate method.
+ Also fixes the handling of decimal separator and its associated field.
+ (handleFractionalPart): new method, needed to relax a bit
+ formatInternal.
+
+2006-12-01 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ * java/beans/beancontext/BeanContextServicesSupport.java:
+ (BCSSProxyServiceProvider.getCurrentServiceSelectors(BeanContextServices,
+ Class)): Implemented.
+ (BCSSProxyServiceProvider.getService(BeanContextServices, Object,
+ Class, Object)): Implemented.
+ (BCSSProxyServiceProvider.releaseService(BeanContextServices,
+ Object, Object)): Implemented.
+ (BCSSProxyServiceProvider.serviceRevoked(BeanContextServiceRevokedEvent)):
+ Implemented.
+ (initialiseBeanContextResources()): Implemented.
+ (releaseBeanContextResoures()): Implemented.
+
+2006-12-01 Mark Wielaard <mark@klomp.org>
+
+ * include/gnu_java_awt_peer_gtk_GdkFontPeer.h: Regenerated.
+
+2006-12-01 Roman Kennke <kennke@aicas.com>
+
+ * gnu/javax/swing/text/html/css/BorderStyle.java: New class for
+ handling border styles.
+ * gnu/javax/swing/text/html/css/BorderWidth.java
+ (isValid): New method.
+ * gnu/javax/swing/text/html/css/Length.java
+ (isValid): New method.
+ * javax/swing/text/html/CSS.java
+ (addInternal): Added shorthand parsing for border, padding and
+ margin.
+ (parseBackgroundShorthand): Added API docs.
+ (parsePaddingShorthand): New method. Handles padding shorthand
+ values.
+ (parseMarginShorthand): New method. Handles margin shorthand
+ values.
+ (parseBorderShorthand): New method. Handles border shorthand
+ values.
+ * javax/swing/text/html/StyleSheet.java
+ (translateHTMLToCSS): Set specific padding attributes.
+ (BoxPainter.BoxPainter): Don't handle PADDING and MARGIN here.
+ These shorthands are now handled in CSS.
+ (BoxPainter.paint): Exclude the outer margin.
+
+2006-12-01 Roman Kennke <kennke@aicas.com>
+
+ * gnu/javax/swing/text/html/css/Length.java
+ (emBase): New field.
+ (exBase): New field.
+ (isFontEMRelative): New field.
+ (isFontEXRelative): New field.
+ (Length): Recognize and setup EM and EX relative values.
+ (getValue): Handle EM and EX relative values.
+ (isEMRelative): New method.
+ (isEXRelative): New method.
+ (setEMBase): New method.
+ (setEXBase): New method.
+ (setFontBases): New method.
+ * gnu/javax/swing/text/html/parser/support/Parser.java
+ (_handleEmptyTag): Use new isBlock() helper method.
+ (_handleEndTag_remaining): Use new isBlock() helper method.
+ (_handleStartTag): Consume whitespace after block start tag.
+ (Comment): Consume whitespace after a comment.
+ (isBlock): New helper method.
+ (readAttributes): Consider all characters in unquoted attribute
+ values.
+ * javax/swing/text/html/BlockView.java
+ (layoutMinorAxis): Use cached span value.
+ (paint): Added debug code (commented out).
+ (setPropertiesFromAttributes): Set the EM and EX base on lengths.
+ * javax/swing/text/html/CSSBorder.java
+ (CSSBorder): Take StyleSheet as argument. Call getBorderWidth()
+ with stylesheet.
+ (getBorderWidth): Set the EM and EX base on the length values.
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.ParagraphAction.end): Do not set the inParagraph field.
+ (HTMLReader.ParagraphAction.start): Do not set the inParagraph field.
+ (HTMLReader.inImpliedParagraph): Removed.
+ (HTMLReader.inParagraph): Removed.
+ (HTMLReader.parseStack): New field.
+ (HTMLReader.addContent): Use new paragraph handling.
+ (HTMLReader.addSpecialElement): Use new paragraph handling.
+ (HTMLReader.blockClose): Use new paragraph handling.
+ (HTMLReader.blockOpen): Use new paragraph handling.
+ (HTMLReader.inImpliedParagraph): New helper method.
+ (HTMLReader.inParagraph): New helper method.
+ * javax/swing/text/html/ImageView.java
+ (attributes): New field. Caches view attributes.
+ (spans): New field. Caches CSS spans.
+ (getAttributes): Correctly setup CSS view attributes.
+ (getPreferredSpan): Use caches spans.
+ (getStyleSheet): Use the view's getDocument() method.
+ (setPropertiesFromAttributes): Cache spans and setup EM and EX.
+ (updateSize): Use cached spans.
+ * javax/swing/text/html/ParagraphView.java
+ (setPropertiesFromAttributes): Setup EM and EX.
+ * javax/swing/text/html/StyleSheet.java
+ (BoxPainter.BoxPainter): Setup EM and EX correctly.
+ (getEMBase): New helper method.
+ (getEXBase): New helper method.
+ * javax/swing/text/html/TableView.java
+ (width): New field. Caches the table width.
+ (calculateMinorAxisRequirements): Use caches span.
+ (setPropertiesFromAttributes): Cache span and setup EM/EX.
+ (updateGrid): Correctly setup EM/EX.
+
+2006-11-30 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/FormSubmitEvent.java: New class.
+ * javax/swing/text/html/FormView.java
+ (SubmitThread): New class for submitting data in a separate thread.
+ (actionPerformed): Fetch the actual for data.
+ (addData): New helper method.
+ (getElementFormData): New helper method.
+ (getFormData): New helper method.
+ (getInputFormData): New helper method.
+ (submitData): Implemented.
+ * javax/swing/text/html/FrameView.java
+ (createComponent): Add this as hyperlink listener.
+ Set the target document as frame document.
+ (getTopEditorPane): New helper method.
+ (hyperlinkUpdate): Implementation of the HyperlinkListener interface.
+ (handleHyperlinkEvent): New helper method.
+ (handleFormSubmitEvent): New helper method.
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.BaseAction.start): Track the base target.
+ (HTMLReader.BaseAction.end): Removed.
+ (baseTarget): New field.
+ (frameDocument): New field.
+ (getBaseTarget): New property accessor.
+ (isFrameDocument): New property accessor.
+ (processHTMLFrameHyperlinkEvent): Implemented.
+ (setFrameDocument): New property accessor.
+ (updateFrame): New helper method.
+ (updateFrameSet): New helper method.
+ * javax/swing/text/html/HTMLEditorKit.java
+ (LinkController.createHyperlinkEvent): Handle frame documents.
+ (autoFormSubmission): New field.
+ (HTMLEditorKit): Set autoFormSubmission to true.
+ (isAutoFormSubmission): New property accessor.
+ (setAutoFormSubmission): New property accessor.
+
+2006-11-30 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/ElementIterator.java
+ (ElementRef): New inner class.
+ (currentDepth): Removed.
+ (currentElement): Removed.
+ (previousItem): Removed.
+ (stack): New field. Holds the iteration stack.
+ (state): Removed.
+ (ElementIterator(Document)): Removed init of removed fields.
+ (ElementIterator(Element)): Removed init of removed fields.
+ (current): Changed to stack based algorithm.
+ (deepestLeaf): New helper method.
+ (depth): Changed to stack based algorithm.
+ (first): Changed to stack based algorithm.
+ (next): Changed to stack based algorithm.
+ (previous): Changed to stack based algorithm.
+
+2006-11-30 Francis Kung <fkung@redhat.com>
+
+ * .settings/org.eclipse.jdt.core.prefs: Set compilar compliance to 1.4.
+ * .externalToolBuilders/ClasspathJar.launch: Include sun.* classses.
+
+2006-11-30 Francis Kung <fkung@redhat.com>
+
+ * gnu/java/awt/peer/gtk/BufferedImageGraphics.java
+ (draw): Set transform in buffered composite.
+ (drawComposite): Do not transform bounds; round bounds.
+ (drawGlyphVector): Set transform in buffered composite.
+ (drawRenderedImage): Set transform in buffered composite.
+ (fill): Set transform in buffered composite.
+ (updateBufferedImage): Fix scanline & height calculations.
+ * gnu/java/awt/peer/gtk/CairoGraphics2D.java
+ (createPath): Simplify width & height calculation.
+ (drawImage): Also transform width & height.
+
+2006-11-30 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/FrameSetView.java: New class. Implements
+ HTML framesets.
+ * javax/swing/text/html/FrameView.java: New class. Implements
+ HTML frames.
+ * javax/swing/text/html/HTMLDocument.java:
+ (HTMLReader.addSpecialElement): Only add one artificial space.
+ * javax/swing/text/html/HTMLEditorKit.java
+ (HTMLFactory.create): Uncomment code for FrameSetView and FrameView.
+ * gnu/javax/swing/text/html/parser/support/Parser.java
+ (_handleEmptyTag): Also consume whitespace after frame tags.
+
+2006-11-30 Gary Benson <gbenson@redhat.com>
+
+ * java/lang/Thread.java: Javadoc fixes.
+
2006-11-29 Tom Tromey <tromey@redhat.com>
PR classpath/28203:
diff --git a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
index 7de9c057e..37ae498ad 100644
--- a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
+++ b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
@@ -248,13 +248,13 @@ public class BufferedImageGraphics extends CairoGraphics2D
if (sm.getScanlineStride() == imageWidth && minX == 0)
{
System.arraycopy(pixels, y * imageWidth,
- db, y * imageWidth - minY,
+ db, (y - minY) * imageWidth,
height * imageWidth);
}
else
{
int scanline = sm.getScanlineStride();
- for (int i = y; i < height; i++)
+ for (int i = y; i < (height + y); i++)
System.arraycopy(pixels, i * imageWidth + x, db,
(i - minY) * scanline + x - minX, width);
@@ -313,6 +313,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setStroke(this.getStroke());
g2d.setColor(this.getColor());
+ g2d.setTransform(transform);
g2d.draw(s);
drawComposite(r.getBounds2D(), null);
@@ -334,6 +335,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setPaint(this.getPaint());
g2d.setColor(this.getColor());
+ g2d.setTransform(transform);
g2d.fill(s);
drawComposite(s.getBounds2D(), null);
@@ -353,6 +355,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setRenderingHints(this.getRenderingHints());
+ g2d.setTransform(transform);
g2d.drawRenderedImage(image, xform);
drawComposite(buffer.getRaster().getBounds(), null);
@@ -427,43 +430,64 @@ public class BufferedImageGraphics extends CairoGraphics2D
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setPaint(this.getPaint());
g2d.setStroke(this.getStroke());
+ g2d.setTransform(transform);
g2d.drawGlyphVector(gv, x, y);
drawComposite(bounds, null);
}
}
+ /**
+ * Perform composite drawing from the buffer onto the main image.
+ *
+ * The image to be composited should already be drawn into the buffer, in the
+ * proper place, after all necessary transforms have been applied.
+ *
+ * @param bounds The bounds to draw, in user-space.
+ * @param observer The image observer, if any (may be null).
+ * @return True on success, false on failure.
+ */
private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
{
- // Clip source to visible areas that need updating
- Rectangle2D clip = this.getClipBounds();
- Rectangle2D.intersect(bounds, clip, bounds);
- clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
- buffer.getWidth(), buffer.getHeight());
- Rectangle2D.intersect(bounds, clip, bounds);
+ // Find bounds in device space
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+ bounds = new Rectangle2D.Double(points[0], points[1],
+ (points[2] - points[0]),
+ (points[3] - points[1]));
+
+ // Clip bounds by the stored clip, and by the internal buffer
+ Rectangle2D devClip = this.getClipInDevSpace();
+ Rectangle2D.intersect(bounds, devClip, bounds);
+ devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, devClip, bounds);
+
+ // Round bounds as needed, but be conservative in our rounding
+ // (otherwise it may leave unpainted stripes)
+ double x = bounds.getX();
+ double y = bounds.getY();
+ double w = bounds.getWidth();
+ double h = bounds.getHeight();
+ if (Math.floor(x) != x)
+ w--;
+ if (Math.floor(y) != y)
+ h--;
+ bounds.setRect(Math.ceil(x), Math.ceil(y), Math.floor(w), Math.floor(h));
+ // Find subimage of internal buffer for updating
BufferedImage buffer2 = buffer;
if (!bounds.equals(buffer2.getRaster().getBounds()))
buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
(int)bounds.getWidth(),
(int)bounds.getHeight());
-
- // Get destination clip to bounds
- double[] points = new double[] {bounds.getX(), bounds.getY(),
- bounds.getMaxX(), bounds.getMaxY()};
- transform.transform(points, 0, points, 0, 2);
-
- Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
- points[2] - points[0],
- points[3] - points[1]);
-
- Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
-
+
+ // Find subimage of main image for updating
BufferedImage current = image;
- current = current.getSubimage((int)deviceBounds.getX(),
- (int)deviceBounds.getY(),
- (int)deviceBounds.getWidth(),
- (int)deviceBounds.getHeight());
+ current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
// Perform actual composite operation
compCtx.compose(buffer2.getRaster(), current.getRaster(),
diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
index 16de95185..ec9890524 100644
--- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java
+++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
@@ -1153,8 +1153,8 @@ public abstract class CairoGraphics2D extends Graphics2D
// does not get distorted by this shifting operation
double x = shiftX(r.getX(),shiftDrawCalls && isDraw);
double y = shiftY(r.getY(), shiftDrawCalls && isDraw);
- double w = shiftX(r.getWidth() + r.getX(), shiftDrawCalls && isDraw) - x;
- double h = shiftY(r.getHeight() + r.getY(), shiftDrawCalls && isDraw) - y;
+ double w = Math.round(r.getWidth());
+ double h = Math.round(r.getHeight());
cairoRectangle(nativePointer, x, y, w, h);
}
@@ -1506,8 +1506,11 @@ public abstract class CairoGraphics2D extends Graphics2D
setBackground(bgcolor);
double[] origin = new double[] {0,0};
+ double[] dimensions = new double[] {width, height};
xform.transform(origin, 0, origin, 0, 1);
- clearRect((int)origin[0], (int)origin[1], width, height);
+ xform.deltaTransform(dimensions, 0, dimensions, 0, 1);
+ clearRect((int)origin[0], (int)origin[1],
+ (int)dimensions[0], (int)dimensions[1]);
setBackground(oldColor);
}
@@ -2051,4 +2054,4 @@ public abstract class CairoGraphics2D extends Graphics2D
return rect;
}
-}
+} \ No newline at end of file
diff --git a/gnu/javax/swing/text/html/css/BorderStyle.java b/gnu/javax/swing/text/html/css/BorderStyle.java
new file mode 100644
index 000000000..d75beea52
--- /dev/null
+++ b/gnu/javax/swing/text/html/css/BorderStyle.java
@@ -0,0 +1,64 @@
+/* BorderStyle.java -- Utility for dealing with 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 gnu.javax.swing.text.html.css;
+
+/**
+ * Utility class for handling border styles.
+ */
+public class BorderStyle
+{
+
+ /**
+ * Determines if a given value makes up a valid border style value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> when this is a valid border style,
+ * <code>false</code> otherwise
+ */
+ public static boolean isValidStyle(String value)
+ {
+ return value.equals("none") || value.equals("hidden")
+ || value.equals("dotted") || value.equals("dashed")
+ || value.equals("solid") || value.equals("double")
+ || value.equals("groove") || value.equals("ridge")
+ || value.equals("inset") || value.equals("outset");
+
+ }
+}
diff --git a/gnu/javax/swing/text/html/css/BorderWidth.java b/gnu/javax/swing/text/html/css/BorderWidth.java
index b717020e3..ae64c2110 100644
--- a/gnu/javax/swing/text/html/css/BorderWidth.java
+++ b/gnu/javax/swing/text/html/css/BorderWidth.java
@@ -63,4 +63,16 @@ public class BorderWidth
floatValue = 3.F;
}
+ /**
+ * Checks if the specified value makes up a valid border-width value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> if the value is a valid border-width
+ */
+ public static boolean isValid(String value)
+ {
+ return value.equals("thin") || value.equals("medium")
+ || value.equals("thick") || Length.isValid(value);
+ }
}
diff --git a/gnu/javax/swing/text/html/css/FontSize.java b/gnu/javax/swing/text/html/css/FontSize.java
index 7dc8d46c6..2795b6784 100644
--- a/gnu/javax/swing/text/html/css/FontSize.java
+++ b/gnu/javax/swing/text/html/css/FontSize.java
@@ -255,13 +255,13 @@ public class FontSize
private int mapRelative(int par)
{
- if (value.contains("%"))
+ if (value.indexOf('%') != -1)
size = mapPercent(par);
- else if (value.contains("em"))
+ else if (value.indexOf("em") != -1)
size = mapEM(par);
- else if (value.contains("larger"))
+ else if (value.indexOf("larger") != -1)
size = mapLarger(par);
- else if (value.contains("smaller"))
+ else if (value.indexOf("smaller") != -1)
size = mapSmaller(par);
return size;
}
diff --git a/gnu/javax/swing/text/html/css/Length.java b/gnu/javax/swing/text/html/css/Length.java
index 339e2a2e0..06fa36e3d 100644
--- a/gnu/javax/swing/text/html/css/Length.java
+++ b/gnu/javax/swing/text/html/css/Length.java
@@ -62,15 +62,40 @@ public class Length
private boolean isPercentage;
/**
+ * Indicates a length value that is relative to the font size (em).
+ */
+ private boolean isFontEMRelative;
+
+ /**
+ * Indicates a length value that is relative to the font size (ex).
+ */
+ private boolean isFontEXRelative;
+
+ /**
+ * The EM base size.
+ */
+ private float emBase;
+
+ /**
+ * The EX base size.
+ */
+ private float exBase;
+
+ /**
* Creates a new length converter instance.
*
* @param val the CSS value
*/
public Length(String val)
{
+ isFontEMRelative = false;
+ isFontEXRelative = false;
+ isPercentage = false;
value = val;
int i = value.indexOf("px");
int percent = value.indexOf("%");
+ int em = value.indexOf("em");
+ int ex = value.indexOf("ex");
try
{
floatValue = 0.0F;
@@ -85,13 +110,24 @@ public class Length
String sub = value.substring(0, percent);
floatValue = Float.parseFloat(sub) / 100;
}
+ else if (em != -1)
+ {
+ isFontEMRelative = true;
+ String sub = value.substring(0, em);
+ floatValue = Float.parseFloat(sub);
+ }
+ else if (ex != -1)
+ {
+ isFontEXRelative = true;
+ String sub = value.substring(0, ex);
+ floatValue = Float.parseFloat(sub);
+ }
else
{
- // TODO: Implement other length options.
floatValue = Float.parseFloat(value);
}
}
- catch (NumberFormatException ex)
+ catch (NumberFormatException exc)
{
// Don't let such small problems interrupt CSS parsing.
System.err.println("couldn't parse: " + val);
@@ -112,19 +148,79 @@ public class Length
* Returns the absolute span for the case when this length value is
* a relative value.
*
- * @param available the target span
+ * @param base the base span
*
* @return the absolute span
*/
- public float getValue(float available)
+ public float getValue(float base)
{
float span = floatValue;
if (isPercentage)
- span *= available;
+ span *= base;
+ else if (isFontEMRelative)
+ span *= emBase;
+ else if (isFontEXRelative)
+ span *= exBase;
return span;
}
/**
+ * Sets the font relative EM base.
+ *
+ * @param base the font relative EM base
+ */
+ public void setEMBase(float base)
+ {
+ emBase = base;
+ }
+
+ /**
+ * Sets the font relative EX base.
+ *
+ * @param base the font relative EX base
+ */
+ public void setEXBase(float base)
+ {
+ exBase = base;
+ }
+
+ /**
+ * Sets the font relative base values.
+ *
+ * @param emBase the EM base
+ * @param exBase the EX base
+ */
+ public void setFontBases(float emBase, float exBase)
+ {
+ setEMBase(emBase);
+ setEXBase(exBase);
+ }
+
+ /**
+ * Returns true when this length value is an em font relative value. In
+ * order to get correct results, you need the exBase property set up
+ * correctly.
+ *
+ * @return true when this length value is an ex font relative value
+ */
+ public boolean isFontEMRelative()
+ {
+ return isFontEMRelative;
+ }
+
+ /**
+ * Returns true when this length value is an ex font relative value. In
+ * order to get correct results, you need the emBase property set up
+ * correctly.
+ *
+ * @return true when this length value is an ex font relative value
+ */
+ public boolean isFontEXRelative()
+ {
+ return isFontEXRelative;
+ }
+
+ /**
* Returns <code>true</code> when the length value is a percentage
* value, <code>false</code> otherwise.
*
@@ -135,4 +231,53 @@ public class Length
{
return isPercentage;
}
+
+ /**
+ * Checks if the specified value makes up a valid length value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> if the value is a valid length
+ */
+ public static boolean isValid(String value)
+ {
+ boolean isValid = true;
+ int px = value.indexOf("px");
+ int em = value.indexOf("em");
+ int ex = value.indexOf("ex");
+ int pc = value.indexOf('%');
+ try
+ {
+ if (px != -1)
+ {
+ Integer.parseInt(value.substring(0, px));
+ }
+ else if (em != -1)
+ {
+ Integer.parseInt(value.substring(0, em));
+ }
+ else if (ex != -1)
+ {
+ Integer.parseInt(value.substring(0, ex));
+ }
+ else if (pc != -1)
+ {
+ Integer.parseInt(value.substring(0, ex));
+ }
+ else
+ {
+ Integer.parseInt(value);
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ isValid = false;
+ }
+ return isValid;
+ }
+
+ public String toString()
+ {
+ return value;
+ }
}
diff --git a/gnu/javax/swing/text/html/css/Selector.java b/gnu/javax/swing/text/html/css/Selector.java
index b8128233b..210df3a7b 100644
--- a/gnu/javax/swing/text/html/css/Selector.java
+++ b/gnu/javax/swing/text/html/css/Selector.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.javax.swing.text.html.css;
+import java.util.Map;
import java.util.StringTokenizer;
/**
@@ -98,7 +99,7 @@ public class Selector
* @return <code>true</code> when this selector matches the element path,
* <code>false</code> otherwise
*/
- public boolean matches(String[] tags, String[] pathClasses, String[] pathIds)
+ public boolean matches(String[] tags, Map[] attributes)
{
// TODO: This implements class, id and descendent matching. These are
// the most commonly used selector matchers in CSS together with HTML.
@@ -119,15 +120,22 @@ public class Selector
boolean tagMatch = false;
for (; tagIndex < numTags && tagMatch == false; tagIndex++)
{
+ Object pathClass = attributes[tagIndex].get("class");
+ // Try pseudo class too.
+ Object pseudoClass = attributes[tagIndex].get("_pseudo");
+ Object dynClass = attributes[tagIndex].get("_dynamic");
+ Object pathId = attributes[tagIndex].get("id");
String tag = elements[j];
String clazz = classes[j];
String id = ids[j];
tagMatch = tag.equals("") || tag.equals("*")
|| tag.equals(tags[tagIndex]);
tagMatch = tagMatch && (clazz.equals("*")
- || clazz.equals(pathClasses[tagIndex]));
+ || clazz.equals(dynClass)
+ || clazz.equals(pseudoClass)
+ || clazz.equals(pathClass));
tagMatch = tagMatch && (id.equals("*")
- || id.equals(pathIds[tagIndex]));
+ || id.equals(pathId));
// For the last element in the selector we must not look
// further.
if (j == 0)
@@ -190,6 +198,9 @@ public class Selector
{
String sel = selector[i];
int clazzIndex = sel.indexOf('.');
+ // Try pseudo class too.
+ if (clazzIndex == -1)
+ clazzIndex = sel.indexOf(':');
int idIndex = sel.indexOf('#');
String clazz;
if (clazzIndex == -1)
diff --git a/gnu/javax/swing/text/html/parser/support/Parser.java b/gnu/javax/swing/text/html/parser/support/Parser.java
index 98058e503..f04c58138 100644
--- a/gnu/javax/swing/text/html/parser/support/Parser.java
+++ b/gnu/javax/swing/text/html/parser/support/Parser.java
@@ -498,6 +498,9 @@ public class Parser
mustBe(t.kind);
}
hTag = new Token(start, last);
+
+ // Consume any whitespace immediately following a comment.
+ optional(WS);
handleComment();
}
@@ -983,13 +986,15 @@ public class Parser
+ next.getImage() + "'");
attrValue = value.getImage();
}
- else if (next.kind == SLASH)
- // The slash in this context is treated as the ordinary
- // character, not as a token. The slash may be part of
+ else if (next.kind == SLASH || next.kind == OTHER)
+ // The slash and other characters (like %) in this context is
+ // treated as the ordinary
+ // character, not as a token. The character may be part of
// the unquoted URL.
{
StringBuffer image = new StringBuffer(value.getImage());
- while (next.kind == NUMTOKEN || next.kind == SLASH)
+ while (next.kind == NUMTOKEN || next.kind == SLASH
+ || next.kind == OTHER)
{
image.append(getNextToken().getImage());
next = getTokenAhead();
@@ -1181,6 +1186,13 @@ public class Parser
{
validator.validateTag(tag, attributes);
handleEmptyTag(tag);
+ HTML.Tag h = tag.getHTMLTag();
+ // When a block tag is closed, consume whitespace that follows after
+ // it.
+ // For some unknown reason a FRAME tag is not treated as block element.
+ // However in this case it should be treated as such.
+ if (isBlock(h))
+ optional(WS);
}
catch (ChangedCharSetException ex)
{
@@ -1219,7 +1231,7 @@ public class Parser
// When a block tag is closed, consume whitespace that follows after
// it.
- if (h.isBlock())
+ if (isBlock(h))
optional(WS);
if (h == HTML.Tag.TITLE)
@@ -1248,6 +1260,9 @@ public class Parser
HTML.Tag h = tag.getHTMLTag();
+ if (isBlock(h))
+ optional(WS);
+
if (h.isPreformatted())
preformatted++;
@@ -1495,4 +1510,19 @@ public class Parser
{
error("Whitespace here is not permitted");
}
+
+ /**
+ * Returns true when the specified tag should be considered a block tag
+ * wrt whitespace handling. We need this special handling, since there
+ * are a couple of tags that we must treat as block tags but which aren't
+ * officially block tags.
+ *
+ * @param tag the tag to check
+ * @return true when the specified tag should be considered a block tag
+ * wrt whitespace handling
+ */
+ private boolean isBlock(HTML.Tag tag)
+ {
+ return tag.isBlock() || tag == HTML.Tag.STYLE || tag == HTML.Tag.FRAME;
+ }
}
diff --git a/include/gnu_java_awt_peer_gtk_GdkFontPeer.h b/include/gnu_java_awt_peer_gtk_GdkFontPeer.h
index 3b9ddd443..c23980ca5 100644
--- a/include/gnu_java_awt_peer_gtk_GdkFontPeer.h
+++ b/include/gnu_java_awt_peer_gtk_GdkFontPeer.h
@@ -18,6 +18,22 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkFontPeer_getFontMetrics (JN
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkFontPeer_getTextMetrics (JNIEnv *env, jobject, jstring, jdoubleArray);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkFontPeer_releasePeerGraphicsResource (JNIEnv *env, jobject);
JNIEXPORT jbyteArray JNICALL Java_gnu_java_awt_peer_gtk_GdkFontPeer_getTrueTypeTable (JNIEnv *env, jobject, jbyte, jbyte, jbyte, jbyte);
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_ASCENT
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_ASCENT 0L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_MAX_ASCENT
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_MAX_ASCENT 1L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_DESCENT
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_DESCENT 2L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_MAX_DESCENT
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_MAX_DESCENT 3L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_MAX_ADVANCE
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_MAX_ADVANCE 4L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_HEIGHT
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_HEIGHT 5L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_UNDERLINE_OFFSET
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_UNDERLINE_OFFSET 6L
+#undef gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_UNDERLINE_THICKNESS
+#define gnu_java_awt_peer_gtk_GdkFontPeer_FONT_METRICS_UNDERLINE_THICKNESS 7L
#ifdef __cplusplus
}
diff --git a/java/beans/beancontext/BeanContextServicesSupport.java b/java/beans/beancontext/BeanContextServicesSupport.java
index ce09b86cc..f354ff474 100644
--- a/java/beans/beancontext/BeanContextServicesSupport.java
+++ b/java/beans/beancontext/BeanContextServicesSupport.java
@@ -86,38 +86,39 @@ public class BeanContextServicesSupport
{
private static final long serialVersionUID = 7078212910685744490L;
- private BCSSProxyServiceProvider()
+ private BeanContextServiceProvider provider;
+
+ private BCSSProxyServiceProvider(BeanContextServiceProvider p)
{
+ provider = p;
}
public Iterator getCurrentServiceSelectors (BeanContextServices bcs,
Class serviceClass)
- throws NotImplementedException
{
- throw new Error ("Not implemented");
+ return provider.getCurrentServiceSelectors(bcs, serviceClass);
}
public Object getService (BeanContextServices bcs,
Object requestor,
Class serviceClass,
Object serviceSelector)
- throws NotImplementedException
{
- throw new Error ("Not implemented");
+ return provider.getService(bcs, requestor, serviceClass,
+ serviceSelector);
}
public void releaseService (BeanContextServices bcs,
Object requestor,
Object service)
- throws NotImplementedException
{
- throw new Error ("Not implemented");
+ provider.releaseService(bcs, requestor, service);
}
public void serviceRevoked (BeanContextServiceRevokedEvent bcsre)
- throws NotImplementedException
{
- throw new Error ("Not implemented");
+ if (provider instanceof BeanContextServiceRevokedListener)
+ ((BeanContextServiceRevokedListener) provider).serviceRevoked(bcsre);
}
}
@@ -772,16 +773,24 @@ public class BeanContextServicesSupport
serviceLeases = new HashMap();
}
- protected void initializeBeanContextResources ()
- throws NotImplementedException
+ /**
+ * Subclasses may override this method to allocate resources
+ * from the nesting bean context.
+ */
+ protected void initializeBeanContextResources()
{
- throw new Error ("Not implemented");
+ /* Purposefully left empty */
}
- protected void releaseBeanContextResources ()
- throws NotImplementedException
+ /**
+ * Relinquishes any resources obtained from the parent context.
+ * Specifically, those services obtained from the parent are revoked.
+ * Subclasses may override this method to deallocate resources
+ * from the nesting bean context.
+ */
+ protected void releaseBeanContextResources()
{
- throw new Error ("Not implemented");
+ /* Purposefully left empty */
}
/**
diff --git a/java/lang/Thread.java b/java/lang/Thread.java
index 2261bbcfc..551cd1b9e 100644
--- a/java/lang/Thread.java
+++ b/java/lang/Thread.java
@@ -853,11 +853,13 @@ public class Thread implements Runnable
* are no guarantees which thread will be next to run, but most VMs will
* choose the highest priority thread that has been waiting longest.
*
- * @param ms the number of milliseconds to sleep.
+ * @param ms the number of milliseconds to sleep, or 0 for forever
* @throws InterruptedException if the Thread is (or was) interrupted;
* it's <i>interrupted status</i> will be cleared
* @throws IllegalArgumentException if ms is negative
* @see #interrupt()
+ * @see #notify()
+ * @see #wait(long)
*/
public static void sleep(long ms) throws InterruptedException
{
@@ -877,13 +879,15 @@ public class Thread implements Runnable
* immediately when time expires, because some other thread may be
* active. So don't expect real-time performance.
*
- * @param ms the number of milliseconds to sleep
+ * @param ms the number of milliseconds to sleep, or 0 for forever
* @param ns the number of extra nanoseconds to sleep (0-999999)
* @throws InterruptedException if the Thread is (or was) interrupted;
* it's <i>interrupted status</i> will be cleared
* @throws IllegalArgumentException if ms or ns is negative
* or ns is larger than 999999.
* @see #interrupt()
+ * @see #notify()
+ * @see #wait(long, int)
*/
public static void sleep(long ms, int ns) throws InterruptedException
{
diff --git a/java/text/DecimalFormat.java b/java/text/DecimalFormat.java
index 3b67a50da..529e57133 100644
--- a/java/text/DecimalFormat.java
+++ b/java/text/DecimalFormat.java
@@ -660,11 +660,11 @@ public class DecimalFormat extends NumberFormat
int len = str.length();
if (len < stop) stop = len;
- char ch;
- int i = 0;
- for (i = start; i < stop; i++)
+ int i = start;
+ while (i < stop)
{
- ch = str.charAt(i);
+ char ch = str.charAt(i);
+ i++;
if (ch >= zero && ch <= (zero + 9))
{
@@ -749,7 +749,7 @@ public class DecimalFormat extends NumberFormat
if (isNegative) number.insert(0, '-');
- pos.setIndex(i);
+ pos.setIndex(i - 1);
// now we handle the return type
BigDecimal bigDecimal = new BigDecimal(number.toString());
@@ -1893,30 +1893,102 @@ public class DecimalFormat extends NumberFormat
// add the INTEGER attribute
addAttribute(Field.INTEGER, attributeStart, dest.length());
- if (this.decimalSeparatorAlwaysShown ||
- ((!isLong || this.useExponentialNotation)
- && this.showDecimalSeparator &&
- this.maximumFractionDigits > 0) ||
- this.minimumFractionDigits > 0)
+ // ...update field position, if needed, and return...
+ if ((fieldPos.getField() == INTEGER_FIELD ||
+ fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
+ {
+ fieldPos.setBeginIndex(beginIndexInt);
+ fieldPos.setEndIndex(endIndexInt);
+ }
+
+ handleFractionalPart(dest, fractPart, fieldPos, isLong);
+
+ // and the exponent
+ if (this.useExponentialNotation)
{
attributeStart = dest.length();
+ dest.append(symbols.getExponential());
+
+ addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
+ attributeStart = dest.length();
+
+ if (exponent < 0)
+ {
+ dest.append(symbols.getMinusSign());
+ exponent = -exponent;
+
+ addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
+ }
+
+ attributeStart = dest.length();
+
+ String exponentString = String.valueOf(exponent);
+ int exponentLength = exponentString.length();
+
+ for (int i = 0; i < minExponentDigits - exponentLength; i++)
+ dest.append(symbols.getZeroDigit());
+
+ for (int i = 0; i < exponentLength; ++i)
+ dest.append(exponentString.charAt(i));
+
+ addAttribute(Field.EXPONENT, attributeStart, dest.length());
+ }
+
+ // now include the suffixes...
+ if (isNegative)
+ {
+ dest.append(negativeSuffix);
+ }
+ else
+ {
+ dest.append(positiveSuffix);
+ }
+ }
+
+ /**
+ * Add to the input buffer the result of formatting the fractional
+ * portion of the number.
+ *
+ * @param dest
+ * @param fractPart
+ * @param fieldPos
+ * @param isLong
+ */
+ private void handleFractionalPart(StringBuffer dest, String fractPart,
+ FieldPosition fieldPos, boolean isLong)
+ {
+ int dotStart = 0;
+ int dotEnd = 0;
+ boolean addDecimal = false;
+
+ if (this.decimalSeparatorAlwaysShown ||
+ ((!isLong || this.useExponentialNotation) &&
+ this.showDecimalSeparator && this.maximumFractionDigits > 0) ||
+ this.minimumFractionDigits > 0)
+ {
+ dotStart = dest.length();
+
if (this.useCurrencySeparator)
dest.append(symbols.getMonetaryDecimalSeparator());
else
dest.append(symbols.getDecimalSeparator());
- // add the INTEGER attribute
- addAttribute(Field.DECIMAL_SEPARATOR, attributeStart, dest.length());
+ dotEnd = dest.length();
+ addDecimal = true;
}
// now handle the fraction portion of the number
+ int fractStart = 0;
+ int fractEnd = 0;
+ boolean addFractional = false;
+
if ((!isLong || this.useExponentialNotation)
&& this.maximumFractionDigits > 0
|| this.minimumFractionDigits > 0)
{
- attributeStart = dest.length();
- beginIndexFract = attributeStart;
+ fractStart = dest.length();
+ fractEnd = fractStart;
int digits = this.minimumFractionDigits;
@@ -1939,83 +2011,41 @@ public class DecimalFormat extends NumberFormat
if (fracts[i] != '0')
allZeros = false;
}
-
+
if (!allZeros || (minimumFractionDigits > 0))
{
appendDigit(fractPart, dest, false);
- endIndexFract = dest.length();
- addAttribute(Field.FRACTION, attributeStart, endIndexFract);
+ fractEnd = dest.length();
+
+ addDecimal = true;
+ addFractional = true;
}
else if (!this.decimalSeparatorAlwaysShown)
{
dest.deleteCharAt(dest.length() - 1);
+ addDecimal = false;
}
else
{
- System.out.println("ayeeeee!");
- endIndexFract = dest.length();
- addAttribute(Field.FRACTION, attributeStart, endIndexFract);
+ fractEnd = dest.length();
+ addFractional = true;
}
}
- // and the exponent
- if (this.useExponentialNotation)
- {
- attributeStart = dest.length();
-
- dest.append(symbols.getExponential());
-
- addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
- attributeStart = dest.length();
-
- if (exponent < 0)
- {
- dest.append(symbols.getMinusSign());
- exponent = -exponent;
-
- addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
- }
-
- attributeStart = dest.length();
-
- String exponentString = String.valueOf(exponent);
- int exponentLength = exponentString.length();
-
- for (int i = 0; i < minExponentDigits - exponentLength; i++)
- dest.append(symbols.getZeroDigit());
-
- for (int i = 0; i < exponentLength; ++i)
- dest.append(exponentString.charAt(i));
-
- addAttribute(Field.EXPONENT, attributeStart, dest.length());
- }
-
- // now include the suffixes...
- if (isNegative)
- {
- dest.append(negativeSuffix);
- }
- else
- {
- dest.append(positiveSuffix);
- }
+ if (addDecimal)
+ addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd);
- // ...update field position, if needed, and return...
- if ((fieldPos.getField() == INTEGER_FIELD ||
- fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
- {
- fieldPos.setBeginIndex(beginIndexInt);
- fieldPos.setEndIndex(endIndexInt);
- }
+ if (addFractional)
+ addAttribute(Field.FRACTION, fractStart, fractEnd);
if ((fieldPos.getField() == FRACTION_FIELD ||
fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION))
{
- fieldPos.setBeginIndex(beginIndexFract);
- fieldPos.setEndIndex(endIndexFract);
+ fieldPos.setBeginIndex(fractStart);
+ fieldPos.setEndIndex(fractEnd);
}
}
-
+
/**
* Append to <code>dest</code>the give number of zeros.
* Grouping is added if needed.
diff --git a/javax/swing/text/ElementIterator.java b/javax/swing/text/ElementIterator.java
index a6a5ff618..112d55e96 100644
--- a/javax/swing/text/ElementIterator.java
+++ b/javax/swing/text/ElementIterator.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package javax.swing.text;
+import java.util.Stack;
+
/**
* This class can be used to iterate over the {@link Element} tree of
* a {@link Document} or an {@link Element}. This iterator performs
@@ -46,20 +48,41 @@ package javax.swing.text;
*/
public class ElementIterator implements Cloneable
{
+ /**
+ * Uses to track the iteration on the stack.
+ */
+ private class ElementRef
+ {
+ /**
+ * The element.
+ */
+ Element element;
+
+ /**
+ * The child index. -1 means the element itself. >= 0 values mean the
+ * n-th child of the element.
+ */
+ int index;
+
+ /**
+ * Creates a new ElementRef.
+ *
+ * @param el the element
+ */
+ ElementRef(Element el)
+ {
+ element = el;
+ index = -1;
+ }
+ }
+
// The root element.
private Element root;
- // The current element.
- private Element currentElement;
- // The depth to which we have descended in the tree.
- private int currentDepth;
-
- // This is at least as big as the current depth, and at index N
- // contains the index of the child element we're currently
- // examining.
- private int[] state;
- // The previous item.
- private Element previousItem;
+ /**
+ * Holds ElementRefs.
+ */
+ private Stack stack;
/**
* Create a new ElementIterator to iterate over the given document.
@@ -67,9 +90,7 @@ public class ElementIterator implements Cloneable
*/
public ElementIterator(Document document)
{
- this.root = document.getDefaultRootElement();
- this.currentElement = root;
- this.state = new int[5];
+ root = document.getDefaultRootElement();
}
/**
@@ -79,8 +100,6 @@ public class ElementIterator implements Cloneable
public ElementIterator(Element root)
{
this.root = root;
- this.currentElement = root;
- this.state = new int[5];
}
/**
@@ -105,7 +124,24 @@ public class ElementIterator implements Cloneable
*/
public Element current()
{
- return currentElement;
+ Element current;
+ if (stack == null)
+ current = first();
+ else
+ {
+ current = null;
+ if (! stack.isEmpty())
+ {
+ ElementRef ref = (ElementRef) stack.peek();
+ Element el = ref.element;
+ int index = ref.index;
+ if (index == -1)
+ current = el;
+ else
+ current = el.getElement(index);
+ }
+ }
+ return current;
}
/**
@@ -113,7 +149,10 @@ public class ElementIterator implements Cloneable
*/
public int depth()
{
- return currentDepth;
+ int depth = 0;
+ if (stack != null)
+ depth = stack.size();
+ return depth;
}
/**
@@ -121,11 +160,15 @@ public class ElementIterator implements Cloneable
*/
public Element first()
{
- // Reset the iterator.
- currentElement = root;
- currentDepth = 0;
- previousItem = null;
- return root;
+ Element first = null;
+ if (root != null)
+ {
+ stack = new Stack();
+ if (root.getElementCount() > 0)
+ stack.push(new ElementRef(root));
+ first = root;
+ }
+ return first;
}
/**
@@ -134,48 +177,96 @@ public class ElementIterator implements Cloneable
*/
public Element next()
{
- previousItem = currentElement;
- if (currentElement == null)
- return null;
- if (! currentElement.isLeaf())
+ Element next;
+ if (stack == null)
+ next = first();
+ else
{
- ++currentDepth;
- if (currentDepth > state.length)
- {
- int[] newState = new int[state.length * 2];
- System.arraycopy(state, 0, newState, 0, state.length);
- state = newState;
- }
- state[currentDepth] = 0;
- currentElement = currentElement.getElement(0);
- return currentElement;
+ next = null;
+ if (! stack.isEmpty())
+ {
+ ElementRef ref = (ElementRef) stack.peek();
+ Element el = ref.element;
+ int index = ref.index;
+ if (el.getElementCount() > index + 1)
+ {
+ Element child = el.getElement(index + 1);
+ if (child.isLeaf())
+ ref.index++;
+ else
+ stack.push(new ElementRef(child));
+ next = child;
+ next = child;
+ }
+ else
+ {
+ stack.pop();
+ if (! stack.isEmpty())
+ {
+ ElementRef top = (ElementRef) stack.peek();
+ top.index++;
+ next = next();
+ }
+ }
+ }
+ // else return null.
}
+ return next;
+ }
- while (currentDepth > 0)
+ /**
+ * Returns the previous item. Does not modify the iterator state.
+ */
+ public Element previous()
+ {
+ Element previous = null;
+ int stackSize;
+ if (stack != null && (stackSize = stack.size()) > 0)
{
- // At a leaf, or done with a non-leaf's children, so go up a
- // level.
- --currentDepth;
- currentElement = currentElement.getParentElement();
- ++state[currentDepth];
- if (state[currentDepth] < currentElement.getElementCount())
- {
- currentElement = currentElement.getElement(state[currentDepth]);
- return currentElement;
- }
+ ElementRef ref = (ElementRef) stack.peek();
+ Element el = ref.element;
+ int index = ref.index;
+ if (index > 0)
+ {
+ previous = deepestLeaf(el.getElement(--index));
+ }
+ else if (index == 0)
+ {
+ previous = el;
+ }
+ else if (index == -1)
+ {
+ ElementRef top = (ElementRef) stack.pop();
+ ElementRef item = (ElementRef) stack.peek();
+ stack.push(top);
+ index = item.index;
+ el = item.element;
+ previous = index == -1 ? el : deepestLeaf(el.getElement(index));
+ }
}
-
- currentElement = null;
- return currentElement;
+ return previous;
}
/**
- * Returns the previous item. Does not modify the iterator state.
+ * Determines and returns the deepest leaf of the element <code>el</code>.
+ *
+ * @param el the base element
+ *
+ * @returnthe deepest leaf of the element <code>el</code>
*/
- public Element previous()
+ private Element deepestLeaf(Element el)
{
- if (currentElement == null || currentElement == root)
- return null;
- return previousItem;
+ Element leaf;
+ if (el.isLeaf())
+ leaf = el;
+ else
+ {
+ int count = el.getElementCount();
+ if (count == 0)
+ leaf = el;
+ else
+ leaf = deepestLeaf(el.getElement(count - 1));
+ }
+ return leaf;
}
}
diff --git a/javax/swing/text/html/BlockView.java b/javax/swing/text/html/BlockView.java
index 2e781412c..82bd8604e 100644
--- a/javax/swing/text/html/BlockView.java
+++ b/javax/swing/text/html/BlockView.java
@@ -40,6 +40,7 @@ package javax.swing.text.html;
import gnu.javax.swing.text.html.css.Length;
+import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
@@ -255,16 +256,13 @@ public class BlockView extends BoxView
int[] offsets, int[] 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);
+ Length length = cssSpans[axis];
if (length != null)
{
min = Math.max((int) length.getValue(targetSpan), min);
@@ -299,6 +297,11 @@ public class BlockView extends BoxView
public void paint(Graphics g, Shape a)
{
Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+
+ // Debug output. Shows blocks in green rectangles.
+ // g.setColor(Color.GREEN);
+ // g.drawRect(rect.x, rect.y, rect.width, rect.height);
+
painter.paint(g, rect.x, rect.y, rect.width, rect.height, this);
super.paint(g, a);
}
@@ -446,8 +449,14 @@ public class BlockView extends BoxView
}
// Fetch width and height.
+ float emBase = ss.getEMBase(attributes);
+ float exBase = ss.getEXBase(attributes);
cssSpans[X_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
+ if (cssSpans[X_AXIS] != null)
+ cssSpans[X_AXIS].setFontBases(emBase, exBase);
cssSpans[Y_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.HEIGHT);
+ if (cssSpans[Y_AXIS] != null)
+ cssSpans[Y_AXIS].setFontBases(emBase, exBase);
}
/**
diff --git a/javax/swing/text/html/CSS.java b/javax/swing/text/html/CSS.java
index c82b6c537..0d1eeb762 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.BorderStyle;
import gnu.javax.swing.text.html.css.BorderWidth;
import gnu.javax.swing.text.html.css.CSSColor;
import gnu.javax.swing.text.html.css.FontSize;
@@ -417,7 +418,7 @@ public class CSS implements Serializable
new Attribute("border-right-color", false, null);
static final Attribute BORDER_SPACING =
new Attribute("border-spacing", false, null);
-
+
/**
* The attribute string.
*/
@@ -537,8 +538,23 @@ public class CSS implements Serializable
{
if (a == Attribute.BACKGROUND)
parseBackgroundShorthand(atts, v);
+ else if (a == Attribute.PADDING)
+ parsePaddingShorthand(atts, v);
+ else if (a == Attribute.MARGIN)
+ parseMarginShorthand(atts, v);
+ else if (a == Attribute.BORDER || a == Attribute.BORDER_LEFT
+ || a == Attribute.BORDER_RIGHT || a == Attribute.BORDER_TOP
+ || a == Attribute.BORDER_BOTTOM)
+ parseBorderShorthand(atts, v, a);
}
+ /**
+ * Parses the background shorthand and translates it to more specific
+ * background attributes.
+ *
+ * @param atts the attributes
+ * @param v the value
+ */
private static void parseBackgroundShorthand(MutableAttributeSet atts,
String v)
{
@@ -551,4 +567,159 @@ public class CSS implements Serializable
new CSSColor(token));
}
}
+
+ /**
+ * Parses the padding shorthand and translates to the specific padding
+ * values.
+ *
+ * @param atts the attributes
+ * @param v the actual value
+ */
+ private static void parsePaddingShorthand(MutableAttributeSet atts, String v)
+ {
+ StringTokenizer tokens = new StringTokenizer(v, " ");
+ int numTokens = tokens.countTokens();
+ if (numTokens == 1)
+ {
+ Length l = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l);
+ atts.addAttribute(Attribute.PADDING_LEFT, l);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l);
+ atts.addAttribute(Attribute.PADDING_TOP, l);
+ }
+ else if (numTokens == 2)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l1);
+ atts.addAttribute(Attribute.PADDING_TOP, l1);
+ atts.addAttribute(Attribute.PADDING_LEFT, l2);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l2);
+ }
+ else if (numTokens == 3)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_TOP, l1);
+ atts.addAttribute(Attribute.PADDING_LEFT, l2);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l2);
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l3);
+ }
+ else
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ Length l4 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_TOP, l1);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l2);
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l3);
+ atts.addAttribute(Attribute.PADDING_LEFT, l4);
+ }
+ }
+
+ /**
+ * Parses the margin shorthand and translates to the specific margin
+ * values.
+ *
+ * @param atts the attributes
+ * @param v the actual value
+ */
+ private static void parseMarginShorthand(MutableAttributeSet atts, String v)
+ {
+ StringTokenizer tokens = new StringTokenizer(v, " ");
+ int numTokens = tokens.countTokens();
+ if (numTokens == 1)
+ {
+ Length l = new Length(tokens.nextToken());
+ System.err.println("margin: " + l);
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l);
+ atts.addAttribute(Attribute.MARGIN_TOP, l);
+ }
+ else if (numTokens == 2)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l1);
+ atts.addAttribute(Attribute.MARGIN_TOP, l1);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l2);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
+ }
+ else if (numTokens == 3)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_TOP, l1);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l2);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l3);
+ }
+ else
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ Length l4 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_TOP, l1);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l3);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l4);
+ }
+ }
+
+ /**
+ * Parses the CSS border shorthand attribute and translates it to the
+ * more specific border attributes.
+ *
+ * @param atts the attribute
+ * @param value the value
+ */
+ private static void parseBorderShorthand(MutableAttributeSet atts,
+ String value, Attribute cssAtt)
+ {
+ StringTokenizer tokens = new StringTokenizer(value, " ");
+ while (tokens.hasMoreTokens())
+ {
+ String token = tokens.nextToken();
+ if (BorderStyle.isValidStyle(token))
+ {
+ if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_LEFT_STYLE, token);
+ if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_RIGHT_STYLE, token);
+ if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_BOTTOM_STYLE, token);
+ if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_TOP_STYLE, token);
+ }
+ else if (BorderWidth.isValid(token))
+ {
+ BorderWidth w = new BorderWidth(token);
+ if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_LEFT_WIDTH, w);
+ if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_RIGHT_WIDTH, w);
+ if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_BOTTOM_WIDTH, w);
+ if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_TOP_WIDTH, w);
+ }
+ else if (CSSColor.isValidColor(token))
+ {
+ CSSColor c = new CSSColor(token);
+ if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_LEFT_COLOR, c);
+ if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_RIGHT_COLOR, c);
+ if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_BOTTOM_COLOR, c);
+ if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_TOP_COLOR, c);
+ }
+ }
+ }
}
diff --git a/javax/swing/text/html/CSSBorder.java b/javax/swing/text/html/CSSBorder.java
index 540955494..fff6b01a1 100644
--- a/javax/swing/text/html/CSSBorder.java
+++ b/javax/swing/text/html/CSSBorder.java
@@ -40,12 +40,10 @@ 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;
@@ -140,7 +138,7 @@ class CSSBorder
*
* @param atts the attribute set that contains the border spec
*/
- CSSBorder(AttributeSet atts)
+ CSSBorder(AttributeSet atts, StyleSheet ss)
{
// Determine the border styles.
int style = getBorderStyle(atts, CSS.Attribute.BORDER_STYLE);
@@ -179,20 +177,20 @@ class CSSBorder
rightColor = color;
// Determine the border widths.
- int width = getBorderWidth(atts, CSS.Attribute.BORDER_WIDTH);
+ int width = getBorderWidth(atts, CSS.Attribute.BORDER_WIDTH, ss);
if (width == -1)
width = 0;
top = bottom = left = right = width;
- width = getBorderWidth(atts, CSS.Attribute.BORDER_TOP_WIDTH);
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_TOP_WIDTH, ss);
if (width >= 0)
top = width;
- width = getBorderWidth(atts, CSS.Attribute.BORDER_BOTTOM_WIDTH);
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_BOTTOM_WIDTH, ss);
if (width >= 0)
bottom = width;
- width = getBorderWidth(atts, CSS.Attribute.BORDER_LEFT_WIDTH);
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_LEFT_WIDTH, ss);
if (width >= 0)
left = width;
- width = getBorderWidth(atts, CSS.Attribute.BORDER_RIGHT_WIDTH);
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_RIGHT_WIDTH, ss);
if (width >= 0)
right = width;
}
@@ -264,12 +262,15 @@ class CSSBorder
*
* @return the width, or -1 of none has been set
*/
- private int getBorderWidth(AttributeSet atts, CSS.Attribute key)
+ private int getBorderWidth(AttributeSet atts, CSS.Attribute key,
+ StyleSheet ss)
{
int width = -1;
Object o = atts.getAttribute(key);
if (o instanceof BorderWidth)
{
+ BorderWidth w = (BorderWidth) o;
+ w.setFontBases(ss.getEMBase(atts), ss.getEXBase(atts));
width = (int) ((BorderWidth) o).getValue();
}
return width;
diff --git a/javax/swing/text/html/FormSubmitEvent.java b/javax/swing/text/html/FormSubmitEvent.java
new file mode 100644
index 000000000..bc7c36f4b
--- /dev/null
+++ b/javax/swing/text/html/FormSubmitEvent.java
@@ -0,0 +1,123 @@
+/* FormSubmitEvent.java -- Event fired on form submit
+ 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 java.net.URL;
+
+import javax.swing.text.Element;
+
+/**
+ * The event fired on form submit.
+ *
+ * @since 1.5
+ */
+public class FormSubmitEvent
+ extends HTMLFrameHyperlinkEvent
+{
+
+ // FIXME: Use enums when available.
+ /**
+ * The submit method.
+ */
+ public static class MethodType
+ {
+ /**
+ * Indicates a form submit with HTTP method POST.
+ */
+ public static final MethodType POST = new MethodType();
+
+ /**
+ * Indicates a form submit with HTTP method GET.
+ */
+ public static final MethodType GET = new MethodType();
+
+ private MethodType()
+ {
+ }
+ }
+
+ /**
+ * The submit method.
+ */
+ private MethodType method;
+
+ /**
+ * The actual submit data.
+ */
+ private String data;
+
+ /**
+ * Creates a new FormSubmitEvent.
+ *
+ * @param source the source
+ * @param type the type of hyperlink update
+ * @param url the action url
+ * @param el the associated element
+ * @param target the target attribute
+ * @param m the submit method
+ * @param d the submit data
+ */
+ FormSubmitEvent(Object source, EventType type, URL url, Element el,
+ String target, MethodType m, String d)
+ {
+ super(source, type, url, el, target);
+ method = m;
+ data = d;
+ }
+
+ /**
+ * Returns the submit data.
+ *
+ * @return the submit data
+ */
+ public String getData()
+ {
+ return data;
+ }
+
+ /**
+ * Returns the HTTP submit method.
+ *
+ * @return the HTTP submit method
+ */
+ public MethodType getMethod()
+ {
+ return method;
+ }
+}
diff --git a/javax/swing/text/html/FormView.java b/javax/swing/text/html/FormView.java
index 031a8b7a4..340f85490 100644
--- a/javax/swing/text/html/FormView.java
+++ b/javax/swing/text/html/FormView.java
@@ -44,24 +44,32 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
import javax.swing.ButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
+import javax.swing.JEditorPane;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
+import javax.swing.SwingUtilities;
import javax.swing.UIManager;
+import javax.swing.event.HyperlinkEvent;
import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
import javax.swing.text.ComponentView;
import javax.swing.text.Document;
import javax.swing.text.Element;
+import javax.swing.text.ElementIterator;
import javax.swing.text.StyleConstants;
/**
@@ -113,6 +121,214 @@ public class FormView
}
/**
+ * Actually submits the form data.
+ */
+ private class SubmitThread
+ extends Thread
+ {
+ /**
+ * The submit data.
+ */
+ private String data;
+
+ /**
+ * Creates a new SubmitThread.
+ *
+ * @param d the submit data
+ */
+ SubmitThread(String d)
+ {
+ data = d;
+ }
+
+ /**
+ * Actually performs the submit.
+ */
+ public void run()
+ {
+ if (data.length() > 0)
+ {
+ final String method = getMethod();
+ final URL actionURL = getActionURL();
+ final String target = getTarget();
+ URLConnection conn;
+ final JEditorPane editor = (JEditorPane) getContainer();
+ final HTMLDocument doc = (HTMLDocument) editor.getDocument();
+ HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
+ if (kit.isAutoFormSubmission())
+ {
+ try
+ {
+ final URL url;
+ if (method != null && method.equals("post"))
+ {
+ // Perform POST.
+ url = actionURL;
+ conn = url.openConnection();
+ postData(conn);
+ }
+ else
+ {
+ // Default to GET.
+ url = new URL(actionURL + "?" + data);
+ }
+ Runnable loadDoc = new Runnable()
+ {
+ public void run()
+ {
+ if (doc.isFrameDocument())
+ {
+ editor.fireHyperlinkUpdate(createSubmitEvent(method,
+ actionURL,
+ target));
+ }
+ else
+ {
+ try
+ {
+ editor.setPage(url);
+ }
+ catch (IOException ex)
+ {
+ // Oh well.
+ ex.printStackTrace();
+ }
+ }
+ }
+ };
+ SwingUtilities.invokeLater(loadDoc);
+ }
+ catch (MalformedURLException ex)
+ {
+ ex.printStackTrace();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ else
+ {
+ editor.fireHyperlinkUpdate(createSubmitEvent(method,actionURL,
+ target));
+ }
+ }
+ }
+
+ /**
+ * Determines the submit method.
+ *
+ * @return the submit method
+ */
+ private String getMethod()
+ {
+ AttributeSet formAtts = getFormAttributes();
+ String method = null;
+ if (formAtts != null)
+ {
+ method = (String) formAtts.getAttribute(HTML.Attribute.METHOD);
+ }
+ return method;
+ }
+
+ /**
+ * Determines the action URL.
+ *
+ * @return the action URL
+ */
+ private URL getActionURL()
+ {
+ AttributeSet formAtts = getFormAttributes();
+ HTMLDocument doc = (HTMLDocument) getElement().getDocument();
+ URL url = doc.getBase();
+ if (formAtts != null)
+ {
+ String action =
+ (String) formAtts.getAttribute(HTML.Attribute.ACTION);
+ if (action != null)
+ {
+ try
+ {
+ url = new URL(url, action);
+ }
+ catch (MalformedURLException ex)
+ {
+ url = null;
+ }
+ }
+ }
+ return url;
+ }
+
+ /**
+ * Fetches the target attribute.
+ *
+ * @return the target attribute or _self if none is present
+ */
+ private String getTarget()
+ {
+ AttributeSet formAtts = getFormAttributes();
+ String target = null;
+ if (formAtts != null)
+ {
+ target = (String) formAtts.getAttribute(HTML.Attribute.TARGET);
+ if (target != null)
+ target = target.toLowerCase();
+ }
+ if (target == null)
+ target = "_self";
+ return target;
+ }
+
+ /**
+ * Posts the form data over the specified connection.
+ *
+ * @param conn the connection
+ */
+ private void postData(URLConnection conn)
+ {
+ // TODO: Implement.
+ }
+
+ /**
+ * Determines the attributes from the relevant form tag.
+ *
+ * @return the attributes from the relevant form tag, <code>null</code>
+ * when there is no form tag
+ */
+ private AttributeSet getFormAttributes()
+ {
+ AttributeSet atts = null;
+ Element form = getFormElement();
+ if (form != null)
+ atts = form.getAttributes();
+ return atts;
+ }
+
+ /**
+ * Creates the submit event that should be fired.
+ *
+ * This is package private to avoid accessor methods.
+ *
+ * @param method the submit method
+ * @param actionURL the action URL
+ * @param target the target
+ *
+ * @return the submit event
+ */
+ FormSubmitEvent createSubmitEvent(String method, URL actionURL,
+ String target)
+ {
+ FormSubmitEvent.MethodType m = "post".equals(method)
+ ? FormSubmitEvent.MethodType.POST
+ : FormSubmitEvent.MethodType.GET;
+ return new FormSubmitEvent(FormView.this,
+ HyperlinkEvent.EventType.ACTIVATED,
+ actionURL, getElement(), target, m, data);
+ }
+ }
+
+ /**
* If the value attribute of an <code>&lt;input type=&quot;submit&quot;&gt>
* tag is not specified, then this string is used.
*
@@ -340,7 +556,7 @@ public class FormView
AttributeSet atts = el.getAttributes();
String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
if (type.equals("submit"))
- submitData(""); // FIXME: How to fetch the actual form data?
+ submitData(getFormData());
}
// FIXME: Implement the remaining actions.
}
@@ -353,7 +569,8 @@ public class FormView
*/
protected void submitData(String data)
{
- // FIXME: Implement this.
+ SubmitThread submitThread = new SubmitThread(data);
+ submitThread.start();
}
/**
@@ -390,4 +607,140 @@ public class FormView
}
return data;
}
+
+ /**
+ * Determines and returns the enclosing form element if there is any.
+ *
+ * This is package private to avoid accessor methods.
+ *
+ * @return the enclosing form element, or <code>null</code> if there is no
+ * enclosing form element
+ */
+ Element getFormElement()
+ {
+ Element form = null;
+ Element el = getElement();
+ while (el != null && form == null)
+ {
+ AttributeSet atts = el.getAttributes();
+ if (atts.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.FORM)
+ form = el;
+ else
+ el = el.getParentElement();
+ }
+ return form;
+ }
+
+ /**
+ * Determines the form data that is about to be submitted.
+ *
+ * @return the form data
+ */
+ private String getFormData()
+ {
+ Element form = getFormElement();
+ StringBuilder b = new StringBuilder();
+ if (form != null)
+ {
+ ElementIterator i = new ElementIterator(form);
+ Element next;
+ while ((next = i.next()) != null)
+ {
+ if (next.isLeaf())
+ {
+ AttributeSet atts = next.getAttributes();
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ if (type != null && type.equals("submit")
+ && next != getElement())
+ {
+ // Skip this. This is not the actual submit trigger.
+ }
+ else if (type == null || ! type.equals("image"))
+ {
+ getElementFormData(next, b);
+ }
+ }
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ * Fetches the form data from the specified element and appends it to
+ * the data string.
+ *
+ * @param el the element from which to fetch form data
+ * @param b the data string
+ */
+ private void getElementFormData(Element el, StringBuilder b)
+ {
+ AttributeSet atts = el.getAttributes();
+ String name = (String) atts.getAttribute(HTML.Attribute.NAME);
+ if (name != null)
+ {
+ String value = null;
+ HTML.Tag tag = (HTML.Tag) atts.getAttribute(StyleConstants.NameAttribute);
+ if (tag == HTML.Tag.INPUT)
+ value = getInputFormData(atts);
+ // TODO: Implement textarea and select.
+ if (name != null && value != null)
+ {
+ addData(b, name, value);
+ }
+ }
+ }
+
+ /**
+ * Fetches form data from an input tag.
+ *
+ * @param atts the attributes from which to fetch the data
+ *
+ * @return the field value
+ */
+ private String getInputFormData(AttributeSet atts)
+ {
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ Object model = atts.getAttribute(StyleConstants.ModelAttribute);
+ String value = null;
+ if (type.equals("text") || type.equals("password"))
+ {
+ Document doc = (Document) model;
+ try
+ {
+ value = doc.getText(0, doc.getLength());
+ }
+ catch (BadLocationException ex)
+ {
+ // Sigh.
+ assert false;
+ }
+ }
+ else if (type.equals("hidden") || type.equals("submit"))
+ {
+ value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = "";
+ }
+ // TODO: Implement the others. radio, checkbox and file.
+ return value;
+ }
+
+ /**
+ * Actually adds the specified data to the string. It URL encodes
+ * the name and value and handles separation of the fields.
+ *
+ * @param b the string at which the form data to be added
+ * @param name the name of the field
+ * @param value the value
+ */
+ private void addData(StringBuilder b, String name, String value)
+ {
+ if (b.length() > 0)
+ b.append('&');
+ String encName = URLEncoder.encode(name);
+ b.append(encName);
+ b.append('=');
+ String encValue = URLEncoder.encode(value);
+ b.append(encValue);
+ }
}
diff --git a/javax/swing/text/html/FrameSetView.java b/javax/swing/text/html/FrameSetView.java
new file mode 100644
index 000000000..e3252d79c
--- /dev/null
+++ b/javax/swing/text/html/FrameSetView.java
@@ -0,0 +1,274 @@
+/* FrameSetView.java -- Implements HTML frameset
+ 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 java.util.StringTokenizer;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BoxView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * Implements HTML framesets. This is implemented as a vertical box that
+ * holds the rows of the frameset. Each row is again a horizontal box that
+ * holds the actual columns.
+ */
+public class FrameSetView
+ extends BoxView
+{
+
+ /**
+ * A row of a frameset.
+ */
+ private class FrameSetRow
+ extends BoxView
+ {
+ private int row;
+ FrameSetRow(Element el, int r)
+ {
+ super(el, X_AXIS);
+ row = r;
+ }
+
+ protected void loadChildren(ViewFactory f)
+ {
+ // Load the columns here.
+ Element el = getElement();
+ View[] columns = new View[numViews[X_AXIS]];
+ int offset = row * numViews[X_AXIS];
+ for (int c = 0; c < numViews[X_AXIS]; c++)
+ {
+ Element child = el.getElement(offset + c);
+ columns[c] = f.create(child);
+ }
+ replace(0, 0, columns);
+ }
+
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ int numRows = numViews[X_AXIS];
+ int[] abs = absolute[X_AXIS];
+ int[] rel = relative[X_AXIS];
+ int[] perc = percent[X_AXIS];
+ layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
+ }
+ }
+
+ /**
+ * Holds the absolute layout information for the views along one axis. The
+ * indices are absolute[axis][index], where axis is either X_AXIS (columns)
+ * or Y_AXIS (rows). Rows or columns that don't have absolute layout have
+ * a -1 in this array.
+ */
+ int[][] absolute;
+
+ /**
+ * Holds the relative (*) layout information for the views along one axis.
+ * The indices are relative[axis][index], where axis is either X_AXIS
+ * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
+ * layout have a Float.NaN in this array.
+ */
+ int[][] relative;
+
+ /**
+ * Holds the relative (%) layout information for the views along one axis.
+ * The indices are relative[axis][index], where axis is either X_AXIS
+ * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
+ * layout have a Float.NaN in this array.
+ *
+ * The percentage is divided by 100 so that we hold the actual fraction here.
+ */
+ int[][] percent;
+
+ /**
+ * The number of children in each direction.
+ */
+ int[] numViews;
+
+ FrameSetView(Element el)
+ {
+ super(el, Y_AXIS);
+ numViews = new int[2];
+ absolute = new int[2][];
+ relative = new int[2][];
+ percent = new int[2][];
+ }
+
+ /**
+ * Loads the children and places them inside the grid.
+ */
+ protected void loadChildren(ViewFactory f)
+ {
+ parseRowsCols();
+ // Set up the rows.
+ View[] rows = new View[numViews[Y_AXIS]];
+ for (int r = 0; r < numViews[Y_AXIS]; r++)
+ {
+ rows[r] = new FrameSetRow(getElement(), r);
+ }
+ replace(0, 0, rows);
+ }
+
+ /**
+ * Parses the rows and cols attributes and sets up the layout info.
+ */
+ private void parseRowsCols()
+ {
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ String cols = (String) atts.getAttribute(HTML.Attribute.COLS);
+ if (cols == null) // Defaults to '100%' when not specified.
+ cols = "100%";
+ parseLayout(cols, X_AXIS);
+ String rows = (String) atts.getAttribute(HTML.Attribute.ROWS);
+ if (rows == null) // Defaults to '100%' when not specified.
+ rows = "100%";
+ parseLayout(rows, Y_AXIS);
+ }
+
+ /**
+ * Parses the cols or rows attribute and places the layout info in the
+ * appropriate arrays.
+ *
+ * @param att the attributes to parse
+ * @param axis the axis
+ */
+ private void parseLayout(String att, int axis)
+ {
+ StringTokenizer tokens = new StringTokenizer(att, ",");
+ numViews[axis] = tokens.countTokens();
+ absolute[axis] = new int[numViews[axis]];
+ relative[axis] = new int[numViews[axis]];
+ percent[axis] = new int[numViews[axis]];
+ for (int index = 0; tokens.hasMoreTokens(); index++)
+ {
+ String token = tokens.nextToken();
+ int p = token.indexOf('%');
+ int s = token.indexOf('*');
+ if (p != -1)
+ {
+ // Percent value.
+ String number = token.substring(0, p);
+ try
+ {
+ percent[axis][index] = Integer.parseInt(number);
+ }
+ catch (NumberFormatException ex)
+ {
+ // Leave value as 0 then.
+ }
+ }
+ else if (s != -1)
+ {
+ // Star relative value.
+ String number = token.substring(0, s);
+ try
+ {
+ relative[axis][index] = Integer.parseInt(number);
+ }
+ catch (NumberFormatException ex)
+ {
+ // Leave value as 0 then.
+ }
+ }
+ else
+ {
+ // Absolute value.
+ try
+ {
+ absolute[axis][index] = Integer.parseInt(token);
+ }
+ catch (NumberFormatException ex)
+ {
+ // Leave value as 0 then.
+ }
+ }
+ }
+ }
+
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ int numRows = numViews[Y_AXIS];
+ int[] abs = absolute[Y_AXIS];
+ int[] rel = relative[Y_AXIS];
+ int[] perc = percent[Y_AXIS];
+ layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
+ }
+
+ void layoutViews(int targetSpan, int axis, int[] offsets, int[] spans,
+ int numViews, int[] abs, int[] rel, int[] perc)
+ {
+ // We need two passes. In the first pass we layout the absolute and
+ // percent values and accumulate the needed space. In the second pass
+ // the relative values are distributed and the offsets are set.
+ int total = 0;
+ int relTotal = 0;
+ for (int i = 0; i < numViews; i++)
+ {
+ if (abs[i] > 0)
+ {
+ spans[i] = abs[i];
+ total += spans[i];
+ }
+ else if (perc[i] > 0)
+ {
+ spans[i] = (targetSpan * perc[i]) / 100;
+ total += spans[i];
+ }
+ else if (rel[i] > 0)
+ {
+ relTotal += rel[i];
+ }
+ }
+ int offs = 0;
+ for (int i = 0; i < numViews; i++)
+ {
+ if (relTotal > 0 && rel[i] > 0)
+ {
+ spans[i] = targetSpan * (rel[i] / relTotal);
+ }
+ offsets[i] = offs;
+ offs += spans[i];
+ }
+ }
+}
diff --git a/javax/swing/text/html/FrameView.java b/javax/swing/text/html/FrameView.java
new file mode 100644
index 000000000..cd4e44a98
--- /dev/null
+++ b/javax/swing/text/html/FrameView.java
@@ -0,0 +1,233 @@
+/* FrameView.java -- Renders HTML frame tags
+ 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 java.awt.Component;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.JEditorPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+/**
+ * A view that is responsible for rendering HTML frame tags.
+ * This is accomplished by a specialized {@link ComponentView}
+ * that embeds a JEditorPane with an own document.
+ */
+class FrameView
+ extends ComponentView
+ implements HyperlinkListener
+{
+
+ /**
+ * Creates a new FrameView for the specified element.
+ *
+ * @param el the element for the view
+ */
+ FrameView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Creates the element that will be embedded in the view.
+ * This will be a JEditorPane with the appropriate content set.
+ *
+ * @return the element that will be embedded in the view
+ */
+ protected Component createComponent()
+ {
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ JEditorPane html = new JEditorPane();
+ html.addHyperlinkListener(this);
+ URL base = ((HTMLDocument) el.getDocument()).getBase();
+ String srcAtt = (String) atts.getAttribute(HTML.Attribute.SRC);
+ if (srcAtt != null && ! srcAtt.equals(""))
+ {
+ try
+ {
+ URL page = new URL(base, srcAtt);
+ html.setPage(page);
+ ((HTMLDocument) html.getDocument()).setFrameDocument(true);
+ }
+ catch (MalformedURLException ex)
+ {
+ // Leave page empty.
+ }
+ catch (IOException ex)
+ {
+ // Leave page empty.
+ }
+ }
+ return html;
+ }
+
+ /**
+ * Catches hyperlink events on that frame's editor and forwards it to
+ * the outermost editorpane.
+ */
+ public void hyperlinkUpdate(HyperlinkEvent event)
+ {
+ JEditorPane outer = getTopEditorPane();
+ if (outer != null)
+ {
+ if (event instanceof HTMLFrameHyperlinkEvent)
+ {
+ HTMLFrameHyperlinkEvent hfhe = (HTMLFrameHyperlinkEvent) event;
+ if (hfhe.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
+ {
+ String target = hfhe.getTarget();
+ if (event instanceof FormSubmitEvent)
+ {
+ handleFormSubmitEvent(hfhe, outer, target);
+ }
+ else // No FormSubmitEvent.
+ {
+ handleHyperlinkEvent(hfhe, outer, target);
+ }
+ }
+ }
+ else
+ {
+ // Simply forward this event.
+ outer.fireHyperlinkUpdate(event);
+ }
+ }
+ }
+
+ /**
+ * Handles normal hyperlink events.
+ *
+ * @param event the event
+ * @param outer the top editor
+ * @param target the target
+ */
+ private void handleHyperlinkEvent(HyperlinkEvent event,
+ JEditorPane outer, String target)
+ {
+ if (target.equals("_top"))
+ {
+ try
+ {
+ outer.setPage(event.getURL());
+ }
+ catch (IOException ex)
+ {
+ // Well...
+ ex.printStackTrace();
+ }
+ }
+ if (! outer.isEditable())
+ {
+ outer.fireHyperlinkUpdate
+ (new HTMLFrameHyperlinkEvent(outer,
+ event.getEventType(),
+ event.getURL(),
+ event.getDescription(),
+ getElement(),
+ target));
+ }
+ }
+
+ /**
+ * Handles form submit events.
+ *
+ * @param event the event
+ * @param outer the top editor
+ * @param target the target
+ */
+ private void handleFormSubmitEvent(HTMLFrameHyperlinkEvent event,
+ JEditorPane outer,
+ String target)
+ {
+ HTMLEditorKit kit = (HTMLEditorKit) outer.getEditorKit();
+ if (kit != null && kit.isAutoFormSubmission())
+ {
+ if (target.equals("_top"))
+ {
+ try
+ {
+ outer.setPage(event.getURL());
+ }
+ catch (IOException ex)
+ {
+ // Well...
+ ex.printStackTrace();
+ }
+ }
+ else
+ {
+ HTMLDocument doc =
+ (HTMLDocument) outer.getDocument();
+ doc.processHTMLFrameHyperlinkEvent(event);
+ }
+ }
+ else
+ {
+ outer.fireHyperlinkUpdate(event);
+ }
+ }
+
+ /**
+ * Determines the topmost editor in a nested frameset.
+ *
+ * @return the topmost editor in a nested frameset
+ */
+ private JEditorPane getTopEditorPane()
+ {
+ View parent = getParent();
+ View top = null;
+ while (parent != null)
+ {
+ if (parent instanceof FrameSetView)
+ top = parent;
+ }
+ JEditorPane editor = null;
+ if (top != null)
+ editor = (JEditorPane) top.getContainer();
+ return editor;
+ }
+}
diff --git a/javax/swing/text/html/HTML.java b/javax/swing/text/html/HTML.java
index b803e9637..93c05daa2 100644
--- a/javax/swing/text/html/HTML.java
+++ b/javax/swing/text/html/HTML.java
@@ -465,6 +465,16 @@ public class HTML
public static final Attribute WIDTH = new Attribute("width");
/**
+ * This is used to reflect the pseudo class for the a tag.
+ */
+ static final Attribute PSEUDO_CLASS = new Attribute("_pseudo");
+
+ /**
+ * This is used to reflect the dynamic class for the a tag.
+ */
+ static final Attribute DYNAMIC_CLASS = new Attribute("_dynamic");
+
+ /**
* The attribute name.
*/
private final String name;
diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java
index ee59d7025..25b44615e 100644
--- a/javax/swing/text/html/HTMLDocument.java
+++ b/javax/swing/text/html/HTMLDocument.java
@@ -52,6 +52,8 @@ import java.util.Vector;
import javax.swing.DefaultButtonModel;
import javax.swing.JEditorPane;
import javax.swing.JToggleButton;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.UndoableEditEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
@@ -89,7 +91,17 @@ public class HTMLDocument extends DefaultStyledDocument
boolean preservesUnknownTags = true;
int tokenThreshold = Integer.MAX_VALUE;
HTMLEditorKit.Parser parser;
-
+
+ /**
+ * Indicates whether this document is inside a frame or not.
+ */
+ private boolean frameDocument;
+
+ /**
+ * Package private to avoid accessor methods.
+ */
+ String baseTarget;
+
/**
* Constructs an HTML document using the default buffer size and a default
* StyleSheet.
@@ -365,11 +377,119 @@ public class HTMLDocument extends DefaultStyledDocument
}
public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event)
- throws NotImplementedException
{
- // TODO: Implement this properly.
+ String target = event.getTarget();
+ Element el = event.getSourceElement();
+ URL url = event.getURL();
+ if (target.equals("_self"))
+ {
+ updateFrame(el, url);
+ }
+ else if (target.equals("_parent"))
+ {
+ updateFrameSet(el.getParentElement(), url);
+ }
+ else
+ {
+ Element targetFrame = findFrame(target);
+ if (targetFrame != null)
+ updateFrame(targetFrame, url);
+ }
}
-
+
+ /**
+ * Finds the named frame inside this document.
+ *
+ * @param target the name to look for
+ *
+ * @return the frame if there is a matching frame, <code>null</code>
+ * otherwise
+ */
+ private Element findFrame(String target)
+ {
+ ElementIterator i = new ElementIterator(this);
+ Element next = null;
+ while ((next = i.next()) != null)
+ {
+ AttributeSet atts = next.getAttributes();
+ if (atts.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.FRAME)
+ {
+ String name = (String) atts.getAttribute(HTML.Attribute.NAME);
+ if (name != null && name.equals(target))
+ break;
+ }
+ }
+ return next;
+ }
+
+ /**
+ * Updates the frame that is represented by the specified element to
+ * refer to the specified URL.
+ *
+ * @param el the element
+ * @param url the new url
+ */
+ private void updateFrame(Element el, URL url)
+ {
+ try
+ {
+ writeLock();
+ DefaultDocumentEvent ev =
+ new DefaultDocumentEvent(el.getStartOffset(), 1,
+ DocumentEvent.EventType.CHANGE);
+ AttributeSet elAtts = el.getAttributes();
+ AttributeSet copy = elAtts.copyAttributes();
+ MutableAttributeSet matts = (MutableAttributeSet) elAtts;
+ ev.addEdit(new AttributeUndoableEdit(el, copy, false));
+ matts.removeAttribute(HTML.Attribute.SRC);
+ matts.addAttribute(HTML.Attribute.SRC, url.toString());
+ ev.end();
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ finally
+ {
+ writeUnlock();
+ }
+ }
+
+ /**
+ * Updates the frameset that is represented by the specified element
+ * to create a frame that refers to the specified URL.
+ *
+ * @param el the element
+ * @param url the url
+ */
+ private void updateFrameSet(Element el, URL url)
+ {
+ int start = el.getStartOffset();
+ int end = el.getEndOffset();
+
+ StringBuilder html = new StringBuilder();
+ html.append("<frame");
+ if (url != null)
+ {
+ html.append(" src=\"");
+ html.append(url.toString());
+ html.append("\"");
+ }
+ html.append('>');
+ if (getParser() == null)
+ setParser(new HTMLEditorKit().getParser());
+ try
+ {
+ setOuterHTML(el, html.toString());
+ }
+ catch (BadLocationException ex)
+ {
+ ex.printStackTrace();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
/**
* Gets an iterator for the given HTML.Tag.
* @param t the requested HTML.Tag
@@ -529,8 +649,13 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected MutableAttributeSet charAttr = new SimpleAttributeSet();
- protected Vector<ElementSpec> parseBuffer = new Vector<ElementSpec>();
-
+ protected Vector<ElementSpec> parseBuffer = new Vector<ElementSpec>();
+
+ /**
+ * The parse stack. It holds the current element tree path.
+ */
+ private Stack<HTML.Tag> parseStack = new Stack<HTML.Tag>();
+
/**
* A stack for character attribute sets *
*/
@@ -577,16 +702,6 @@ 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.
*
@@ -676,6 +791,10 @@ public class HTMLDocument extends DefaultStyledDocument
// Put the old attribute set on the stack.
pushCharacterStyle();
+ // Initialize with link pseudo class.
+ if (t == HTML.Tag.A)
+ a.addAttribute(HTML.Attribute.PSEUDO_CLASS, "link");
+
// Just add the attributes in <code>a</code>.
charAttr.addAttribute(t, a.copyAttributes());
}
@@ -828,7 +947,6 @@ public class HTMLDocument extends DefaultStyledDocument
public void start(HTML.Tag t, MutableAttributeSet a)
{
super.start(t, a);
- inParagraph = true;
}
/**
@@ -838,7 +956,6 @@ public class HTMLDocument extends DefaultStyledDocument
public void end(HTML.Tag t)
{
super.end(t);
- inParagraph = false;
}
}
@@ -954,20 +1071,9 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
+ baseTarget = (String) a.getAttribute(HTML.Attribute.TARGET);
}
-
- /**
- * 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.
- }
}
class HeadAction extends BlockAction
@@ -1529,9 +1635,12 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
{
- if (inImpliedParagraph)
+ if (inImpliedParagraph())
blockClose(HTML.Tag.IMPLIED);
+ // Push the new tag on top of the stack.
+ parseStack.push(t);
+
DefaultStyledDocument.ElementSpec element;
AbstractDocument.AttributeContext ctx = getAttributeContext();
@@ -1543,6 +1652,34 @@ public class HTMLDocument extends DefaultStyledDocument
}
/**
+ * Returns true when we are currently inside a paragraph, either
+ * a real one or an implied, false otherwise.
+ *
+ * @return
+ */
+ private boolean inParagraph()
+ {
+ boolean inParagraph = false;
+ if (! parseStack.isEmpty())
+ {
+ HTML.Tag top = parseStack.peek();
+ inParagraph = top == HTML.Tag.P || top == HTML.Tag.IMPLIED;
+ }
+ return inParagraph;
+ }
+
+ private boolean inImpliedParagraph()
+ {
+ boolean inParagraph = false;
+ if (! parseStack.isEmpty())
+ {
+ HTML.Tag top = parseStack.peek();
+ inParagraph = top == HTML.Tag.IMPLIED;
+ }
+ return inParagraph;
+ }
+
+ /**
* Instructs the parse buffer to close the block element associated with
* the given HTML.Tag
*
@@ -1552,13 +1689,12 @@ public class HTMLDocument extends DefaultStyledDocument
{
DefaultStyledDocument.ElementSpec element;
- if (inImpliedParagraph)
- {
- inImpliedParagraph = false;
- inParagraph = false;
- if (t != HTML.Tag.IMPLIED)
- blockClose(HTML.Tag.IMPLIED);
- }
+ if (inImpliedParagraph() && t != HTML.Tag.IMPLIED)
+ blockClose(HTML.Tag.IMPLIED);
+
+ // Pull the token from the stack.
+ if (! parseStack.isEmpty()) // Just to be sure.
+ parseStack.pop();
// If the previous tag is a start tag then we insert a synthetic
// content tag.
@@ -1602,11 +1738,9 @@ public class HTMLDocument extends DefaultStyledDocument
protected void addContent(char[] data, int offs, int length,
boolean generateImpliedPIfNecessary)
{
- if (generateImpliedPIfNecessary && (! inParagraph) && (! inPreTag))
+ if (generateImpliedPIfNecessary && ! inParagraph())
{
blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
- inParagraph = true;
- inImpliedParagraph = true;
}
AbstractDocument.AttributeContext ctx = getAttributeContext();
@@ -1651,11 +1785,9 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
{
- if (t != HTML.Tag.FRAME && ! inParagraph && ! inImpliedParagraph)
+ if (t != HTML.Tag.FRAME && ! inParagraph())
{
blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
- inParagraph = true;
- inImpliedParagraph = true;
}
a.addAttribute(StyleConstants.NameAttribute, t);
@@ -1666,7 +1798,7 @@ public class HTMLDocument extends DefaultStyledDocument
DefaultStyledDocument.ElementSpec spec =
new DefaultStyledDocument.ElementSpec(a.copyAttributes(),
DefaultStyledDocument.ElementSpec.ContentType,
- new char[] {' ', ' '}, 0, 2 );
+ new char[] {' '}, 0, 1 );
parseBuffer.add(spec);
}
@@ -1955,4 +2087,83 @@ public void setOuterHTML(Element elem, String htmlText)
}
super.insertUpdate(evt, att);
}
+
+ /**
+ * Returns <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise.
+ *
+ * @return <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise
+ */
+ boolean isFrameDocument()
+ {
+ return frameDocument;
+ }
+
+ /**
+ * Set <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise.
+ *
+ * @param frameDoc <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise
+ */
+ void setFrameDocument(boolean frameDoc)
+ {
+ frameDocument = frameDoc;
+ }
+
+ /**
+ * Returns the target that is specified in the base tag, if this is the case.
+ *
+ * @return the target that is specified in the base tag, if this is the case
+ */
+ String getBaseTarget()
+ {
+ return baseTarget;
+ }
+
+ /**
+ * Updates the A tag's pseudo class value in response to a hyperlink
+ * action.
+ *
+ * @param el the corresponding element
+ * @param value the new value
+ */
+ void updateSpecialClass(Element el, HTML.Attribute cl, String value)
+ {
+ try
+ {
+ writeLock();
+ DefaultDocumentEvent ev =
+ new DefaultDocumentEvent(el.getStartOffset(), 1,
+ DocumentEvent.EventType.CHANGE);
+ AttributeSet elAtts = el.getAttributes();
+ AttributeSet anchorAtts = (AttributeSet) elAtts.getAttribute(HTML.Tag.A);
+ if (anchorAtts != null)
+ {
+ AttributeSet copy = elAtts.copyAttributes();
+ StyleSheet ss = getStyleSheet();
+ if (value != null)
+ {
+ anchorAtts = ss.addAttribute(anchorAtts, cl, value);
+ }
+ else
+ {
+ anchorAtts = ss.removeAttribute(anchorAtts, cl);
+ }
+ MutableAttributeSet matts = (MutableAttributeSet) elAtts;
+ ev.addEdit(new AttributeUndoableEdit(el, copy, false));
+ matts.removeAttribute(HTML.Tag.A);
+ matts.addAttribute(HTML.Tag.A, anchorAtts);
+ ev.end();
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ }
+ finally
+ {
+ writeUnlock();
+ }
+ }
+
}
diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java
index f3a3d90b6..3b122bb36 100644
--- a/javax/swing/text/html/HTMLEditorKit.java
+++ b/javax/swing/text/html/HTMLEditorKit.java
@@ -98,7 +98,12 @@ public class HTMLEditorKit
extends MouseAdapter
implements MouseMotionListener, Serializable
{
-
+
+ /**
+ * The element of the last anchor tag.
+ */
+ private Element lastAnchorElement;
+
/**
* Constructor
*/
@@ -162,10 +167,41 @@ public class HTMLEditorKit
AttributeSet aAtts = (AttributeSet)
el.getAttributes().getAttribute(HTML.Tag.A);
if (aAtts != null)
- newCursor = kit.getLinkCursor();
+ {
+ if (el != lastAnchorElement)
+ {
+ if (lastAnchorElement != null)
+ htmlDoc.updateSpecialClass(lastAnchorElement,
+ HTML.Attribute.DYNAMIC_CLASS,
+ null);
+ lastAnchorElement = el;
+ htmlDoc.updateSpecialClass(el,
+ HTML.Attribute.DYNAMIC_CLASS,
+ "hover");
+ }
+ newCursor = kit.getLinkCursor();
+ }
+ else
+ {
+ if (lastAnchorElement != null)
+ htmlDoc.updateSpecialClass(lastAnchorElement,
+ HTML.Attribute.DYNAMIC_CLASS,
+ null);
+ lastAnchorElement = null;
+ }
+ }
+ else
+ {
+ if (lastAnchorElement != null)
+ htmlDoc.updateSpecialClass(lastAnchorElement,
+ HTML.Attribute.DYNAMIC_CLASS,
+ null);
+ lastAnchorElement = null;
}
if (editor.getCursor() != newCursor)
- editor.setCursor(newCursor);
+ {
+ editor.setCursor(newCursor);
+ }
}
}
}
@@ -198,6 +234,8 @@ public class HTMLEditorKit
if (anchorAtts != null)
{
href = (String) anchorAtts.getAttribute(HTML.Attribute.HREF);
+ htmlDoc.updateSpecialClass(el, HTML.Attribute.PSEUDO_CLASS,
+ "visited");
}
else
{
@@ -243,10 +281,25 @@ public class HTMLEditorKit
{
url = null;
}
- // TODO: Handle frame documents and target here.
- HyperlinkEvent ev =
- new HyperlinkEvent(editor, HyperlinkEvent.EventType.ACTIVATED, url,
- href, el);
+ HyperlinkEvent ev;
+ if (doc.isFrameDocument())
+ {
+ String target = null;
+ if (anchor != null)
+ target = (String) anchor.getAttribute(HTML.Attribute.TARGET);
+ if (target == null || target.equals(""))
+ target = doc.getBaseTarget();
+ if (target == null || target.equals(""))
+ target = "_self";
+ ev = new HTMLFrameHyperlinkEvent(editor,
+ HyperlinkEvent.EventType.ACTIVATED,
+ url, href, el, target);
+ }
+ else
+ {
+ ev = new HyperlinkEvent(editor, HyperlinkEvent.EventType.ACTIVATED,
+ url, href, el);
+ }
return ev;
}
}
@@ -773,14 +826,14 @@ public class HTMLEditorKit
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))
view = new FrameSetView(element);
else if (tag.equals(HTML.Tag.FRAME))
- view = new FrameView(element); */
+ view = new FrameView(element);
+ // FIXME: Uncomment when the views have been implemented
+ /*
+ else if (tag.equals(HTML.Tag.OBJECT))
+ view = new ObjectView(element); */
}
if (view == null)
{
@@ -1065,13 +1118,22 @@ public class HTMLEditorKit
/** The editor pane used. */
JEditorPane editorPane;
-
+
+ /**
+ * Whether or not the editor kit handles form submissions.
+ *
+ * @see #isAutoFormSubmission()
+ * @see #setAutoFormSubmission(boolean)
+ */
+ private boolean autoFormSubmission;
+
/**
* Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.
*/
public HTMLEditorKit()
{
linkController = new LinkController();
+ autoFormSubmission = true;
}
/**
@@ -1416,4 +1478,39 @@ public class HTMLEditorKit
styleSheet = s;
}
+ /**
+ * Returns <code>true</code> when forms should be automatically submitted
+ * by the editor kit. Set this to <code>false</code> when you want to
+ * intercept form submission. In this case you'd want to listen for
+ * hyperlink events on the document and handle FormSubmitEvents specially.
+ *
+ * The default is <code>true</code>.
+ *
+ * @return <code>true</code> when forms should be automatically submitted
+ * by the editor kit, <code>false</code> otherwise
+ *
+ * @since 1.5
+ *
+ * @see #setAutoFormSubmission(boolean)
+ * @see FormSubmitEvent
+ */
+ public boolean isAutoFormSubmission()
+ {
+ return autoFormSubmission;
+ }
+
+ /**
+ * Sets whether or not the editor kit should automatically submit forms.
+ *
+ * @param auto <code>true</code> when the editor kit should handle form
+ * submission, <code>false</code> otherwise
+ *
+ * @since 1.5
+ *
+ * @see #isAutoFormSubmission()
+ */
+ public void setAutoFormSubmission(boolean auto)
+ {
+ autoFormSubmission = auto;
+ }
}
diff --git a/javax/swing/text/html/ImageView.java b/javax/swing/text/html/ImageView.java
index f073c6d05..050eb16e2 100644
--- a/javax/swing/text/html/ImageView.java
+++ b/javax/swing/text/html/ImageView.java
@@ -111,6 +111,16 @@ public class ImageView extends View
private ImageObserver observer;
/**
+ * The CSS width and height.
+ */
+ private Length[] spans;
+
+ /**
+ * The cached attributes.
+ */
+ private AttributeSet attributes;
+
+ /**
* Creates the image view that represents the given element.
*
* @param element the element, represented by this image view.
@@ -221,12 +231,9 @@ public class ImageView extends View
*/
public AttributeSet getAttributes()
{
- StyleSheet styles = getStyleSheet();
- if (styles == null)
- return super.getAttributes();
- else
- return CombinedAttributes.combine(super.getAttributes(),
- styles.getViewAttributes(this));
+ if (attributes == null)
+ attributes = getStyleSheet().getViewAttributes(this);
+ return attributes;
}
/**
@@ -318,9 +325,8 @@ public class ImageView extends View
if (axis == View.X_AXIS)
{
- Object w = attrs.getAttribute(CSS.Attribute.WIDTH);
- if (w instanceof Length)
- return ((Length) w).getValue();
+ if (spans[axis] != null)
+ return spans[axis].getValue();
else if (image != null)
return image.getWidth(getContainer());
else
@@ -328,9 +334,8 @@ public class ImageView extends View
}
else if (axis == View.Y_AXIS)
{
- Object w = attrs.getAttribute(CSS.Attribute.HEIGHT);
- if (w instanceof Length)
- return ((Length) w).getValue();
+ if (spans[axis] != null)
+ return spans[axis].getValue();
else if (image != null)
return image.getHeight(getContainer());
else
@@ -347,11 +352,8 @@ public class ImageView extends View
*/
protected StyleSheet getStyleSheet()
{
- Document d = getElement().getDocument();
- if (d instanceof HTMLDocument)
- return ((HTMLDocument) d).getStyleSheet();
- else
- return null;
+ HTMLDocument doc = (HTMLDocument) getDocument();
+ return doc.getStyleSheet();
}
/**
@@ -410,7 +412,21 @@ public class ImageView extends View
*/
protected void setPropertiesFromAttributes()
{
- // FIXME: Implement this properly.
+ AttributeSet atts = getAttributes();
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
+ spans = new Length[2];
+ spans[X_AXIS] = (Length) atts.getAttribute(CSS.Attribute.WIDTH);
+ if (spans[X_AXIS] != null)
+ {
+ spans[X_AXIS].setFontBases(emBase, exBase);
+ }
+ spans[Y_AXIS] = (Length) atts.getAttribute(CSS.Attribute.HEIGHT);
+ if (spans[Y_AXIS] != null)
+ {
+ spans[Y_AXIS].setFontBases(emBase, exBase);
+ }
}
/**
@@ -503,7 +519,7 @@ public class ImageView extends View
{
AttributeSet atts = getAttributes();
// Fetch width.
- Length l = (Length) atts.getAttribute(CSS.Attribute.WIDTH);
+ Length l = spans[X_AXIS];
if (l != null)
{
newW = (int) l.getValue();
@@ -514,7 +530,7 @@ public class ImageView extends View
newW = newIm.getWidth(observer);
}
// Fetch height.
- l = (Length) atts.getAttribute(CSS.Attribute.HEIGHT);
+ l = spans[Y_AXIS];
if (l != null)
{
newH = (int) l.getValue();
diff --git a/javax/swing/text/html/InlineView.java b/javax/swing/text/html/InlineView.java
index 6b134ae39..cea0782b1 100644
--- a/javax/swing/text/html/InlineView.java
+++ b/javax/swing/text/html/InlineView.java
@@ -139,6 +139,7 @@ public class InlineView
StyleSheet ss = getStyleSheet();
attributes = ss.getViewAttributes(this);
preferenceChanged(null, true, true);
+ setPropertiesFromAttributes();
}
/**
@@ -303,4 +304,5 @@ public class InlineView
}
return span;
}
+
}
diff --git a/javax/swing/text/html/ParagraphView.java b/javax/swing/text/html/ParagraphView.java
index 8443515d3..d149627ff 100644
--- a/javax/swing/text/html/ParagraphView.java
+++ b/javax/swing/text/html/ParagraphView.java
@@ -153,8 +153,15 @@ public class ParagraphView
(short) painter.getInset(BOTTOM, this),
(short) painter.getInset(RIGHT, this));
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(attributes);
+ float exBase = ss.getEXBase(attributes);
cssWidth = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
+ if (cssWidth != null)
+ cssWidth.setFontBases(emBase, exBase);
cssHeight = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
+ if (cssHeight != null)
+ cssHeight.setFontBases(emBase, exBase);
}
}
diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java
index 3322a390c..15384e16d 100644
--- a/javax/swing/text/html/StyleSheet.java
+++ b/javax/swing/text/html/StyleSheet.java
@@ -52,6 +52,8 @@ import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -66,6 +68,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import javax.swing.border.Border;
import javax.swing.event.ChangeListener;
@@ -300,11 +303,21 @@ public class StyleSheet extends StyleContext
selector.append('#');
selector.append(atts.getAttribute(HTML.Attribute.ID));
}
- else if (atts.isDefined(HTML.Attribute.CLASS))
+ if (atts.isDefined(HTML.Attribute.CLASS))
{
selector.append('.');
selector.append(atts.getAttribute(HTML.Attribute.CLASS));
}
+ if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
+ }
+ if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
+ }
selector.append(' ');
}
selector.append(t.toString());
@@ -326,11 +339,21 @@ public class StyleSheet extends StyleContext
selector.append('#');
selector.append(atts.getAttribute(HTML.Attribute.ID));
}
- else if (atts.isDefined(HTML.Attribute.CLASS))
+ if (atts.isDefined(HTML.Attribute.CLASS))
{
selector.append('.');
selector.append(atts.getAttribute(HTML.Attribute.CLASS));
}
+ if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
+ }
+ if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
+ }
}
return getResolvedStyle(selector.toString(), path, t);
}
@@ -357,7 +380,7 @@ public class StyleSheet extends StyleContext
/**
* Resolves a style. This creates arrays that hold the tag names,
* class and id attributes and delegates the work to
- * {@link #resolveStyle(String, String[], String[], String[])}.
+ * {@link #resolveStyle(String, String[], Map[])}.
*
* @param selector the selector
* @param path the Element path
@@ -369,8 +392,7 @@ public class StyleSheet extends StyleContext
{
int count = path.size();
String[] tags = new String[count];
- String[] ids = new String[count];
- String[] classes = new String[count];
+ Map[] attributes = new Map[count];
for (int i = 0; i < count; i++)
{
Element el = (Element) path.get(i);
@@ -391,24 +413,16 @@ public class StyleSheet extends StyleContext
tags[i] = t.toString();
else
tags[i] = null;
- if (atts.isDefined(HTML.Attribute.CLASS))
- classes[i] = atts.getAttribute(HTML.Attribute.CLASS).toString();
- else
- classes[i] = null;
- if (atts.isDefined(HTML.Attribute.ID))
- ids[i] = atts.getAttribute(HTML.Attribute.ID).toString();
- else
- ids[i] = null;
+ attributes[i] = attributeSetToMap(atts);
}
else
{
tags[i] = null;
- classes[i] = null;
- ids[i] = null;
+ attributes[i] = null;
}
}
tags[0] = tag.toString();
- return resolveStyle(selector, tags, ids, classes);
+ return resolveStyle(selector, tags, attributes);
}
/**
@@ -416,13 +430,11 @@ public class StyleSheet extends StyleContext
*
* @param selector the selector
* @param tags the tags
- * @param ids the corresponding ID attributes
- * @param classes the corresponding CLASS attributes
+ * @param attributes the attributes of the tags
*
* @return the resolved style
*/
- private Style resolveStyle(String selector, String[] tags, String[] ids,
- String[] classes)
+ private Style resolveStyle(String selector, String[] tags, Map[] attributes)
{
// FIXME: This style resolver is not correct. But it works good enough for
// the default.css.
@@ -431,7 +443,7 @@ public class StyleSheet extends StyleContext
for (Iterator i = css.iterator(); i.hasNext();)
{
CSSStyle style = (CSSStyle) i.next();
- if (style.selector.matches(tags, classes, ids))
+ if (style.selector.matches(tags, attributes))
styles.add(style);
}
@@ -444,7 +456,7 @@ public class StyleSheet extends StyleContext
for (int j = ss.css.size() - 1; j >= 0; j--)
{
CSSStyle style = (CSSStyle) ss.css.get(j);
- if (style.selector.matches(tags, classes, ids))
+ if (style.selector.matches(tags, attributes))
styles.add(style);
}
}
@@ -741,8 +753,13 @@ public class StyleSheet extends StyleContext
.getAttributes();
o = tableAttrs.getAttribute(HTML.Attribute.CELLPADDING);
if (o != null)
- cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING,
- new Length(o.toString()));
+ {
+ Length l = new Length(o.toString());
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_BOTTOM, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_LEFT, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_RIGHT, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_TOP, l);
+ }
}
// TODO: Add more mappings.
return cssAttr;
@@ -882,7 +899,37 @@ public class StyleSheet extends StyleContext
style |= fStyle.getValue();
return new Font(family, style, realSize);
}
-
+
+ /**
+ * Determines the EM base value based on the specified attributes.
+ *
+ * @param atts the attibutes
+ *
+ * @return the EM base value
+ */
+ float getEMBase(AttributeSet atts)
+ {
+ Font font = getFont(atts);
+ FontRenderContext ctx = new FontRenderContext(null, false, false);
+ Rectangle2D bounds = font.getStringBounds("M", ctx);
+ return (float) bounds.getWidth();
+ }
+
+ /**
+ * Determines the EX base value based on the specified attributes.
+ *
+ * @param atts the attibutes
+ *
+ * @return the EX base value
+ */
+ float getEXBase(AttributeSet atts)
+ {
+ Font font = getFont(atts);
+ FontRenderContext ctx = new FontRenderContext(null, false, false);
+ Rectangle2D bounds = font.getStringBounds("x", ctx);
+ return (float) bounds.getHeight();
+ }
+
/**
* Resolves the fontsize for a given set of attributes.
*
@@ -1120,49 +1167,62 @@ public class StyleSheet extends StyleContext
*/
BoxPainter(AttributeSet as, StyleSheet ss)
{
+ float emBase = ss.getEMBase(as);
+ float exBase = ss.getEXBase(as);
// Fetch margins.
- Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN);
+ Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
if (l != null)
{
- topInset = bottomInset = leftInset = rightInset = l.getValue();
+ l.setFontBases(emBase, exBase);
+ leftInset = l.getValue();
}
- l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
- if (l != null)
- leftInset = l.getValue();
- else if (as.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.UL)
- System.err.println("UL margin left value: " + l + " atts: " + as);
l = (Length) as.getAttribute(CSS.Attribute.MARGIN_RIGHT);
if (l != null)
- rightInset = l.getValue();
+ {
+ l.setFontBases(emBase, exBase);
+ rightInset = l.getValue();
+ }
l = (Length) as.getAttribute(CSS.Attribute.MARGIN_TOP);
if (l != null)
- topInset = l.getValue();
+ {
+ l.setFontBases(emBase, exBase);
+ topInset = l.getValue();
+ }
l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM);
if (l != null)
- bottomInset = l.getValue();
+ {
+ l.setFontBases(emBase, exBase);
+ bottomInset = l.getValue();
+ }
// Fetch padding.
- l = (Length) as.getAttribute(CSS.Attribute.PADDING);
+ l = (Length) as.getAttribute(CSS.Attribute.PADDING_LEFT);
if (l != null)
{
- leftPadding = rightPadding = topPadding = bottomPadding =
- l.getValue();
+ l.setFontBases(emBase, exBase);
+ leftPadding = l.getValue();
}
- l = (Length) as.getAttribute(CSS.Attribute.PADDING_LEFT);
- if (l != null)
- leftPadding = l.getValue();
l = (Length) as.getAttribute(CSS.Attribute.PADDING_RIGHT);
if (l != null)
- rightPadding = l.getValue();
+ {
+ l.setFontBases(emBase, exBase);
+ rightPadding = l.getValue();
+ }
l = (Length) as.getAttribute(CSS.Attribute.PADDING_TOP);
if (l != null)
- topPadding = l.getValue();
+ {
+ l.setFontBases(emBase, exBase);
+ topPadding = l.getValue();
+ }
l = (Length) as.getAttribute(CSS.Attribute.PADDING_BOTTOM);
if (l != null)
- bottomPadding = l.getValue();
+ {
+ l.setFontBases(emBase, exBase);
+ bottomPadding = l.getValue();
+ }
// Determine border.
- border = new CSSBorder(as);
+ border = new CSSBorder(as, ss);
// Determine background.
background = ss.getBackground(as);
@@ -1229,15 +1289,18 @@ public class StyleSheet extends StyleContext
*/
public void paint(Graphics g, float x, float y, float w, float h, View v)
{
-
+ int inX = (int) (x + leftInset);
+ int inY = (int) (y + topInset);
+ int inW = (int) (w - leftInset - rightInset);
+ int inH = (int) (h - topInset - bottomInset);
if (background != null)
{
g.setColor(background);
- g.fillRect((int) x, (int) y, (int) w, (int) h);
+ g.fillRect(inX, inY, inW, inH);
}
if (border != null)
{
- border.paintBorder(null, g, (int) x, (int) y, (int) w, (int) h);
+ border.paintBorder(null, g, inX, inY, inW, inH);
}
}
}
@@ -1342,4 +1405,23 @@ public class StyleSheet extends StyleContext
}
}
+ /**
+ * Converts an AttributeSet to a Map. This is used for CSS resolving.
+ *
+ * @param atts the attributes to convert
+ *
+ * @return the converted map
+ */
+ private Map attributeSetToMap(AttributeSet atts)
+ {
+ HashMap map = new HashMap();
+ Enumeration keys = atts.getAttributeNames();
+ while (keys.hasMoreElements())
+ {
+ Object key = keys.nextElement();
+ Object value = atts.getAttribute(key);
+ map.put(key.toString(), value.toString());
+ }
+ return map;
+ }
}
diff --git a/javax/swing/text/html/TableView.java b/javax/swing/text/html/TableView.java
index 971d54cb6..90b3ecc4f 100644
--- a/javax/swing/text/html/TableView.java
+++ b/javax/swing/text/html/TableView.java
@@ -140,6 +140,7 @@ class TableView
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
int spans[])
{
+ updateGrid();
int numCols = offsets.length;
int realColumn = 0;
for (int i = 0; i < numCols; i++)
@@ -255,6 +256,11 @@ class TableView
Length[] columnWidths;
/**
+ * The table width.
+ */
+ private Length width;
+
+ /**
* Indicates if the grid setup is ok.
*/
boolean gridValid;
@@ -358,13 +364,11 @@ class TableView
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)
+ if (width != null)
{
- int width = (int) l.getValue();
- if (r.minimum < width)
- r.minimum = width;
+ int w = (int) width.getValue();
+ if (r.minimum < w)
+ r.minimum = w;
}
// Adjust requirements when we have cell spacing.
@@ -373,6 +377,7 @@ class TableView
r.preferred += adjust;
// Apply the alignment.
+ AttributeSet atts = getAttributes();
Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN);
r.alignment = 0.0F;
if (o != null)
@@ -660,11 +665,17 @@ class TableView
/**
* Updates the arrays that contain the row and column data in response
* to a change to the table structure.
+ *
+ * Package private to avoid accessor methods.
*/
- private void updateGrid()
+ void updateGrid()
{
if (! gridValid)
{
+ AttributeSet atts = getAttributes();
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
int maxColumns = 0;
int numRows = getViewCount();
for (int r = 0; r < numRows; r++)
@@ -697,7 +708,10 @@ class TableView
cv.getAttributes().getAttribute(CSS.Attribute.WIDTH);
if (o != null && columnWidths[colIndex] == null
&& o instanceof Length)
- columnWidths[colIndex]= (Length) o;
+ {
+ columnWidths[colIndex]= (Length) o;
+ columnWidths[colIndex].setFontBases(emBase, exBase);
+ }
colIndex += cv.colSpan;
}
}
@@ -741,12 +755,23 @@ class TableView
private void setPropertiesFromAttributes()
{
// Fetch and parse cell spacing.
- Object o = getAttributes().getAttribute(CSS.Attribute.BORDER_SPACING);
+ AttributeSet atts = getAttributes();
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
+ Object o = atts.getAttribute(CSS.Attribute.BORDER_SPACING);
if (o != null && o instanceof Length)
{
Length l = (Length) o;
+ l.setFontBases(emBase, exBase);
cellSpacing = (int) l.getValue();
}
+ o = atts.getAttribute(CSS.Attribute.WIDTH);
+ if (o != null && o instanceof Length)
+ {
+ width = (Length) o;
+ width.setFontBases(emBase, exBase);
+ }
}
/**