From 2a2b91f336fe4f6c2a314db2bc4cdffff6cf5a61 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Mon, 13 Nov 2006 00:29:48 +0000 Subject: 2006-11-13 Andrew John Hughes * Merge of HEAD-->generics from 2006/11/04-2006/11/12. --- ChangeLog | 561 +++++++++++++++ examples/Makefile.am | 7 +- .../gnu/classpath/examples/swing/HtmlDemo.java | 266 ++----- examples/gnu/classpath/examples/swing/forms.html | 69 ++ .../gnu/classpath/examples/swing/textstyles.html | 78 +++ examples/gnu/classpath/examples/swing/welcome.html | 52 ++ gnu/java/awt/peer/gtk/CairoGraphics2D.java | 21 +- gnu/java/awt/peer/gtk/ComponentGraphics.java | 225 +++++- gnu/java/awt/peer/gtk/GtkImageConsumer.java | 43 +- gnu/java/awt/peer/gtk/VolatileImageGraphics.java | 4 + .../peer/headless/HeadlessGraphicsEnvironment.java | 88 +++ gnu/java/awt/peer/headless/HeadlessToolkit.java | 371 ++++++++++ gnu/java/awt/peer/swing/SwingButtonPeer.java | 22 +- gnu/java/awt/peer/swing/SwingComponent.java | 6 +- gnu/java/awt/peer/swing/SwingComponentPeer.java | 196 +++++- gnu/java/awt/peer/swing/SwingContainerPeer.java | 209 ++++-- gnu/java/awt/peer/swing/SwingFramePeer.java | 11 +- gnu/java/awt/peer/swing/SwingLabelPeer.java | 48 +- gnu/java/awt/peer/swing/SwingListPeer.java | 352 ++++++++++ gnu/java/awt/peer/swing/SwingMenuBarPeer.java | 2 +- gnu/java/awt/peer/swing/SwingPanelPeer.java | 4 +- gnu/java/awt/peer/swing/SwingTextAreaPeer.java | 317 +++++++++ gnu/java/awt/peer/swing/SwingTextFieldPeer.java | 32 +- gnu/java/awt/peer/swing/SwingWindowPeer.java | 8 +- gnu/java/net/protocol/jar/Handler.java | 46 +- gnu/javax/swing/text/html/css/BorderWidth.java | 66 ++ gnu/javax/swing/text/html/css/CSSColor.java | 29 + gnu/javax/swing/text/html/css/CSSParser.java | 23 +- .../swing/text/html/css/CSSParserCallback.java | 2 +- gnu/javax/swing/text/html/css/CSSScanner.java | 1 + gnu/javax/swing/text/html/css/Length.java | 64 +- gnu/javax/swing/text/html/css/Selector.java | 233 +++++++ .../swing/text/html/parser/GnuParserDelegator.java | 3 +- .../swing/text/html/parser/HTML_401Swing.java | 91 --- .../swing/text/html/parser/support/Parser.java | 21 +- include/gnu_java_net_VMPlainDatagramSocketImpl.h | 30 - include/gnu_java_nio_channels_FileChannelImpl.h | 46 -- java/awt/FlowLayout.java | 5 +- java/awt/TextComponent.java | 4 +- java/awt/TextField.java | 12 +- java/awt/Toolkit.java | 9 + java/beans/SimpleBeanInfo.java | 15 +- java/beans/beancontext/BeanContextSupport.java | 75 +- java/io/OutputStreamWriter.java | 6 + java/util/Collections.java | 15 +- java/util/regex/Matcher.java | 1 + javax/swing/JLabel.java | 35 +- javax/swing/JTree.java | 88 ++- javax/swing/text/ComponentView.java | 19 +- javax/swing/text/CompositeView.java | 2 +- javax/swing/text/FlowView.java | 31 +- javax/swing/text/GlyphView.java | 71 +- javax/swing/text/ParagraphView.java | 16 +- javax/swing/text/View.java | 21 +- javax/swing/text/html/BlockView.java | 204 +++++- javax/swing/text/html/CSS.java | 56 +- javax/swing/text/html/CSSBorder.java | 420 +++++++++++ javax/swing/text/html/HTMLDocument.java | 152 ++-- javax/swing/text/html/HTMLEditorKit.java | 10 +- javax/swing/text/html/HTMLWriter.java | 50 +- javax/swing/text/html/InlineView.java | 102 ++- javax/swing/text/html/ListView.java | 3 - javax/swing/text/html/ParagraphView.java | 119 +++- javax/swing/text/html/StyleSheet.java | 278 ++++++-- javax/swing/text/html/TableView.java | 616 ++++++++++++++-- javax/swing/text/html/parser/DocumentParser.java | 4 +- javax/swing/text/html/parser/ParserDelegator.java | 4 +- .../gnu_java_net_VMPlainDatagramSocketImpl.c | 406 ----------- native/jni/java-nio/Makefile.am | 1 - native/jni/java-nio/gnu_java_nio_VMChannel.c | 4 +- .../gnu_java_nio_channels_FileChannelImpl.c | 773 --------------------- 71 files changed, 5170 insertions(+), 2104 deletions(-) create mode 100644 examples/gnu/classpath/examples/swing/forms.html create mode 100644 examples/gnu/classpath/examples/swing/textstyles.html create mode 100644 examples/gnu/classpath/examples/swing/welcome.html create mode 100644 gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java create mode 100644 gnu/java/awt/peer/headless/HeadlessToolkit.java create mode 100644 gnu/java/awt/peer/swing/SwingListPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingTextAreaPeer.java create mode 100644 gnu/javax/swing/text/html/css/BorderWidth.java create mode 100644 gnu/javax/swing/text/html/css/Selector.java delete mode 100644 gnu/javax/swing/text/html/parser/HTML_401Swing.java delete mode 100644 include/gnu_java_net_VMPlainDatagramSocketImpl.h delete mode 100644 include/gnu_java_nio_channels_FileChannelImpl.h create mode 100644 javax/swing/text/html/CSSBorder.java delete mode 100644 native/jni/java-net/gnu_java_net_VMPlainDatagramSocketImpl.c delete mode 100644 native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c diff --git a/ChangeLog b/ChangeLog index e19e1bb74..8e4952f17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,564 @@ +2006-11-11 Andreas Tobler + + * gnu/java/awt/peer/gtk/GtkImageConsumer.java (setPixels): Handle data + from big endian systems correctly. + +2006-11-11 Roman Kennke + + * gnu/javax/swing/text/html/css/CSSColor.java + (isValidColor): New helper method. Checks strings if they + form a valid color value. + * gnu/javax/swing/text/html/css/Length.java + (Length): Catch number format exceptions. + * javax/swing/text/html/CSS.java + (addInternal): New method. Checks for shorthand CSS attributes + and parses them. + (parseBackgroundShorthand): New method. Parses the background + shorthand attribute. + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.LinkAction): Made class a subclass of HiddenAction. + (HTMLReader.LinkAction.start): Implemented to load the linked + stylesheet. + (HTMLReader.LinkAction.end): Removed. This is not needed. + * javax/swing/text/html/StyleSheet.java + (CSSStyleSheetParserCallback.declaration): Push declaration + through CSS.addInternal() to parse shorthand attributes. + (addCSSAttribute): Push declaration through CSS.addInternal() + to parse shorthand attributes. + (importStyleSheet): Implemented. This adds a stylesheet from + an URL. + * javax/swing/text/html/TableView.java + (calculateColumnRequirements): Increase column index for + non CellView children to avoid endless loop. + * javax/swing/text/CompositeView.java + (setParent): Comparen with numChildren not with real arraylength. + +2006-11-11 David Gilbert + + * java/beans/beancontext/BeanContextSupport.java + (getChildBeanContextChild): Implemented. + +2006-11-10 Roman Kennke + + * javax/swing/text/View.java + (updateLayout): Only repaint when needed. + +2006-11-10 David Gilbert + + * java/util/Collections.java + (sort(List)): Minor API doc addition, + (sort(List, Comparator)): Likewise. + +2006-11-10 David Fu + + * javax/swing/text/html/HTMLWriter.java + (traverse): Removed Classpath specific handling of implied + tags. + (traverseHtmlFragment): Removed Classpath specific handling of + implied tags. + +2006-11-10 Roman Kennke + + * javax/swing/text/ParagraphView.java + (Row.getMaximumSize): Removed. This method is not necessary. + * javax/swing/text/html/TableView.java + (CellView): Moved attribute init to setPropertiesFromAttributes(). + (setPropertiesFromAttributes): Fetch attributes here. + (RowView.RowView): Documented. + (RowView.getMaximumSpan): Overridden to restrict the max span + in the Y direction. + (RowView.layoutMajorAxis): Correctly layout the spans. + (columnWidths): New field. Stores the width attributes of + the columns. + (calculateColumnRequirements): Added support for relative + (== percent) width attributes. + (calculateMajorAxisRequirements): Removed. + (calculateMinorAxisRequirements): Removed unnecessary code. + (getMaximumSpan): Overridden to restrict the table's width. + (layoutColumns): Documented. Implement more clever table layout, + i.e. for relative columns etc. + (layoutMinorAxis): Don't mark rows invalid. + (updateGrid): Added docs. Initialize column widths. + +2006-11-09 Roman Kennke + + * gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment, + * gnu/java/awt/peer/headless/HeadlessToolkit: New classes. + Implement basic headless toolkit. + * java/awt/Toolkit.java + (getDefaultToolkit): Check headless property and create + headless toolkit when true. + +2006-11-09 Ingo Proetel +2006-11-09 Roman Kennke + + * gnu/java/awt/peer/swing/SwingButtonPeer.java + (SwingButton.button): New field. + (SwingButton.SwingButton): Added constructor. + (SwingButton.isShowing): Access button field instead of + the surrounding class. + (SwingButton.getParent): Access button field instead of + the surrounding class. + (SwingButtonPeer): Call new SwingButton constructor. + * gnu/java/awt/peer/swing/SwingComponent.java: + Several documentation updates. + * gnu/java/awt/peer/swing/SwingComponentPeer.java + (currentPaintEvents): New field. + (peerFont): New field. + (SwingComponentPeer): Initialize currentPaintEvents fields. + (coalescePaintEvents): Implemented. + (dispose): Unregister peer from heavyweight list of its container. + (getGraphics): Fetch graphics from parent component. + (handleEvent): Discard paint event if its coalesced. + (init): Register component with its container for proper painting. + (paint): Call peerPaint(). + (peerPaint): Added argument that indicates if we should update. + Call paint or update on the actual AWT component. + (peerPaintComponent): New method. Paints the peer (Swing) component. + (setFont): Set peerFont field. + * gnu/java/awt/peer/swing/SwingContainerPeer.java + (backbuffer): New field. + (focusOwner): New field. + (heavyweightDescendents): New field. + (SwingContainerPeer): Take Container as argument. Don't call init + yet. + (addHeavyweightDescendent): New method. + (getFocusOwner): New helper method. + (getInsets): Delegate to insets(). + (handleKeyEvent): Dispatch event to focus owner. + (handleMouseEvent): Dispatch to child component. + (isDoubleBuffering): New helper method. + (peerPaint): Overridden to implement container painting with + double buffering. + (peerPaintChildren): New method. Paints the descendents of this + container. + (removeHeavyweightDescendent): New helper method. + * gnu/java/awt/peer/swing/SwingFramePeer.java + (peerPaint): Removed. + (peerPaintComponent): Overridden to paint the menu bar. + * gnu/java/awt/peer/swing/SwingLabelPeer.java + (SwingLabel.label): New field. + (SwingLabel.SwingLabel): Added constructor with Label argument. + (SwingLabel.getGraphics): Implemented to fetch the graphics from + the actual AWT component. + (SwingLabel.getParent): Implemented to fetch the parent from + the AWT component. + (SwingLabel.isShowing): Access the label field. + (SwingLabelPeer): Set alignment from label. + * gnu/java/awt/peer/swing/SwingListPeer.java: New class. + * gnu/java/awt/peer/swing/SwingMenuBarPeer.java: Documentation + fixlet. + * gnu/java/awt/peer/swing/SwingPanelPeer.java: + Don't be a lighweight peer. + (SwingPanelPeer): Call init. + * gnu/java/awt/peer/swing/SwingTextAreaPeer.java: New class. + * gnu/java/awt/peer/swing/SwingTextFieldPeer.java + (SwingTextField.textField): New field. + (SwingTextField.SwingTextField): New constructor. + (SwingTextField.isShowing): Access field not enclosing class. + (SwingTextField.getGraphics): New method. + (SwingTextField.getParent): New method. + (SwingTextFieldPeer): Call new constructor. + (select): Renamed arguments. + * gnu/java/awt/peer/swing/SwingWindowPeer.java + (SwingWindowPeer): Call init. + +2006-11-09 Tania Bento + + * javax/swing/JLabel.java + (JLabel(Icon)): Changed documentation; Changed text to null. + (JLabel(Icon,int)): Likewise. + (JLabel(text)): Changed documenation. + (JLabel(text,int)): Likewise. + (JLabel(text,Icon,int)): Changed documentation; Throw + IllegalArgumentException if int is not one of LEFT, RIGHT, + CENTER, LEADING or TRAILING. + +2006-11-09 David Gilbert + + * java/beans/beancontext/BeanContextSupport.java + (BeanContextSupport): Use correct dtime default, + (BeanContextSupport(BeanContext)): Likewise, + (BeanContextSupport(BeanContext, Locale)): Likewise, plus renamed + locale argument, + (BeanContextSupport(BeanContext, Locale, boolean)): Likewise, + (BeanContextSupport(BeanContext, Locale, boolean, boolean)): Likewise. + +2006-11-09 David Gilbert + + * java/beans/beancontext/BeanContextSupport.java + (getBeanContextPeer): Implemented. + +2006-11-09 Roman Kennke + + * javax/swing/text/html/BlockView.java + (cssHeight): Removed. + (cssWidth): Removed. + (cssSpans): New field. Replaces the two fields above. + (BlockView): Allocate cssSpans array. + (layoutMinorAxis): Fetch and use child span, not this view's span. + (setCSSSpan): Adjusted to use cssSpans array. + (setPropertiesFromAttributes): Adjusted to use cssSpans array. + +2006-11-09 Roman Kennke + + * javax/swing/text/html/InlineView.java + (nowrap): New field. + (getBreakWeight): Add support for nowrap. + (setPropertiesFromAttributes): Fetch the nowrap setting. + +2006-11-09 Roman Kennke + + * gnu/javax/swing/text/html/css/CSSParser.java + (parseRuleset): Use new Selector class. + (parseValue): Parse multiple anys, not only one. + (main): Allow stylesheet be specified on the command line. + Use new Selector class. + * gnu/javax/swing/text/html/css/CSSParserCallback.java + (startStatement): Use Selector class. + * gnu/javax/swing/text/html/css/CSSScanner.java + (readName): Actually read a character in the loop to avoid + endless loop. + * gnu/javax/swing/text/html/css/Length.java + (getValue): Only multiply when we have a percentage value. + * gnu/javax/swing/text/html/css/Selector.java: + New class. Provides handling of CSS selectors. + * javax/swing/text/html/StyleSheet.java + (CSSStyle.PREC_AUTHOR_IMPORTANT): New constant field. + (CSSStyle.PREC_AUTHOR_NORMAL): New constant field. + (CSSStyle.PREC_NORM): New constant field. + (CSSStyle.PREC_UA): New constant field. + (CSSStyle.PREC_USER_IMPORTANT): New constant field. + (CSSStyle.precedence): New field. + (CSSStyle.priority): Removed. + (CSSStyle.selector): New field. + (CSSStyle.CSSStyle(int,Selector)): Initialize with Selector + and precendence. + (CSSStyle.compareTo): Adjusted to use the precedence and + specificity of the selector. + (CSSStyleSheetParserCallback.precedence): New field. + (CSSStyleSheetParserCallback.selector): Removed. + (CSSStyleSheetParserCallback.style): New field. + (CSSStyleSheetParserCallback.CSSStyleSheetParserCallback): + Initialize with precedence. + (CSSStyleSheetParserCallback.declaration): Don't look up + existing rule, simply create new one. + (CSSStyleSheetParserCallback.endStatement): Append style + to stylesheet. + (CSSStyleSheetParserCallback.startStatement): Use new Selector + class. + (css): Changed to be ArrayList. + (addRule): Create parser with author-normal precendence. + (getRule): Fixed implementation. + (loadRules): Create parser with UA precendence. + (resolveStyle): Use Selector class for resolving and matching + stylesheet rules. + (translateHTMLToCSS): Added mappings for a couple of HTML + attributes. + +2006-11-09 David Gilbert + + Fixes bug #29770 + * java/beans/SimpleBeanInfo.java + (loadImage): Check for nulls. + +2006-11-09 Robert Schuster + + * native/jni/java-nio/gnu_java_nio_VMChannel.c: + (getpeername): Added 16 byte offset to memcpy operation. + +2006-11-09 Robert Schuster + + * native/jni/java-nio/gnu_java_nio_VMChannel.c: + (getsockname): Added 16 byte offset to memcpy operation. + +2006-11-08 Mark Wielaard + + Fixes bug #29754 + * java/io/OutputStreamWriter.java + (OutputStreamWriter(OutputStream,Charset)): Set encodingName. + (OutputStreamWriter(OutputStream,CharsetEncoder)): Likewise. + +2006-11-08 Roman Kennke + + * javax/swing/text/html/HTMLEditorKit.java + (getParser): Use plain HTML_401F DTD. + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.print): Removed method and all calls to it. + (HTMLReader.printBuffer): Removed method and all calls to it. + (HTMLReader.inImpliedParagraph): New field. + (HTMLReader.inParagraph): New field. + (HTMLReader.addContent): Create implied p-tag if necessary. + (HTMLReader.addSpecialElement): Create implied p-tag if necessary. + (HTMLReader.blockClose): Close implied p-tag if necessary. + (HTMLReader.blockOpen): Close implied p-tag if necessary. + * gnu/javax/swing/text/html/parser/HTML_401Swing.java: Removed. + +2006-11-08 Roman Kennke + + * javax/swing/text/html/HTMLEditorKit.java + (HTMLFactory.create): Removed mapping for TD tag. This + is done in TableView. + * javax/swing/text/html/TableView.java: + Implemented from scratch. + +2006-11-07 Roman Kennke + + * gnu/javax/swing/text/html/parser/support/Parser.java + (_handleText): Check if text content is actually allowed before + passing empty text fragments on to the parser callbacks. + +2006-11-07 Mark Wielaard + + * gnu/java/net/protocol/jar/Handler.java (parseURL): Flatten jar + path. + (flat): New method. + +2006-11-07 Tania Bento + + * java/awt/FlowLayout.java + (getSize): If parent does not have a component, then a + different formula is used to calcuate the width. + +2006-11-07 Roman Kennke + + * javax/swing/text/html/HTMLEditorKit.java + (HTMLFactory.create): Include ListView. + * javax/swing/text/html/ListView.java + (paint): Removed comment. + * javax/swing/text/html/StyleSheet.java + (CSSStyle.priority): New field. + (CSSStyle.CSSStyle(int)): New constructor with priority. + (CSSStyle.compareTo): New method. Used for sorting the styles. + (CSSStyleSheetParserCallback.declaration): Store the style + with the complete selector. + (ListPainter.attributes): Renamed as field. + (ListPainter.styleSheet): New field. + (ListPainter.type): New field. + (ListPainter.ListPainter): Pass StyleSheet to constructor. + (ListPainter.paint): Provide simplistic implementation. + (getListPainter): Pass StyleSheet to constructor. + (resolveStyle): Fixed CSS style resolving. + +2006-11-07 Roman Kennke + + * gnu/javax/swing/text/html/css/BorderWidth.java: + New class. Handles CSS border width values. + * gnu/javax/swing/text/html/css/Length.java + (floatValue): Made protected so that BorderWidth can access it. + * javax/swing/text/html/CSS.java + (Attribute.BORDER_BOTTOM_COLOR): New static field. + (Attribute.BORDER_BOTTOM_STYLE): New static field. + (Attribute.BORDER_LEFT_COLOR): New static field. + (Attribute.BORDER_LEFT_STYLE): New static field. + (Attribute.BORDER_RIGHT_COLOR): New static field. + (Attribute.BORDER_RIGHT_STYLE): New static field. + (Attribute.BORDER_TOP_COLOR): New static field. + (Attribute.BORDER_TOP_STYLE): New static field. + (getValue): Added some mappings for the border color and + border width values. + * javax/swing/text/html/CSSBorder.java: New class. Implements + CSS borders. + * javax/swing/text/html/StyleSheet.java + (BoxPainter.background): New field. + (BoxPainter.border): New field. + (BoxPainter.bottomInset): Documented. + (BoxPainter.leftInset): Documented. + (BoxPainter.rightInset): Documented. + (BoxPainter.topInset): Documented. + (BoxPainter.BoxPainter): Added support for borders and background. + (BoxPainter.getInset): Add border insets. + (BoxPainter.paint): Implemented. Paints the background and the + CSS border. + (addRule): Be less picky about parse and IO exceptions. + (getBoxPainter): Adjust to new BoxPainter constructor. + +2006-11-07 Andreas + + * examples/Makefile.am: Add rule to install the *.html files we use + in the Swing Demo. + +2006-11-06 Francis Kung + + * gnu/java/awt/peer/gtk/ComponentGraphics.java + (fillRect): Handle custom composites. + (drawRenderedImage): Handle custom composites. + (drawImage): Handle custom composites. + (createBuffer): New method. + (drawLine): Handle custom composites. + (drawComposite): New method. + (fill): Handle custom composites. + (getNativeCM): New method. + (drawGlyphVector): Handle custom composites. + (drawRect): Handle custom composites. + (draw): Handle custom composites. + * gnu/java/awt/peer/gtk/VolatileImageGraphics.java + (drawComposite): Unset composite during draw call, to prevent parent + from handling composite again. + * gnu/java/awt/peer/gtk/CairoGraphics2D.java + (getBufferCM): Added comments. + (getNativeCM): Made abstract. + (setComposite): Removed comments. + +2006-11-06 Roman Kennke + + * examples/gnu/classpath/examples/swing/HtmlDemo.java: + Fixed initial window size and start document. + +2006-11-06 Roman Kennke + + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.addSpecialElement): Removed comment about + htmlAttributeSet. + (HTMLReader.handleComment): Create SimpleAttributeSet instead + of htmlAttributeSet. + * javax/swing/text/html/parser/DocumentParser.java + (gnuParser.handleStartTag): Use SimpleAttributeSet instead + of htmlAttributeSet. + * javax/swing/text/html/parser/ParserDelegator.java + (gnuParser.handleStartTag): Use SimpleAttributeSet instead + of htmlAttributeSet. + * gnu/javax/swing/text/html/parser/GnuParserDelegator.java + (gnuParser.handleStartTag): Use SimpleAttributeSet instead + of htmlAttributeSet. + * gnu/javax/swing/text/html/parser/support/Parser.java + (getAttributes): Return a SimpleAttributeSet. + (restOfTag): Don't set resolving parent here. + +2006-11-06 Tania Bento + + * java/awt/TextComponent.java + (setSelectionStart): Added check. + +2006-11-06 Tania Bento + + * java/awt/TextField.java + (minimumSize(int)): Check if minimum size has been previously + set and changed values of Dimension returned if peer == null. + (preferredSize(int)): Check if preferred size has been previously + set and changed values of Dimension returned if peer == null. + +2006-11-06 Roman Kennke + + * javax/swing/JTree.java + (TreeModelHandler.treeNodesRemoved): Implemented. + (TreeModelHandler.treeStructureChanged): Implemented. + (nodeStates): Made package private. + +2006-11-06 Francis Kung + + PR 29420 + * javax/swing/JTree.java + (clearSelectionPathStates): New private method to clean up nodeStates. + (removeSelectionPath): Call clearSelectionPathStates(). + (removeSelectionPaths): Call clearSelectionPathStates(). + (removeSelectionRow): Call clearSelectionPathStates(). + (setSelectionPath): Call clearSelectionPathStates(). + (setSelectionPaths): Call clearSelectionPathStates(). + (setSelectionRow): Call clearSelectionPathStates(). + +2006-11-06 Ito Kazumitsu + + Fixes bug #29703 + * java/util/regex/Matcher.java(reset): Reset inputCharIndexed. + +2006-11-06 Roman Kennke + + * examples/gnu/classpath/examples/swing/HtmlDemo.java: + Changed to implement a minimalistic browser. + * examples/gnu/classpath/examples/swing/forms.html, + * examples/gnu/classpath/examples/swing/textstyles.html, + * examples/gnu/classpath/examples/swing/welcome.html: + Some example content. + +2006-11-06 Roman Kennke + + * javax/swing/text/ComponentView.java + (setParent): Lock the document and repaint the hosting + container. + * javax/swing/text/FlowView.java + (FlowStrategy.createView): Removed comment. + (FlowView): Initialize span with Short.MAX_VALUE. + (getFlowStart): Return 0 unconditionally. + (layout): Moved code around to make it more readable. + (loadChildren): Always set the parent. + * javax/swing/text/GlyphView.java + (DefaultGlyphPainter.fontMetrics): New field. + (DefaultGlyphPainter.getAscent): Use new helper method to + synchronize the font metrics. + (DefaultGlyphPainter.getBoundedPosition): Use new helper method + to synchronize the font metrics. + (DefaultGlyphPainter.getDescent): Use new helper method to + synchronize the font metrics. + (DefaultGlyphPainter.getHeight): Use new helper method to + synchronize the font metrics. + (DefaultGlyphPainter.getSpan): Use new helper method to + synchronize the font metrics. + (DefaultGlyphPainter.modelToView): Use new helper method to + synchronize the font metrics. + (DefaultGlyphPainter.updateFontMetrics): New helper method for + font metrics caching. + (DefaultGlyphPainter.viewToModel): Use new helper method to + synchronize the font metrics. Fixed view to model mapping. + * javax/swing/text/View.java + (removeAll): Pass null to replace(). + (setParent): Only reparent children that have this view as parent. + +2006-11-05 Mark Wielaard + + * include/gnu_java_net_VMPlainDatagramSocketImpl.h: Removed. + * include/gnu_java_nio_channels_FileChannelImpl.h: Removed. + * native/jni/java-net/gnu_java_net_VMPlainDatagramSocketImpl.c: + Removed. + * native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c: + Removed. + * native/jni/java-nio/Makefile.am (libjavanio_la_SOURCES): + Remove gnu_java_nio_channels_FileChannelImpl.c. + +2006-11-03 Roman Kennke + + * javax/swing/text/html/BlockView.java + (attributes): New field. + (cssHeight): New field. + (cssWidth): New field. + (painter): New field. + (calculateMajorAxisRequirements): Overridden to account for + CSS settings. + (calculateMinorAxisRequirements): Overridden to account for + CSS settings. + (layoutMinorAxis): Overridden to account for CSS settings. + (changedUpdate): Formatting fixlet. + (constrainSize): New helper method. + (getAlignment): Fix alignment. + (getAttributes): Cache attributes for better performance. + (getStyleSheet): Fetch stylesheet from document rather than creating + a new one. + (paint): Remove comment. + (setCSSSpan): New helper method. + (setPropertiesFromAttributes): Implemented to fetch the + recognized properties. + * javax/swing/text/html/CSS.java + (getValue): Added mapping for width and height attributes. + * javax/swing/text/html/InlineView.java + (longestWord): New field. + (getLongestWord): New helper method. + (calculateLongestWord): New helper method. + (getMinimumSpan): Overridden to constrain the minimum span by the + longest word. + * javax/swing/text/html/ParagraphView.java + (cssHeight): New field. + (cssWidth): New field. + (calculateMinorAxisRequirements): Overridden to account for + CSS settings. + (setCSSSpan): New helper method. + (setPropertiesFromAttributes): Fetch CSS width and height. Added + null check. + * gnu/javax/swing/text/html/css/Length.java + (percentage): New field. + (Length): Determine percentage values. + (getValue(float)): New method for handling percentage values. + (isPercentage): New method. + 2006-11-03 Tania Bento * java/awt/TextArea.java diff --git a/examples/Makefile.am b/examples/Makefile.am index 43df1bdcf..6940bdf25 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -36,11 +36,14 @@ BUILT_SOURCES = $(EXAMPLE_ZIP) # the png icons we use in some of the examples. EXAMPLE_ICONS = $(srcdir)/gnu/classpath/examples/icons/*.png +# the html pages we use in the swing demo example. +EXAMPLE_HTML = $(srcdir)/gnu/classpath/examples/swing/*.html + # The example specific README files. READMES = $(srcdir)/gnu/classpath/examples/CORBA/swing/README.html # All the files we find "interesting" -ALL_EXAMPLE_FILES = $(EXAMPLE_JAVA_FILES) $(EXAMPLE_C_FILES) $(EXAMPLE_CH_FILES) $(EXAMPLE_ICONS) $(READMES) +ALL_EXAMPLE_FILES = $(EXAMPLE_JAVA_FILES) $(EXAMPLE_C_FILES) $(EXAMPLE_CH_FILES) $(EXAMPLE_ICONS) $(EXAMPLE_HTML) $(READMES) # Some architecture independent data to be installed. example_DATA = $(EXAMPLE_ZIP) README @@ -100,6 +103,8 @@ dist-hook: $(EXAMPLE_ZIP): $(EXAMPLE_JAVA_FILES) mkdir -p classes/gnu/classpath/examples/icons cp $(EXAMPLE_ICONS) classes/gnu/classpath/examples/icons + mkdir -p classes/gnu/classpath/examples/swing + cp $(EXAMPLE_HTML) classes/gnu/classpath/examples/swing $(JCOMPILER) -d classes $(EXAMPLE_JAVA_FILES) (cd classes; \ if test "$(ZIP)" != ""; then $(ZIP) -r ../$(EXAMPLE_ZIP) .; fi; \ diff --git a/examples/gnu/classpath/examples/swing/HtmlDemo.java b/examples/gnu/classpath/examples/swing/HtmlDemo.java index d31d8cc9d..4cbf3ce47 100644 --- a/examples/gnu/classpath/examples/swing/HtmlDemo.java +++ b/examples/gnu/classpath/examples/swing/HtmlDemo.java @@ -40,21 +40,22 @@ package gnu.classpath.examples.swing; import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.io.IOException; +import java.net.URL; +import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTextArea; +import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.SwingUtilities; -import javax.swing.text.AbstractDocument; -import javax.swing.text.Element; -import javax.swing.text.html.HTMLDocument; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; /** * Parses and displays HTML content. @@ -64,49 +65,36 @@ import javax.swing.text.html.HTMLDocument; public class HtmlDemo extends JPanel { + private class LoadActionListener + implements ActionListener + { + + public void actionPerformed(ActionEvent event) + { + String urlStr = url.getText(); + try + { + html.setPage(url.getText()); + } + catch (IOException ex) + { + System.err.println("exception while loading: " + ex); + ex.printStackTrace(); + } + } + } + /** * Setting this to true causes the parsed element structure to be dumped. */ private static final boolean DEBUG = true; - JTextPane html = new JTextPane(); - - JTextArea text = new JTextArea("\n" + /** + * The URL entry field. + */ + JTextField url = new JTextField(); - + "

H1 Headline

\n" - + "

H2 Headline

\n" - + "

H3 Headline

\n" - + "

H4 Headline

\n" - + "
H5 Headline
\n" - + "
H6 Headline
\n" - + "

CSS colors via font tag

\n" - + "

" - + "maroon\n" - + "red\n" - + "orange\n" - + "yellow\n" - + "olive\n" - + "purlpe\n" - + "fuchsia\n" - + "white\n" - + "lime\n" - + "green\n" - + "navy\n" - + "blue\n" - + "aqua\n" - + "teal\n" - + "black\n" - + "silver\n" - + "gray\n" - + "

" - + "

Some HTML formatting tags

\n" - + "

Normal Bold Italic Bold + Italic

\n" - + "

Big Emphasized Small\n" - + "Strike Strong Underline

\n" - + "

Normal vs Superscript vs Subscript text

\n" - + "\n"); - - JPanel buttons; + JTextPane html = new JTextPane(); int n; @@ -116,7 +104,7 @@ public class HtmlDemo extends JPanel html.setContentType("text/html"); // not now. createContent(); } - + /** * Returns a panel with the demo content. The panel uses a BorderLayout(), and * the BorderLayout.SOUTH area is empty, to allow callers to add controls to @@ -126,158 +114,56 @@ public class HtmlDemo extends JPanel private void createContent() { setLayout(new BorderLayout()); - - JPanel center = new JPanel(); - GridLayout layout = new GridLayout(); - layout.setRows(2); - center.setLayout(layout); - center.add(new JScrollPane(text)); - center.add(new JScrollPane(html)); - - buttons = new JPanel(); - - JButton parse = new JButton("parse"); - parse.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - String t = text.getText(); - System.out.println("HtmlDemo.java.createContent:Parsing started"); - html.setText(t); - System.out.println("HtmlDemo.java.createContent:Parsing completed"); - if (DEBUG) - ((AbstractDocument) html.getDocument()).dump(System.out); - } - }); - - buttons.add(parse); - - JButton insertBeforeEnd = new JButton("before end"); - insertBeforeEnd.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - HTMLDocument doc = (HTMLDocument) html.getDocument(); - Element el = doc.getElement("insertHere"); - System.out.println("Element found:"+el); - try - { - doc.insertBeforeEnd(el,"before end "+(n++)); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }); - - JButton insertBeforeStart = new JButton("before start"); - insertBeforeStart.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - HTMLDocument doc = (HTMLDocument) html.getDocument(); - Element el = doc.getElement("insertHere"); - System.out.println("Element found:"+el); - try - { - doc.insertBeforeStart(el,"before start "+(n++)); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }); - - JButton insertAfterEnd = new JButton("after end"); - insertAfterEnd.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - HTMLDocument doc = (HTMLDocument) html.getDocument(); - Element el = doc.getElement("insertHere"); - System.out.println("Element found:"+el); - try - { - doc.insertAfterEnd(el,"after end "+(n++)); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }); - - JButton insertAfterStart = new JButton("after start"); - insertAfterStart.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - HTMLDocument doc = (HTMLDocument) html.getDocument(); - Element el = doc.getElement("insertHere"); - System.out.println("Element found:"+el); - try - { - doc.insertAfterStart(el,"after start "+(n++)); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }); - - JButton setInner = new JButton("inner"); - setInner.addActionListener(new ActionListener() + html.setEditable(false); + html.addHyperlinkListener(new HyperlinkListener() + { + + public void hyperlinkUpdate(HyperlinkEvent event) { - public void actionPerformed(ActionEvent event) + URL u = event.getURL(); + if (u != null) { - HTMLDocument doc = (HTMLDocument) html.getDocument(); - Element el = doc.getElement("insertHere"); - System.out.println("Element found:"+el); + url.setText(u.toString()); try { - doc.setInnerHTML(el,"inner "+(n++)); + html.setPage(u); } - catch (Exception e) + catch (IOException ex) { - e.printStackTrace(); + ex.printStackTrace(); } } - }); - - JButton setOuter = new JButton("outer"); - setOuter.addActionListener(new ActionListener() + } + + }); + + JScrollPane scroller = new JScrollPane(html); + JPanel urlPanel = new JPanel(); + urlPanel.setLayout(new BoxLayout(urlPanel, BoxLayout.X_AXIS)); + url.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE)); + LoadActionListener action = new LoadActionListener(); + url.addActionListener(action); + urlPanel.add(url); + JButton loadButton = new JButton("go"); + urlPanel.add(loadButton); + loadButton.addActionListener(action); + add(urlPanel, BorderLayout.NORTH); + add(scroller, BorderLayout.CENTER); + + // Load start page. + URL startpage = getClass().getResource("welcome.html"); + try { - public void actionPerformed(ActionEvent event) - { - HTMLDocument doc = (HTMLDocument) html.getDocument(); - Element el = doc.getElement("insertHere"); - System.out.println("Element found:"+el); - try - { - doc.setOuterHTML(el,"outer "+(n++)); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }); - - - buttons.add(insertBeforeStart); - buttons.add(insertAfterStart); - buttons.add(insertBeforeEnd); - buttons.add(insertAfterEnd); + html.setPage(startpage); + url.setText(startpage.toString()); + } + catch (IOException ex) + { + System.err.println("couldn't load page: " + startpage); + } - buttons.add(setInner); - buttons.add(setOuter); - - add(center, BorderLayout.CENTER); - add(buttons, BorderLayout.SOUTH); + setPreferredSize(new Dimension(600, 400)); } /** @@ -294,18 +180,6 @@ public class HtmlDemo extends JPanel public void run() { HtmlDemo demo = new HtmlDemo(); - - JButton exit = new JButton("exit"); - exit.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - System.exit(0); - } - }); - - demo.buttons.add(exit); - JFrame frame = new JFrame(); frame.getContentPane().add(demo); frame.setSize(new Dimension(700, 480)); diff --git a/examples/gnu/classpath/examples/swing/forms.html b/examples/gnu/classpath/examples/swing/forms.html new file mode 100644 index 000000000..2cfdb4bcc --- /dev/null +++ b/examples/gnu/classpath/examples/swing/forms.html @@ -0,0 +1,69 @@ + + + + + + HTML text styles + + + Back to start page +

Some form elements

+

Textarea

+ + +

Buttons

+

+ + + +

+ +

Checkboxes and Radiobuttons

+

+ Check this! + Or this +

+

+ A radio button + Another radio +

+ + \ No newline at end of file diff --git a/examples/gnu/classpath/examples/swing/textstyles.html b/examples/gnu/classpath/examples/swing/textstyles.html new file mode 100644 index 000000000..786e18b77 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/textstyles.html @@ -0,0 +1,78 @@ + + + + + + HTML text styles + + + Back to start page +

Colors

+

The following are the 16 named colors in HTML. Of course you can also + use all RGB colors by specifying a value in the #RRGGBB + notation.

+

+ Black, Gray, + Maroon, Red, + Green, Lime, + Olive, Yellow, + Navy, Blue, + Purple, Fuchsia, + Teal, Aqua, + Silver, White

+

Font styles

+

The following lists the logical and physical font styles that can be set + by certain HTML tags

+

+ +

Address
, Bold, Big, + Citation, Code, Deleted, + Emphasized, Italic, Inserted, Quote, + Stroke-Through, Example, Small, + Strike, Strong, Subscript, + Superscript, Underlined, Variable +

+

Header Level 1

+

Header Level 2

+

Header Level 3

+

Header Level 4

+
Header Level 5
+
Header Level 6
+
Some centered Text
+ + \ No newline at end of file diff --git a/examples/gnu/classpath/examples/swing/welcome.html b/examples/gnu/classpath/examples/swing/welcome.html new file mode 100644 index 000000000..62fb51429 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/welcome.html @@ -0,0 +1,52 @@ + + + + + GNU Classpath HTML Browser + + + +

Welcome to GNU Classpath

+

These pages are here to demonstrate the HTML rendering capabilities + of GNU Classpath's Swing.

+ + + \ No newline at end of file diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java index 7f55747c6..ce3041d73 100644 --- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java +++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -985,10 +985,6 @@ public abstract class CairoGraphics2D extends Graphics2D if (sm != null) sm.checkPermission(new AWTPermission("readDisplayPixels")); - // FIXME: implement general Composite support - //throw new java.lang.UnsupportedOperationException(); - // this is in progress! yay! - //compCtx = comp.createContext(getNativeCM(), getNativeCM(), hints); compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints); } } @@ -1000,18 +996,17 @@ public abstract class CairoGraphics2D extends Graphics2D * * @return ColorModel the ColorModel of native data in this peer */ - /* protected abstract ColorModel getNativeCM(); */ - protected ColorModel getNativeCM() - { - // This stub should be removed and the method made abstract once I'm done - // implementing custom composites across all the peers... but we need it - // for now, so that the build doesn't break. - return null; - } + protected abstract ColorModel getNativeCM(); - // This may be overridden by some subclasses + /** + * Returns the Color Model describing the buffer that this peer uses + * for custom composites. + * + * @return ColorModel the ColorModel of the composite buffer in this peer. + */ protected ColorModel getBufferCM() { + // This may be overridden by some subclasses return getNativeCM(); } diff --git a/gnu/java/awt/peer/gtk/ComponentGraphics.java b/gnu/java/awt/peer/gtk/ComponentGraphics.java index d9d173118..c8ec2c95e 100644 --- a/gnu/java/awt/peer/gtk/ComponentGraphics.java +++ b/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -38,22 +38,31 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import gnu.classpath.Pointer; + +import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; +import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.Toolkit; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; +import java.awt.image.Raster; import java.awt.image.RenderedImage; -import gnu.classpath.Pointer; +import java.awt.image.WritableRaster; +import java.util.Hashtable; /** * ComponentGraphics - context for drawing directly to a component, @@ -67,6 +76,7 @@ public class ComponentGraphics extends CairoGraphics2D private GtkComponentPeer component; protected long cairo_t; + private BufferedImage buffer, componentBuffer; private static ThreadLocal hasLock = new ThreadLocal(); private static Integer ONE = Integer.valueOf(1); @@ -227,7 +237,20 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.draw(s); + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.draw(s); + + drawComposite(s.getBounds2D(), null); + } } finally { @@ -240,7 +263,20 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.fill(s); + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } } finally { @@ -253,7 +289,19 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.drawRenderedImage(image, xform); + if (comp == null || comp instanceof AlphaComposite) + super.drawRenderedImage(image, xform); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } } finally { @@ -268,7 +316,44 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - rv = super.drawImage(img, xform, bgcolor, obs); + if (comp == null || comp instanceof AlphaComposite) + rv = super.drawImage(img, xform, bgcolor, obs); + + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); + Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(), + bImg.getHeight() + bImg.getMinY()); + if (xform != null) + { + origin = xform.transform(origin, origin); + pt = xform.transform(pt, pt); + } + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + rv = drawComposite(new Rectangle2D.Double(origin.getX(), + origin.getY(), + pt.getX(), pt.getY()), + obs); + } } finally { @@ -282,7 +367,23 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.drawGlyphVector(gv, x, y); + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } } finally { @@ -384,7 +485,11 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.drawLine(x1, y1, x2, y2); + if (comp == null || comp instanceof AlphaComposite) + super.drawLine(x1, y1, x2, y2); + + else + draw(new Line2D.Double(x1, y1, x2, y2)); } finally { @@ -397,7 +502,11 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.drawRect(x, y, width, height); + if (comp == null || comp instanceof AlphaComposite) + super.drawRect(x, y, width, height); + + else + draw(new Rectangle2D.Double(x, y, width, height)); } finally { @@ -410,7 +519,11 @@ public class ComponentGraphics extends CairoGraphics2D lock(); try { - super.fillRect(x, y, width, height); + if (comp == null || comp instanceof AlphaComposite) + super.fillRect(x, y, width, height); + + else + fill(new Rectangle2D.Double(x, y, width, height)); } finally { @@ -431,5 +544,99 @@ public class ComponentGraphics extends CairoGraphics2D } } + + 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); + + 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); + + // Get current image on the component + unlock(); + GtkImage img = grab(component); + Graphics gr = componentBuffer.createGraphics(); + gr.drawImage(img, 0, 0, null); + gr.dispose(); + lock(); + + BufferedImage cBuffer = componentBuffer; + if (!deviceBounds.equals(cBuffer.getRaster().getBounds())) + cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(), + (int)deviceBounds.getY(), + (int)deviceBounds.getWidth(), + (int)deviceBounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(), + cBuffer.getRaster()); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(cBuffer, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(), + component.awtComponent.getHeight()), + new Point(0,0)); + + buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + + if (componentBuffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(), + component.awtComponent.getHeight()), + new Point(0,0)); + + componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + } + + protected ColorModel getNativeCM() + { + return GtkVolatileImage.gdkColorModel; + } } diff --git a/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/gnu/java/awt/peer/gtk/GtkImageConsumer.java index f1a74b8cc..53e97bb1a 100644 --- a/gnu/java/awt/peer/gtk/GtkImageConsumer.java +++ b/gnu/java/awt/peer/gtk/GtkImageConsumer.java @@ -42,6 +42,7 @@ import java.awt.image.ColorModel; import java.awt.image.ImageConsumer; import java.awt.image.ImageProducer; import java.awt.image.MemoryImageSource; +import java.nio.ByteOrder; import java.util.Hashtable; /** @@ -103,7 +104,7 @@ public class GtkImageConsumer implements ImageConsumer scansize); } - public synchronized void setPixels (int x, int y, int width, int height, + public synchronized void setPixels (int x, int y, int width, int height, ColorModel cm, int[] pixels, int offset, int scansize) { @@ -117,18 +118,34 @@ public class GtkImageConsumer implements ImageConsumer width); else { - for (int i = 0; i < height; i++) - for (int j = 0; j < width; j++) - { - // get in AARRGGBB and convert to AABBGGRR - int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); - byte b = (byte)(pix & 0xFF); - byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); - pix &= 0xFF00FF00; - pix |= ((b & 0xFF) << 16); - pix |= (r & 0xFF); - pixelCache[(y + i) * this.width + x + j] = pix; - } + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in RRGGBBAA and convert to AARRGGBB + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + int a = ((pix & 0xFF000000) >> 24) & 0xFF; + int rgb = (pix & 0x00FFFFFF) << 8; + pix = rgb | a; + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + else + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in AARRGGBB and convert to AABBGGRR + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + byte b = (byte)(pix & 0xFF); + byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); + pix &= 0xFF00FF00; + pix |= ((b & 0xFF) << 16); + pix |= (r & 0xFF); + pixelCache[(y + i) * this.width + x + j] = pix; + } + } } } diff --git a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java index 3a9f9d693..62dbb45d8 100644 --- a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java +++ b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java @@ -40,6 +40,7 @@ package gnu.java.awt.peer.gtk; import java.awt.AlphaComposite; import java.awt.Color; +import java.awt.Composite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; @@ -269,10 +270,13 @@ public class VolatileImageGraphics extends ComponentGraphics // This MUST call directly into the "action" method in CairoGraphics2D, // not one of the wrappers, to ensure that the composite isn't processed // more than once! + Composite oldComp = comp; // so that ComponentGraphics doesn't + comp = null; // process the composite again boolean rv = super.drawImage(buffer2, AffineTransform.getTranslateInstance(bounds.getX(), bounds.getY()), null, null); + comp = oldComp; return rv; } diff --git a/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java b/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java new file mode 100644 index 000000000..77ec4bf00 --- /dev/null +++ b/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java @@ -0,0 +1,88 @@ +/* HeadlessGraphicsEnvironment.java -- A graphics environment for headless mode + 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.java.awt.peer.headless; + +import gnu.java.awt.java2d.RasterGraphics; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.image.BufferedImage; +import java.util.Locale; + +public class HeadlessGraphicsEnvironment + extends GraphicsEnvironment +{ + + public Graphics2D createGraphics(BufferedImage image) + { + return new RasterGraphics(image.getRaster(), image.getColorModel()); + } + + public Font[] getAllFonts() + { + // FIXME: Implement. + return null; + } + + public String[] getAvailableFontFamilyNames() + { + // FIXME: Implement. + return null; + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + // FIXME: Implement. + return null; + } + + public GraphicsDevice getDefaultScreenDevice() + { + throw new HeadlessException(); + } + + public GraphicsDevice[] getScreenDevices() + { + throw new HeadlessException(); + } + +} diff --git a/gnu/java/awt/peer/headless/HeadlessToolkit.java b/gnu/java/awt/peer/headless/HeadlessToolkit.java new file mode 100644 index 000000000..96798c9e9 --- /dev/null +++ b/gnu/java/awt/peer/headless/HeadlessToolkit.java @@ -0,0 +1,371 @@ +/* HeadlessToolkit.java -- A toolkit for headless mode + 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.java.awt.peer.headless; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; +import java.util.Properties; + +public class HeadlessToolkit + extends ClasspathToolkit +{ + + /** + * The graphics environment for headless graphics. + */ + private HeadlessGraphicsEnvironment graphicsEnv; + + public void beep() + { + // TODO Auto-generated method stub + + } + + public int checkImage(Image image, int width, int height, + ImageObserver observer) + { + // TODO Auto-generated method stub + return 0; + } + + protected ButtonPeer createButton(Button target) + { + throw new HeadlessException(); + } + + protected CanvasPeer createCanvas(Canvas target) + { + throw new HeadlessException(); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + throw new HeadlessException(); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + throw new HeadlessException(); + } + + protected ChoicePeer createChoice(Choice target) + { + throw new HeadlessException(); + } + + protected DialogPeer createDialog(Dialog target) + { + throw new HeadlessException(); + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + throw new HeadlessException(); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + throw new HeadlessException(); + } + + protected FramePeer createFrame(Frame target) + { + throw new HeadlessException(); + } + + public Image createImage(String filename) + { + // FIXME: Implement. + return null; + } + + public Image createImage(URL url) + { + // FIXME: Implement. + return null; + } + + public Image createImage(ImageProducer producer) + { + // FIXME: Implement. + return null; + } + + public Image createImage(byte[] data, int offset, int len) + { + // TODO Auto-generated method stub + return null; + } + + protected LabelPeer createLabel(Label target) + { + throw new HeadlessException(); + } + + protected ListPeer createList(List target) + { + throw new HeadlessException(); + } + + protected MenuPeer createMenu(Menu target) + { + throw new HeadlessException(); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + throw new HeadlessException(); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + throw new HeadlessException(); + } + + protected PanelPeer createPanel(Panel target) + { + throw new HeadlessException(); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + throw new HeadlessException(); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + throw new HeadlessException(); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + throw new HeadlessException(); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + throw new HeadlessException(); + } + + protected TextFieldPeer createTextField(TextField target) + { + throw new HeadlessException(); + } + + protected WindowPeer createWindow(Window target) + { + throw new HeadlessException(); + } + + public ColorModel getColorModel() + { + // TODO Auto-generated method stub + return null; + } + + public String[] getFontList() + { + // TODO Auto-generated method stub + return null; + } + + public FontMetrics getFontMetrics(Font name) + { + // TODO Auto-generated method stub + return null; + } + + protected FontPeer getFontPeer(String name, int style) + { + // TODO Auto-generated method stub + return null; + } + + public Image getImage(String name) + { + // TODO Auto-generated method stub + return null; + } + + public Image getImage(URL url) + { + // TODO Auto-generated method stub + return null; + } + + public PrintJob getPrintJob(Frame frame, String title, Properties props) + { + // TODO Auto-generated method stub + return null; + } + + public int getScreenResolution() + { + throw new HeadlessException(); + } + + public Dimension getScreenSize() + { + throw new HeadlessException(); + } + + public Clipboard getSystemClipboard() + { + throw new HeadlessException(); + } + + protected EventQueue getSystemEventQueueImpl() + { + throw new HeadlessException(); + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + // TODO Auto-generated method stub + return null; + } + + public boolean prepareImage(Image image, int width, int height, + ImageObserver observer) + { + // TODO Auto-generated method stub + return false; + } + + public void sync() + { + // TODO Auto-generated method stub + + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + throw new HeadlessException(); + } + + public Font createFont(int format, InputStream stream) + { + // TODO Auto-generated method stub + return null; + } + + public RobotPeer createRobot(GraphicsDevice screen) throws AWTException + { + throw new HeadlessException(); + } + + public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs) + { + // TODO Auto-generated method stub + return null; + } + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + if (graphicsEnv == null) + graphicsEnv = new HeadlessGraphicsEnvironment(); + return graphicsEnv; + } + +} diff --git a/gnu/java/awt/peer/swing/SwingButtonPeer.java b/gnu/java/awt/peer/swing/SwingButtonPeer.java index 2357fcbfb..531d6f2db 100644 --- a/gnu/java/awt/peer/swing/SwingButtonPeer.java +++ b/gnu/java/awt/peer/swing/SwingButtonPeer.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.java.awt.peer.swing; import java.awt.Button; +import java.awt.Container; import java.awt.Graphics; import java.awt.Image; import java.awt.Point; @@ -69,6 +70,13 @@ public class SwingButtonPeer extends JButton implements SwingComponent { + Button button; + + SwingButton(Button button) + { + this.button = button; + } + /** * Overridden so that this method returns the correct value even without a * peer. @@ -90,8 +98,8 @@ public class SwingButtonPeer public boolean isShowing() { boolean retVal = false; - if (SwingButtonPeer.this.awtComponent != null) - retVal = SwingButtonPeer.this.awtComponent.isShowing(); + if (button != null) + retVal = button.isShowing(); return retVal; } @@ -168,6 +176,14 @@ public class SwingButtonPeer ev.setSource(this); processKeyEvent(ev); } + + public Container getParent() + { + Container par = null; + if (button != null) + par = button.getParent(); + return par; + } } /** @@ -205,7 +221,7 @@ public class SwingButtonPeer */ public SwingButtonPeer(Button theButton) { - SwingButton button = new SwingButton(); + SwingButton button = new SwingButton(theButton); button.setText(theButton.getLabel()); button.addActionListener(new SwingButtonListener()); init(theButton, button); diff --git a/gnu/java/awt/peer/swing/SwingComponent.java b/gnu/java/awt/peer/swing/SwingComponent.java index a51b758ad..04ca7294f 100644 --- a/gnu/java/awt/peer/swing/SwingComponent.java +++ b/gnu/java/awt/peer/swing/SwingComponent.java @@ -62,7 +62,7 @@ public interface SwingComponent /** * Handles a mouse event. This is usually forwarded to - * {@link java.awt.Component#processMouseMotionEvent(MouseEvent)} of the swing + * {@link Component#processMouseMotionEvent(MouseEvent)} of the swing * component. * * @param ev the mouse event @@ -71,7 +71,7 @@ public interface SwingComponent /** * Handles a mouse motion event. This is usually forwarded to - * {@link java.awt.Component#processMouseEvent(MouseEvent)} of the swing + * {@link Component#processMouseEvent(MouseEvent)} of the swing * component. * * @param ev the mouse motion event @@ -80,7 +80,7 @@ public interface SwingComponent /** * Handles a key event. This is usually forwarded to - * {@link java.awt.Component#processKeyEvent(KeyEvent)} of the swing + * {@link Component#processKeyEvent(KeyEvent)} of the swing * component. * * @param ev the key event diff --git a/gnu/java/awt/peer/swing/SwingComponentPeer.java b/gnu/java/awt/peer/swing/SwingComponentPeer.java index 96ccc00b8..7e1ad86a0 100644 --- a/gnu/java/awt/peer/swing/SwingComponentPeer.java +++ b/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -42,6 +42,7 @@ import java.awt.AWTException; import java.awt.BufferCapabilities; import java.awt.Color; import java.awt.Component; +import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; @@ -62,6 +63,13 @@ import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; +import java.awt.peer.LightweightPeer; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JComponent; +import javax.swing.RepaintManager; /** * The base class for Swing based component peers. This provides the basic @@ -75,7 +83,7 @@ import java.awt.peer.ContainerPeer; * This class also provides the necesary hooks into the Swing painting and * event handling system. In order to achieve this, it traps paint, mouse and * key events in {@link #handleEvent(AWTEvent)} and calls some special methods - * ({@link #peerPaint(Graphics)}, {@link #handleKeyEvent(KeyEvent)}, + * ({@link #peerPaint(Graphics,boolean)}, {@link #handleKeyEvent(KeyEvent)}, * {@link #handleMouseEvent(MouseEvent)} and * {@link #handleMouseMotionEvent(MouseEvent)}) that call the corresponding * Swing methods. @@ -97,14 +105,30 @@ public class SwingComponentPeer protected SwingComponent swingComponent; /** + * The font that is set for this peer. + */ + protected Font peerFont; + + /** + * The repaint requests that will be handled next. The events queued + * up here are in the exact same order as they appear in + * {@link #coalescePaintEvent(PaintEvent)}, that is in event queue order. + * This is used for coalescing paint events. + * + * @see #coalescePaintEvent(PaintEvent) + */ + protected List currentPaintEvents; + + /** * Creates a SwingComponentPeer instance. Subclasses are expected to call - * this constructor and thereafter call - * {@link #init(Component,SwingComponent)} - * in order to setup the AWT and Swing components properly. + * this constructor and thereafter call {@link #init(Component, + * SwingComponent)}in order to setup the AWT and Swing components properly. */ protected SwingComponentPeer() { - // Nothing to do here. + // Initialize paint event queue. + currentPaintEvents = new LinkedList(); + } /** @@ -118,6 +142,38 @@ public class SwingComponentPeer { awtComponent = awtComp; swingComponent = swingComp; + if (swingComponent != null) + { + JComponent c = swingComponent.getJComponent(); + if (c != null) + { + c.addNotify(); + RepaintManager.currentManager(c).setDoubleBufferingEnabled(false); + System.setProperty("gnu.awt.swing.doublebuffering", "true"); + } + } + + // Register this heavyweight component with the nearest heavyweight + // container, so we get peerPaint() triggered by that container. + if (! (this instanceof LightweightPeer)) + { + Component comp = awtComponent; + Container parent = comp.getParent(); + while (parent != null && + ! (parent.getPeer() instanceof SwingContainerPeer)) + { + comp = parent; + parent = comp.getParent(); + } + + // At this point we have the ancestor with a SwingContainerPeer + // (or null peer). + if (parent != null && parent.getPeer() instanceof SwingContainerPeer) + { + SwingContainerPeer p = (SwingContainerPeer) parent.getPeer(); + p.addHeavyweightDescendent(awtComponent); + } + } } /** @@ -185,6 +241,28 @@ public class SwingComponentPeer */ public void dispose() { + // Unregister this heavyweight component from the nearest heavyweight + // container. + if (! (this instanceof LightweightPeer)) + { + Component comp = awtComponent; + Container parent = comp.getParent(); + while (parent != null && + ! (parent.getPeer() instanceof SwingContainerPeer)) + { + comp = parent; + parent = comp.getParent(); + } + + // At this point we have the ancestor with a SwingContainerPeer + // (or null peer). + if (parent != null && parent.getPeer() instanceof SwingContainerPeer) + { + SwingContainerPeer p = (SwingContainerPeer) parent.getPeer(); + p.removeHeavyweightDescendent(awtComponent); + } + } + awtComponent = null; swingComponent = null; } @@ -244,8 +322,7 @@ public class SwingComponentPeer public Graphics getGraphics() { Component parent = awtComponent.getParent(); - ComponentPeer parentPeer = parent.getPeer(); - Graphics g = parentPeer.getGraphics(); + Graphics g = parent.getGraphics(); g.translate(awtComponent.getX(), awtComponent.getY()); g.setClip(0, 0, awtComponent.getWidth(), awtComponent.getHeight()); return g; @@ -331,23 +408,30 @@ public class SwingComponentPeer { case PaintEvent.UPDATE: case PaintEvent.PAINT: - // This only will work when the component is showing. - if (awtComponent.isShowing()) + // Need to synchronize to avoid threading problems on the + // paint event list. + // We must synchronize on the tree lock first to avoid deadlock, + // because Container.paint() will grab it anyway. + synchronized (awtComponent.getTreeLock()) { - Graphics g = getGraphics(); - Rectangle clip = ((PaintEvent)e).getUpdateRect(); - g.clipRect(clip.x, clip.y, clip.width, clip.height); - //if (this instanceof LightweightPeer) - // { - if (e.getID() == PaintEvent.UPDATE) - awtComponent.update(g); - else - awtComponent.paint(g); - // } - // We paint the 'heavyweights' at last, so that they appear on top of - // everything else. - peerPaint(g); - g.dispose(); + synchronized (currentPaintEvents) + { + if (currentPaintEvents.contains(e)) + { + Graphics g = awtComponent.getGraphics(); + try + { + Rectangle clip = ((PaintEvent) e).getUpdateRect(); + g.clipRect(clip.x, clip.y, clip.width, clip.height); + peerPaint(g, e.getID() == PaintEvent.UPDATE); + } + finally + { + g.dispose(); + } + currentPaintEvents.remove(e); + } + } } break; case MouseEvent.MOUSE_PRESSED: @@ -451,9 +535,15 @@ public class SwingComponentPeer return retVal; } + /** + * Paints the component. This is triggered by + * {@link Component#paintAll(Graphics)}. + * + * @param graphics the graphics to paint with + */ public void paint(Graphics graphics) { - // FIXME: I don't know what this method is supposed to do. + peerPaint(graphics, false); } /** @@ -634,6 +724,7 @@ public class SwingComponentPeer */ public void setFont(Font font) { + peerFont = font; if (swingComponent != null) swingComponent.getJComponent().setFont(font); } @@ -741,7 +832,36 @@ public class SwingComponentPeer */ public void coalescePaintEvent(PaintEvent e) { - // Nothing to do here yet. + synchronized (currentPaintEvents) + { + Rectangle newRect = e.getUpdateRect(); + boolean coalesced = false; + for (Iterator i = currentPaintEvents.iterator(); i.hasNext() && ! coalesced;) + { + PaintEvent e2 = (PaintEvent) i.next(); + if (e.getID() == e2.getID()) + { + Rectangle oldRect = e2.getUpdateRect(); + if (oldRect.contains(newRect)) + { + // Merge newRect into oldRect. We have to discard the old request + // so that the events are still in the correct order. + i.remove(); + newRect.setBounds(oldRect); + coalesced = true; + } + else if (newRect.contains(oldRect)) + { + // Merge oldRect into newRect. We have to discard the old request + // so that the events are still in the correct order. + i.remove(); + coalesced = true; + } + } + // TODO: Maybe do something more clever here. + } + currentPaintEvents.add(e); + } } /** @@ -947,9 +1067,33 @@ public class SwingComponentPeer * paint() on the Swing component. * * @param g the graphics context to use for painting + * @param update wether we need to call update or paint on the AWT component + */ + protected void peerPaint(Graphics g, boolean update) + { + peerPaintComponent(g); + + Graphics userGraphics = g.create(); + try{ + if (update) + awtComponent.update(userGraphics); + else + awtComponent.paint(userGraphics); + } finally { + userGraphics.dispose(); + } + + } + + /** + * Paints the actual 'heavyweight' swing component, if there is one + * associated to this peer. + * + * @param g the graphics to paint the component with */ - protected void peerPaint(Graphics g) + protected void peerPaintComponent(Graphics g) { + // Paint the actual Swing component if this peer has one. if (swingComponent != null) swingComponent.getJComponent().paint(g); } diff --git a/gnu/java/awt/peer/swing/SwingContainerPeer.java b/gnu/java/awt/peer/swing/SwingContainerPeer.java index f433e1b5c..c78b644a7 100644 --- a/gnu/java/awt/peer/swing/SwingContainerPeer.java +++ b/gnu/java/awt/peer/swing/SwingContainerPeer.java @@ -37,14 +37,20 @@ exception statement from your version. */ package gnu.java.awt.peer.swing; +import gnu.classpath.SystemProperties; + import java.awt.Component; import java.awt.Container; import java.awt.Graphics; +import java.awt.Image; import java.awt.Insets; -import java.awt.Shape; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; +import java.util.Iterator; +import java.util.LinkedList; /** * A peer for Container to be used with the Swing based AWT peers. @@ -56,14 +62,54 @@ public class SwingContainerPeer implements ContainerPeer { + /** + * Stores all heavyweight descendents of the container. This is used + * in {@link #peerPaintChildren(Graphics)}. + */ + private LinkedList heavyweightDescendents; + + /** + * The backbuffer used for painting UPDATE events. + */ + private Image backbuffer; + /** * Creates a new SwingContainerPeer. * * @param awtCont */ - public SwingContainerPeer(Component awtCont) + public SwingContainerPeer(Container awtCont) + { + heavyweightDescendents = new LinkedList(); + } + + /** + * Registers a heavyweight descendent. This is then painted by + * {@link #peerPaintChildren(Graphics)}. + * + * @param comp the descendent to register + * + * @see #peerPaintChildren(Graphics) + * @see #removeHeavyweightDescendent(Component) + */ + synchronized void addHeavyweightDescendent(Component comp) + { + heavyweightDescendents.add(comp); + focusOwner = null; + } + + /** + * Unregisters a heavyweight descendent. + * + * @param comp the descendent to unregister + * + * @see #peerPaintChildren(Graphics) + * @see #addHeavyweightDescendent(Component) + */ + synchronized void removeHeavyweightDescendent(Component comp) { - init(awtCont, null); + heavyweightDescendents.remove(comp); + focusOwner = null; } /** @@ -92,12 +138,7 @@ public class SwingContainerPeer */ public Insets getInsets() { - Insets retVal; - if (swingComponent != null) - retVal = swingComponent.getJComponent().getInsets(); - else - retVal = new Insets(0, 0, 0, 0); - return retVal; + return insets(); } /** @@ -171,38 +212,83 @@ public class SwingContainerPeer } /** - * Triggers painting of a component. This calls peerPaint on all the child - * components of this container. - * - * @param g the graphics context to paint to + * Performs the super behaviour (call peerPaintComponent() and + * awtComponent.paint()), and forwards the paint request to the heavyweight + * descendents of the container. */ - protected void peerPaint(Graphics g) + protected void peerPaint(Graphics g, boolean update) { - Container c = (Container) awtComponent; - Component[] children = c.getComponents(); - for (int i = children.length - 1; i >= 0; --i) + if (isDoubleBuffering()) { - Component child = children[i]; - ComponentPeer peer = child.getPeer(); - boolean translated = false; - boolean clipped = false; - Shape oldClip = g.getClip(); + int width = awtComponent.getWidth(); + int height = awtComponent.getHeight(); + if (backbuffer == null + || backbuffer.getWidth(awtComponent) < width + || backbuffer.getHeight(awtComponent) < height) + backbuffer = awtComponent.createImage(width, height); + Graphics g2 = backbuffer.getGraphics(); + Rectangle clip = g.getClipRect(); try - { - g.translate(child.getX(), child.getY()); - translated = true; - g.setClip(0, 0, child.getWidth(), child.getHeight()); - clipped = true; - if (peer instanceof SwingComponentPeer) - ((SwingComponentPeer) peer).peerPaint(g); - } + { + g2.setClip(clip); + super.peerPaint(g2, update); + peerPaintChildren(g2); + } finally - { - if (translated) - g.translate(- child.getX(), - child.getY()); - if (clipped) - g.setClip(oldClip); - } + { + g2.dispose(); + } + g.drawImage(backbuffer, 0, 0, awtComponent); + } + else + { + super.peerPaint(g, update); + peerPaintChildren(g); + } + } + + /** + * Determines if we should do double buffering or not. + * + * @return if we should do double buffering or not + */ + private boolean isDoubleBuffering() + { + Object prop = + SystemProperties.getProperty("gnu.awt.swing.doublebuffering", "false"); + return prop.equals("true"); + } + + /** + * Paints any heavyweight child components. + * + * @param g the graphics to use for painting + */ + protected synchronized void peerPaintChildren(Graphics g) + { + // TODO: Is this the right painting order? + for (Iterator i = heavyweightDescendents.iterator(); i.hasNext();) + { + Component child = (Component) i.next(); + ComponentPeer peer = child.getPeer(); + + if (peer instanceof SwingComponentPeer && child.isVisible()) + { + // TODO: The translation here doesn't work for deeper + // nested children. Fix this! + Graphics g2 = g.create(child.getX(), child.getY(), + child.getWidth(), child.getHeight()); + try + { + // update() is only called for the topmost component if + // necessary, all other components only get paint() called. + ((SwingComponentPeer) peer).peerPaint(g2, false); + } + finally + { + g2.dispose(); + } + } } } @@ -214,17 +300,13 @@ public class SwingContainerPeer protected void handleMouseEvent(MouseEvent ev) { Component comp = awtComponent.getComponentAt(ev.getPoint()); - if(comp == null) - comp = awtComponent; - if (comp != null) + if(comp == null) comp = awtComponent; + ComponentPeer peer = comp.getPeer(); + if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) { - ComponentPeer peer = comp.getPeer(); - if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) - { - ev.translatePoint(comp.getX(), comp.getY()); - ev.setSource(comp); - ((SwingComponentPeer) peer).handleMouseEvent(ev); - } + ev.translatePoint(comp.getX(), comp.getY()); + ev.setSource(comp); + ((SwingComponentPeer) peer).handleMouseEvent(ev); } } @@ -246,4 +328,39 @@ public class SwingContainerPeer } } } + + /** + * Handles key events on the component. This is usually forwarded to the + * SwingComponent's processKeyEvent() method. + * + * @param e the key event + */ + protected void handleKeyEvent(KeyEvent e) + { + Component owner = getFocusOwner(); + if(owner != null) + owner.dispatchEvent(e); + else + super.handleKeyEvent(e); + } + + private Component focusOwner = null; + + private Component getFocusOwner() + { + if(focusOwner == null) + { + for(Iterator iter=heavyweightDescendents.iterator(); iter.hasNext();) + { + Component child = (Component) iter.next(); + if(child.isFocusable()) + { + focusOwner = child; + break; + } + } + } + return focusOwner; + } + } diff --git a/gnu/java/awt/peer/swing/SwingFramePeer.java b/gnu/java/awt/peer/swing/SwingFramePeer.java index 0d5a02d78..56c7417cd 100644 --- a/gnu/java/awt/peer/swing/SwingFramePeer.java +++ b/gnu/java/awt/peer/swing/SwingFramePeer.java @@ -43,6 +43,7 @@ import java.awt.Insets; import java.awt.MenuBar; import java.awt.Point; import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; import java.awt.peer.FramePeer; /** @@ -53,9 +54,9 @@ import java.awt.peer.FramePeer; * As a minimum, a subclass must implement all the remaining abstract methods * as well as the following methods: *
    - *
  • {@link java.awt.peer.ComponentPeer#getLocationOnScreen()}
  • - *
  • {@link java.awt.peer.ComponentPeer#getGraphics()}
  • - *
  • {@link java.awt.peer.ComponentPeer#createImage(int, int)}
  • + *
  • {@link ComponentPeer#getLocationOnScreen()}
  • + *
  • {@link ComponentPeer#getGraphics()}
  • + *
  • {@link ComponentPeer#createImage(int, int)}
  • *
* * @author Roman Kennke (kennke@aicas.com) @@ -97,9 +98,9 @@ public abstract class SwingFramePeer * * @param g the graphics context to use for painting */ - protected void peerPaint(Graphics g) + protected void peerPaintComponent(Graphics g) { - super.peerPaint(g); + super.peerPaintComponent(g); if (menuBar != null) menuBar.peerPaint(g); } diff --git a/gnu/java/awt/peer/swing/SwingLabelPeer.java b/gnu/java/awt/peer/swing/SwingLabelPeer.java index dd86fff2d..349c5a0ab 100644 --- a/gnu/java/awt/peer/swing/SwingLabelPeer.java +++ b/gnu/java/awt/peer/swing/SwingLabelPeer.java @@ -37,6 +37,8 @@ exception statement from your version. */ package gnu.java.awt.peer.swing; +import java.awt.Container; +import java.awt.Graphics; import java.awt.Image; import java.awt.Label; import java.awt.Point; @@ -67,7 +69,14 @@ public class SwingLabelPeer extends JLabel implements SwingComponent { - + Label label; + + + SwingLabel(Label label) + { + this.label = label; + } + /** * Returns this label. * @@ -131,8 +140,8 @@ public class SwingLabelPeer public boolean isShowing() { boolean retVal = false; - if (SwingLabelPeer.this.awtComponent != null) - retVal = SwingLabelPeer.this.awtComponent.isShowing(); + if (label != null) + retVal = label.isShowing(); return retVal; } @@ -149,7 +158,19 @@ public class SwingLabelPeer { return SwingLabelPeer.this.createImage(w, h); } - + + public Graphics getGraphics() + { + return SwingLabelPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (label != null) + par = label.getParent(); + return par; + } } /** @@ -160,11 +181,11 @@ public class SwingLabelPeer public SwingLabelPeer(Label label) { super(); - SwingLabel swingLabel = new SwingLabel(); + SwingLabel swingLabel = new SwingLabel(label); swingLabel.setText(label.getText()); - swingLabel.setHorizontalAlignment(label.getAlignment()); swingLabel.setOpaque(true); init(label, swingLabel); + setAlignment(label.getAlignment()); } /** @@ -190,7 +211,20 @@ public class SwingLabelPeer */ public void setAlignment(int alignment) { - ((JLabel) swingComponent.getJComponent()).setHorizontalAlignment(alignment); + JLabel swingLabel = (JLabel) swingComponent.getJComponent(); + switch (alignment) + { + case Label.RIGHT: + swingLabel.setHorizontalAlignment(JLabel.RIGHT); + break; + case Label.CENTER: + swingLabel.setHorizontalAlignment(JLabel.CENTER); + break; + case Label.LEFT: + default: + swingLabel.setHorizontalAlignment(JLabel.LEFT); + break; + } } } diff --git a/gnu/java/awt/peer/swing/SwingListPeer.java b/gnu/java/awt/peer/swing/SwingListPeer.java new file mode 100644 index 000000000..aca207048 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingListPeer.java @@ -0,0 +1,352 @@ +/* SwingListPeer.java -- A Swing based peer for AWT lists + 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.java.awt.peer.swing; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.List; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ListPeer; + +import javax.swing.DefaultListModel; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; + +public class SwingListPeer + extends SwingComponentPeer + implements ListPeer +{ + + /** + * A spezialized Swing scroller used to hold the list. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingList + extends JScrollPane + implements SwingComponent + { + + SwingList(Component comp) + { + super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + dispatchEvent(ev); + } + + /** + * Force lightweight mouse dispatching. + */ + public boolean isLightweight() + { + return false; + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingListPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingListPeer.this.awtComponent != null) + retVal = SwingListPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingListPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingListPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (SwingListPeer.this.awtComponent != null) + par = SwingListPeer.this.awtComponent.getParent(); + return par; + } + } + + /** + * The actual Swing JList. + */ + private JList jList; + + private DefaultListModel listModel; + + public SwingListPeer(List list) + { + super(); + listModel = new DefaultListModel(); + jList = new JList(listModel); + SwingList swingList = new SwingList(jList); + init(list, swingList); + + // Pull over the items from the list. + String[] items = list.getItems(); + for (int i = 0 ; i < items.length; i++) + addItem(items[i], i); + } + + public void add(String item, int index) + { + if (listModel != null) + listModel.add(index, item); + } + + public void addItem(String item, int index) + { + if (listModel != null) + listModel.add(index, item); + } + + public void clear() + { + if (listModel != null) + listModel.clear(); + } + + public void delItems(int startIndex, int endIndex) + { + if (listModel != null) + listModel.removeRange(startIndex, endIndex); + } + + public void deselect(int index) + { + if (jList != null) + { + jList.getSelectionModel().removeSelectionInterval(index, index); + } + } + + public Dimension getMinimumSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getMinimumSize(); + } + return d; + } + + public Dimension getPreferredSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getPreferredSize(); + } + return d; + } + + public int[] getSelectedIndexes() + { + int[] sel = null; + if (jList != null) + { + sel = jList.getSelectedIndices(); + } + return sel; + } + + public void makeVisible(int index) + { + if (jList != null) + { + Component comp = jList.getComponent(index); + jList.scrollRectToVisible(comp.getBounds()); + } + } + + public Dimension minimumSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getMinimumSize(); + } + return d; + } + + public Dimension preferredSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getPreferredSize(); + } + return d; + } + + public void removeAll() + { + if (jList != null) + { + jList.removeAll(); + } + } + + public void select(int index) + { + if (jList != null) + { + jList.setSelectedIndex(index); + } + } + + public void setMultipleMode(boolean multi) + { + if (jList != null) + { + jList.setSelectionMode(multi + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + } + } + + public void setMultipleSelections(boolean multi) + { + if (jList != null) + { + jList.setSelectionMode(multi + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + } + } + + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + { + swingComponent.getJComponent().setBounds(x, y, width, height); + swingComponent.getJComponent().validate(); + } + } + + protected void peerPaint(Graphics g, boolean update) + { + super.peerPaint(g, update); + jList.doLayout(); + jList.list(); + + Rectangle r = getBounds(); + g.setColor(Color.RED); + g.drawRect(r.x, r.y, r.width, r.height); + } +} diff --git a/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/gnu/java/awt/peer/swing/SwingMenuBarPeer.java index 0033efb02..bd9dcd77a 100644 --- a/gnu/java/awt/peer/swing/SwingMenuBarPeer.java +++ b/gnu/java/awt/peer/swing/SwingMenuBarPeer.java @@ -174,7 +174,7 @@ public class SwingMenuBarPeer /** * Adds a help menu to the menu bar. * - * @param menu the menu to add + * @param m the menu to add */ public void addHelpMenu(Menu menu) { diff --git a/gnu/java/awt/peer/swing/SwingPanelPeer.java b/gnu/java/awt/peer/swing/SwingPanelPeer.java index 0a0f20fe8..3cea62ac4 100644 --- a/gnu/java/awt/peer/swing/SwingPanelPeer.java +++ b/gnu/java/awt/peer/swing/SwingPanelPeer.java @@ -39,7 +39,6 @@ exception statement from your version. */ package gnu.java.awt.peer.swing; import java.awt.Panel; -import java.awt.peer.LightweightPeer; import java.awt.peer.PanelPeer; /** @@ -51,7 +50,7 @@ import java.awt.peer.PanelPeer; // necessary, but might be good for more consistend Look. public class SwingPanelPeer extends SwingContainerPeer - implements PanelPeer, LightweightPeer + implements PanelPeer { /** @@ -63,5 +62,6 @@ public class SwingPanelPeer public SwingPanelPeer(Panel panel) { super(panel); + init(panel, null); } } diff --git a/gnu/java/awt/peer/swing/SwingTextAreaPeer.java b/gnu/java/awt/peer/swing/SwingTextAreaPeer.java new file mode 100644 index 000000000..04ac01141 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingTextAreaPeer.java @@ -0,0 +1,317 @@ +/* SwingTextAreaPeer.java -- A Swing based peer for AWT textareas + 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.java.awt.peer.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; + +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.text.BadLocationException; + +public class SwingTextAreaPeer + extends SwingComponentPeer + implements TextAreaPeer +{ + + /** + * A spezialized Swing scroller used to hold the textarea. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingTextArea + extends JScrollPane + implements SwingComponent + { + + SwingTextArea(Component comp) + { + super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + dispatchEvent(ev); + } + + /** + * Force lightweight mouse dispatching. + */ + public boolean isLightweight() + { + return false; + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingTextAreaPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingTextAreaPeer.this.awtComponent != null) + retVal = SwingTextAreaPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingTextAreaPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingTextAreaPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (SwingTextAreaPeer.this.awtComponent != null) + par = SwingTextAreaPeer.this.awtComponent.getParent(); + return par; + } + } + + /** + * The actual JTextArea. + */ + private JTextArea jTextArea; + + public SwingTextAreaPeer(TextArea textArea) + { + super(); + System.err.println("new SwingTextAreaPeer"); + jTextArea = new JTextArea(); + SwingTextArea swingArea = new SwingTextArea(jTextArea); + init(textArea, swingArea); + + // Pull over the text from the text area. + setText(textArea.getText()); + } + + public Dimension getMinimumSize(int rows, int cols) + { + // TODO Auto-generated method stub + return null; + } + + public Dimension getPreferredSize(int rows, int cols) + { + // TODO Auto-generated method stub + return null; + } + + public void insert(String text, int pos) + { + jTextArea.insert(text, pos); + } + + public void insertText(String text, int pos) + { + jTextArea.insert(text, pos); + } + + public Dimension minimumSize(int rows, int cols) + { + // TODO Auto-generated method stub + return null; + } + + public Dimension preferredSize(int rows, int cols) + { + // TODO Auto-generated method stub + return null; + } + + public void replaceRange(String text, int start, int end) + { + jTextArea.replaceRange(text, start, end); + } + + public void replaceText(String text, int start, int end) + { + jTextArea.replaceRange(text, start, end); + } + + public long filterEvents(long filter) + { + // TODO Auto-generated method stub + return 0; + } + + public int getCaretPosition() + { + return jTextArea.getCaretPosition(); + } + + public Rectangle getCharacterBounds(int pos) + { + Rectangle r; + try + { + return jTextArea.modelToView(pos); + } + catch (BadLocationException ex) + { + r = null; + } + return r; + } + + public int getIndexAtPoint(int x, int y) + { + return jTextArea.viewToModel(new Point(x, y)); + } + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } + + public int getSelectionEnd() + { + return jTextArea.getSelectionEnd(); + } + + public int getSelectionStart() + { + return jTextArea.getSelectionStart(); + } + + public String getText() + { + return jTextArea.getText(); + } + + public void select(int start, int end) + { + jTextArea.select(start, end); + } + + public void setCaretPosition(int pos) + { + jTextArea.setCaretPosition(pos); + } + + public void setEditable(boolean editable) + { + jTextArea.setEditable(editable); + } + + public void setText(String text) + { + System.err.println("setText: " + text); + jTextArea.setText(text); + } + +} diff --git a/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/gnu/java/awt/peer/swing/SwingTextFieldPeer.java index 0c3b4e726..d7d574a0b 100644 --- a/gnu/java/awt/peer/swing/SwingTextFieldPeer.java +++ b/gnu/java/awt/peer/swing/SwingTextFieldPeer.java @@ -36,7 +36,10 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ package gnu.java.awt.peer.swing; +import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; @@ -69,6 +72,13 @@ public class SwingTextFieldPeer implements SwingComponent { + TextField textField; + + SwingTextField(TextField textField) + { + this.textField = textField; + } + /** * Overridden to provide normal behaviour even without a real peer * attached. @@ -90,8 +100,8 @@ public class SwingTextFieldPeer public boolean isShowing() { boolean retVal = false; - if (SwingTextFieldPeer.this.awtComponent != null) - retVal = SwingTextFieldPeer.this.awtComponent.isShowing(); + if (textField != null) + retVal = textField.isShowing(); return retVal; } @@ -151,7 +161,19 @@ public class SwingTextFieldPeer ev.setSource(this); processKeyEvent(ev); } - + + public Container getParent() + { + Container par = null; + if (textField != null) + par = textField.getParent(); + return par; + } + + public Graphics getGraphics() + { + return SwingTextFieldPeer.this.getGraphics(); + } } /** @@ -162,7 +184,7 @@ public class SwingTextFieldPeer */ public SwingTextFieldPeer(TextField textField) { - SwingTextField swingTextField = new SwingTextField(); + SwingTextField swingTextField = new SwingTextField(textField); swingTextField.setText(textField.getText()); init(textField, swingTextField); } @@ -283,7 +305,7 @@ public class SwingTextFieldPeer * @param startPos the start index of the selection * @param endPos the start index of the selection */ - public void select(int startPos, int endPos) + public void select(int start_pos, int endPos) { // TODO: Must be implemented. } diff --git a/gnu/java/awt/peer/swing/SwingWindowPeer.java b/gnu/java/awt/peer/swing/SwingWindowPeer.java index 43a509b95..531552d90 100644 --- a/gnu/java/awt/peer/swing/SwingWindowPeer.java +++ b/gnu/java/awt/peer/swing/SwingWindowPeer.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.java.awt.peer.swing; import java.awt.Window; +import java.awt.peer.ComponentPeer; import java.awt.peer.WindowPeer; /** @@ -48,9 +49,9 @@ import java.awt.peer.WindowPeer; * As a minimum, a subclass must implement all the remaining abstract methods * as well as the following methods: *
    - *
  • {@link java.awt.peer.ComponentPeer#getLocationOnScreen()}
  • - *
  • {@link java.awt.peer.ComponentPeer#getGraphics()}
  • - *
  • {@link java.awt.peer.ComponentPeer#createImage(int, int)}
  • + *
  • {@link ComponentPeer#getLocationOnScreen()}
  • + *
  • {@link ComponentPeer#getGraphics()}
  • + *
  • {@link ComponentPeer#createImage(int, int)}
  • *
* * @author Roman Kennke (kennke@aicas.com) @@ -68,5 +69,6 @@ public abstract class SwingWindowPeer public SwingWindowPeer(Window window) { super(window); + init(window, null); } } diff --git a/gnu/java/net/protocol/jar/Handler.java b/gnu/java/net/protocol/jar/Handler.java index 316d8cb02..7c09766a5 100644 --- a/gnu/java/net/protocol/jar/Handler.java +++ b/gnu/java/net/protocol/jar/Handler.java @@ -1,5 +1,5 @@ /* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net - Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,6 +45,9 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; /** * @author Kresten Krab Thorup (krab@gnu.org) @@ -114,7 +117,7 @@ public class Handler extends URLStreamHandler file = file.substring(0, idx + 1) + url_string; } - setURL (url, "jar", url.getHost(), url.getPort(), file, null); + setURL (url, "jar", url.getHost(), url.getPort(), flat(file), null); return; } @@ -148,6 +151,45 @@ public class Handler extends URLStreamHandler setURL (url, "jar", url.getHost(), url.getPort(), url_string, null); } + /** + * Makes the given jar url string 'flat' by removing any . and .. from + * jar file path because ZipFile entries can only handle flat paths. + * Inside jar files '/' is always the path separator. + */ + private static String flat(String url_string) + { + int jar_stop = url_string.indexOf("!/"); + String jar_path = url_string.substring(jar_stop + 1, url_string.length()); + + if (jar_path.indexOf("/.") < 0) + return url_string; + + ArrayList tokens = new ArrayList(); + StringTokenizer st = new StringTokenizer(jar_path, "/"); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (token.equals(".")) + continue; + else if (token.equals("..")) + { + if (! tokens.isEmpty()) + tokens.remove(tokens.size() - 1); + } + else + tokens.add(token); + } + + StringBuffer path = new StringBuffer(url_string.length()); + path.append(url_string.substring(0, jar_stop + 1)); + + Iterator it = tokens.iterator(); + while (it.hasNext()) + path.append('/').append(it.next()); + + return path.toString(); + } + /** * This method converts a Jar URL object into a String. * diff --git a/gnu/javax/swing/text/html/css/BorderWidth.java b/gnu/javax/swing/text/html/css/BorderWidth.java new file mode 100644 index 000000000..b717020e3 --- /dev/null +++ b/gnu/javax/swing/text/html/css/BorderWidth.java @@ -0,0 +1,66 @@ +/* BorderWidth.java -- A CSS metric for border widths + 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; + +/** + * A special CSS metric for border widths. It basically understands everything + * as Length, and in addition to that provides a mapping for the border-width's + * thin, medium and think values. + */ +public class BorderWidth + extends Length +{ + + /** + * Creates a new BorderWidth instance. + * + * @param val the CSS value to be interpreted + */ + public BorderWidth(String val) + { + super(val); + if (val.equals("thin")) + floatValue = 1.F; + else if (val.equals("medium")) + floatValue = 2.F; + else if (val.equals("thick")) + floatValue = 3.F; + } + +} diff --git a/gnu/javax/swing/text/html/css/CSSColor.java b/gnu/javax/swing/text/html/css/CSSColor.java index 381bcd5ed..57230f12a 100644 --- a/gnu/javax/swing/text/html/css/CSSColor.java +++ b/gnu/javax/swing/text/html/css/CSSColor.java @@ -40,6 +40,8 @@ package gnu.javax.swing.text.html.css; import java.awt.Color; import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; /** * Converts CSS color values into AWT Color values. @@ -131,4 +133,31 @@ public class CSSColor { return value; } + + /** + * Returns true if the specified value is a valid color value, + * false otherwise. + * + * @param val the value to check + * + * @return true if the specified value is a valid color value, + * false otherwise + */ + public static boolean isValidColor(String val) + { + boolean ret = false; + if (val.charAt(0) == '#') + ret = true; + else + { + Set colors = COLOR_MAP.keySet(); + for (Iterator i = colors.iterator(); i.hasNext() && ret == false;) + { + String color = (String) i.next(); + if (color.equalsIgnoreCase(val)) + ret = true; + } + } + return ret; + } } diff --git a/gnu/javax/swing/text/html/css/CSSParser.java b/gnu/javax/swing/text/html/css/CSSParser.java index 190c93eb4..0d68457a3 100644 --- a/gnu/javax/swing/text/html/css/CSSParser.java +++ b/gnu/javax/swing/text/html/css/CSSParser.java @@ -39,6 +39,8 @@ exception statement from your version. */ package gnu.javax.swing.text.html.css; import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -156,7 +158,7 @@ public class CSSParser { StringBuilder selector = new StringBuilder(); parseSelector(selector); - callback.startStatement(selector.toString()); + callback.startStatement(new Selector(selector.toString())); // Read any number of whitespace. int token; do @@ -296,7 +298,9 @@ public class CSSParser throws IOException { // FIXME: Handle block and ATKEYWORD. - return parseAny(s); + boolean success = parseAny(s); + while (parseAny(s)); + return success; } /** @@ -439,13 +443,22 @@ public class CSSParser { try { - String name = "/javax/swing/text/html/default.css"; - InputStream in = CSSScanner.class.getResourceAsStream(name); + InputStream in; + if (args.length > 0) + { + File file = new File(args[0]); + in = new FileInputStream(file); + } + else + { + String name = "/javax/swing/text/html/default.css"; + in = CSSScanner.class.getResourceAsStream(name); + } BufferedInputStream bin = new BufferedInputStream(in); InputStreamReader r = new InputStreamReader(bin); CSSParserCallback cb = new CSSParserCallback() { - public void startStatement(String selector) + public void startStatement(Selector selector) { System.out.println("startStatement: " + selector); } diff --git a/gnu/javax/swing/text/html/css/CSSParserCallback.java b/gnu/javax/swing/text/html/css/CSSParserCallback.java index 60dc5488a..b62baddfc 100644 --- a/gnu/javax/swing/text/html/css/CSSParserCallback.java +++ b/gnu/javax/swing/text/html/css/CSSParserCallback.java @@ -62,7 +62,7 @@ public interface CSSParserCallback * * @param selector the selector of the statement. */ - void startStatement(String selector); + void startStatement(Selector selector); /** * Signals the end of a statement. diff --git a/gnu/javax/swing/text/html/css/CSSScanner.java b/gnu/javax/swing/text/html/css/CSSScanner.java index a402b9522..9cc6209a5 100644 --- a/gnu/javax/swing/text/html/css/CSSScanner.java +++ b/gnu/javax/swing/text/html/css/CSSScanner.java @@ -509,6 +509,7 @@ class CSSScanner { parseBuffer[tokenEnd] = (char) ch; tokenEnd++; + ch = read(); } // Push back last read character since it doesn't belong to the IDENT. diff --git a/gnu/javax/swing/text/html/css/Length.java b/gnu/javax/swing/text/html/css/Length.java index 7091fbae7..339e2a2e0 100644 --- a/gnu/javax/swing/text/html/css/Length.java +++ b/gnu/javax/swing/text/html/css/Length.java @@ -54,7 +54,12 @@ public class Length /** * The converted value. */ - private float floatValue; + protected float floatValue; + + /** + * Indicates when the value is a percentage value. + */ + private boolean isPercentage; /** * Creates a new length converter instance. @@ -65,16 +70,31 @@ public class Length { value = val; int i = value.indexOf("px"); - floatValue = 0.0F; - if (i != -1) + int percent = value.indexOf("%"); + try { - String sub = value.substring(0, i); - floatValue = Float.parseFloat(sub); + floatValue = 0.0F; + if (i != -1) + { + String sub = value.substring(0, i); + floatValue = Float.parseFloat(sub); + } + else if (percent != -1) + { + isPercentage = true; + String sub = value.substring(0, percent); + floatValue = Float.parseFloat(sub) / 100; + } + else + { + // TODO: Implement other length options. + floatValue = Float.parseFloat(value); + } } - else + catch (NumberFormatException ex) { - // TODO: Implement other length options. - floatValue = Float.parseFloat(value); + // Don't let such small problems interrupt CSS parsing. + System.err.println("couldn't parse: " + val); } } @@ -87,4 +107,32 @@ public class Length { return floatValue; } + + /** + * Returns the absolute span for the case when this length value is + * a relative value. + * + * @param available the target span + * + * @return the absolute span + */ + public float getValue(float available) + { + float span = floatValue; + if (isPercentage) + span *= available; + return span; + } + + /** + * Returns true when the length value is a percentage + * value, false otherwise. + * + * @return true when the length value is a percentage + * value, false otherwise + */ + public boolean isPercentage() + { + return isPercentage; + } } diff --git a/gnu/javax/swing/text/html/css/Selector.java b/gnu/javax/swing/text/html/css/Selector.java new file mode 100644 index 000000000..75f2d46c6 --- /dev/null +++ b/gnu/javax/swing/text/html/css/Selector.java @@ -0,0 +1,233 @@ +/* Selector.java -- A CSS selector + 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; + +import java.util.StringTokenizer; + +/** + * A CSS selector. This provides methods to interpret a selector and + * query matches with an actual HTML element tree. + */ +public class Selector +{ + + /** + * The actual selector. The selector tokens are stored backwards, that + * is the last token first. This makes matching easier. + */ + private String[] selector; + + private String[] elements; + private String[] ids; + private String[] classes; + + /** + * The specificity of the selector. + */ + private int specificity; + + /** + * An implicit selector has true here. This is the case for CSS rules that + * are attached to HTML elements directly via style="". + */ + private boolean implicit; + + /** + * Creates a new Selector instance for the specified selector string. + * + * @param sel the selector + */ + public Selector(String sel) + { + StringTokenizer selectorTokens = new StringTokenizer(sel, " "); + selector = new String[selectorTokens.countTokens()]; + for (int i = selector.length - 1; selectorTokens.hasMoreTokens(); i--) + { + selector[i] = selectorTokens.nextToken(); + } + calculateSpecificity(); + } + + /** + * Determines if this selector matches the element path specified in the + * arguments. The arguments hold the element names as well as class + * and id attibutes of the HTML element to be queried. The first item + * in the array is the deepest element and the last on the highest up (for + * instance, the html tag). + * + * @param tags + * @param classes + * @param ids + * + * @return true when this selector matches the element path, + * false otherwise + */ + public boolean matches(String[] tags, String[] pathClasses, String[] pathIds) + { + // TODO: This implements class, id and descendent matching. These are + // the most commonly used selector matchers in CSS together with HTML. + // However, the CSS spec defines a couple of more sophisticated matches + // which should be implemented. + // http://www.w3.org/TR/CSS21/selector.html + + // All parts of the selector must match at some point. + boolean match = false; + int numTags = tags.length; + int numSel = selector.length; + if (numSel <= numTags) + { + match = true; + int tagIndex = 0; + for (int j = 0; j < numSel && match; j++) + { + boolean tagMatch = false; + for (; tagIndex < numTags && tagMatch == false; tagIndex++) + { + 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])); + tagMatch = tagMatch && (id.equals("*") + || id.equals(pathIds[tagIndex])); + // For the last element in the selector we must not look + // further. + if (j == 0) + break; + } + // If we don't come out here with a matching tag, then we're + // not matching at all. + match = tagMatch; + } + } + return match; + } + + /** + * Returns the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + * + * @return the specificity of the selector + */ + public int getSpecificity() + { + return specificity; + } + + /** + * Returns a string representation of the selector. This tries to reconstruct + * the original selector as closely as possible. + * + * @return a string representation of the selector + */ + public String toString() + { + StringBuilder b = new StringBuilder(); + for (int i = selector.length - 1; i >= 0; i--) + { + b.append(selector[i]); + if (i > 0) + b.append(' '); + } + return b.toString(); + } + + /** + * Calculates the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + */ + private void calculateSpecificity() + { + int a = implicit ? 1 : 0; + int b = 0; + int c = 0; + int d = 0; + int numSel = selector.length; + elements = new String[numSel]; + ids = new String[numSel]; + classes = new String[numSel]; + for (int i = 0; i < numSel; i++) + { + String sel = selector[i]; + int clazzIndex = sel.indexOf('.'); + int idIndex = sel.indexOf('#'); + String clazz; + if (clazzIndex == -1) + { + clazz = "*"; + clazzIndex = sel.length(); + } + else + { + c++; + clazz = sel.substring(clazzIndex + 1, + idIndex > 0 ? Math.min(idIndex, sel.length()) + : sel.length()); + } + String id; + if (idIndex == -1) + { + id = "*"; + idIndex = sel.length(); + } + else + { + b++; + id = sel.substring(idIndex + 1, + clazzIndex > 0 ? Math.min(idIndex, sel.length()) + : sel.length()); + } + String tag = sel.substring(0, + Math.min(Math.min(clazzIndex, idIndex), + sel.length())); + if (! tag.equals("") && ! tag.equals("*")) + d++; + + elements[i] = tag; + ids[i] = id; + classes[i] = clazz; + } + // An order of 20 should be enough for everybody. + specificity = a * 20 ^ 3 + b * 20 ^ 2 + c * 20 + d; + } +} diff --git a/gnu/javax/swing/text/html/parser/GnuParserDelegator.java b/gnu/javax/swing/text/html/parser/GnuParserDelegator.java index 841db667e..273461a72 100644 --- a/gnu/javax/swing/text/html/parser/GnuParserDelegator.java +++ b/gnu/javax/swing/text/html/parser/GnuParserDelegator.java @@ -43,6 +43,7 @@ import java.io.Reader; import java.io.Serializable; import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit.ParserCallback; import javax.swing.text.html.parser.DTD; @@ -92,7 +93,7 @@ public class GnuParserDelegator extends ParserDelegator implements Serializable protected final void handleStartTag(TagElement tag) { - htmlAttributeSet attributes = gnu.getAttributes(); + SimpleAttributeSet attributes = gnu.getAttributes(); if (tag.fictional()) attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE); diff --git a/gnu/javax/swing/text/html/parser/HTML_401Swing.java b/gnu/javax/swing/text/html/parser/HTML_401Swing.java deleted file mode 100644 index 9c934f647..000000000 --- a/gnu/javax/swing/text/html/parser/HTML_401Swing.java +++ /dev/null @@ -1,91 +0,0 @@ -/* HTML_401Swing.java -- The HTML 4.01 DTD, adapted for HTML rendering in Swing - 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.parser; - -import javax.swing.text.html.parser.DTD; - -/** - * This class is necessary because the current implementation of the GNU - * Classpath Swing requires always enclose the text into paragraphs. - * - * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) - */ -public class HTML_401Swing extends HTML_401F -{ - /** - * The singleton instance; - */ - final static HTML_401Swing singleton = new HTML_401Swing(); - - /** - * Either takes the document (by name) from DTD table, or - * creates a new instance and registers it in the tabe. - * The document is registerd under name "-//W3C//DTD HTML 4.01 Frameset//EN". - * @return The new or existing DTD for parsing HTML 4.01 Frameset. - */ - public static DTD getInstance() - { - return singleton; - } - - /** - * Get elements that are allowed in the document body, at the zero level. - * This list disallows the text at this level (the implied P tag will be - * generated). It also disallows A, B, I, U, CITE and other similar - * elements that have the plain text inside. They will also be placed - * inside the generated implied P tags. - */ - protected String[] getBodyElements() - { - return new String[] { - APPLET, BASEFONT, - BR, BUTTON, - IFRAME, IMG, - INPUT, LABEL, MAP, OBJECT, - SCRIPT, SELECT, - TEXTAREA, - BLOCKQUOTE, CENTER, DEL, DIR, - DIV, DL, FIELDSET, FORM, H1, - H2, H3, H4, H5, H6, - HR, INS, ISINDEX, MENU, NOFRAMES, - NOSCRIPT, OL, P, PRE, TABLE, - UL - }; - } -} diff --git a/gnu/javax/swing/text/html/parser/support/Parser.java b/gnu/javax/swing/text/html/parser/support/Parser.java index 92f9b27c5..f1f25fad0 100644 --- a/gnu/javax/swing/text/html/parser/support/Parser.java +++ b/gnu/javax/swing/text/html/parser/support/Parser.java @@ -56,6 +56,7 @@ import java.util.TreeSet; import java.util.Vector; import javax.swing.text.ChangedCharSetException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.html.HTML; import javax.swing.text.html.parser.AttributeList; import javax.swing.text.html.parser.DTD; @@ -250,9 +251,9 @@ public class Parser * Get the attributes of the current tag. * @return The attribute set, representing the attributes of the current tag. */ - public htmlAttributeSet getAttributes() + public SimpleAttributeSet getAttributes() { - return attributes; + return new SimpleAttributeSet(attributes); } /** @@ -661,12 +662,16 @@ public class Parser if (text != null && text.length > 0) { TagElement pcdata = new TagElement(dtd.getElement("#pcdata")); - attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; - _handleEmptyTag(pcdata); + if ((text.length > 1 && text[0] != ' ') + || validator.tagIsValidForContext(pcdata) == Boolean.TRUE) + { + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleEmptyTag(pcdata); - handleText(text); - if (titleOpen) - title.append(text); + handleText(text); + if (titleOpen) + title.append(text); + } } } @@ -1418,8 +1423,6 @@ public class Parser hTag = new Token(start, next); - attributes.setResolveParent(defaulter.getDefaultParameters(name.getImage())); - if (!end) { // The tag body contains errors. If additionally the tag diff --git a/include/gnu_java_net_VMPlainDatagramSocketImpl.h b/include/gnu_java_net_VMPlainDatagramSocketImpl.h deleted file mode 100644 index 2bd1f4905..000000000 --- a/include/gnu_java_net_VMPlainDatagramSocketImpl.h +++ /dev/null @@ -1,30 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __gnu_java_net_VMPlainDatagramSocketImpl__ -#define __gnu_java_net_VMPlainDatagramSocketImpl__ - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_bind (JNIEnv *env, jclass, jobject, jint, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_create (JNIEnv *env, jclass, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_connect (JNIEnv *env, jclass, jobject, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_nativeSendTo (JNIEnv *env, jclass, jobject, jobject, jint, jbyteArray, jint, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_nativeReceive (JNIEnv *env, jclass, jobject, jbyteArray, jint, jint, jbyteArray, jintArray, jintArray); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_setOption (JNIEnv *env, jclass, jobject, jint, jobject); -JNIEXPORT jobject JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_getOption (JNIEnv *env, jclass, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_close (JNIEnv *env, jclass, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_join (JNIEnv *env, jclass, jobject, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainDatagramSocketImpl_leave (JNIEnv *env, jclass, jobject, jobject); -#undef gnu_java_net_VMPlainDatagramSocketImpl_IP_TTL -#define gnu_java_net_VMPlainDatagramSocketImpl_IP_TTL 7777L - -#ifdef __cplusplus -} -#endif - -#endif /* __gnu_java_net_VMPlainDatagramSocketImpl__ */ diff --git a/include/gnu_java_nio_channels_FileChannelImpl.h b/include/gnu_java_nio_channels_FileChannelImpl.h deleted file mode 100644 index 1e09c09dd..000000000 --- a/include/gnu_java_nio_channels_FileChannelImpl.h +++ /dev/null @@ -1,46 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __gnu_java_nio_channels_FileChannelImpl__ -#define __gnu_java_nio_channels_FileChannelImpl__ - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_init (JNIEnv *env, jclass); -JNIEXPORT jint JNICALL Java_gnu_java_nio_channels_FileChannelImpl_open (JNIEnv *env, jobject, jstring, jint); -JNIEXPORT jint JNICALL Java_gnu_java_nio_channels_FileChannelImpl_available (JNIEnv *env, jobject); -JNIEXPORT jlong JNICALL Java_gnu_java_nio_channels_FileChannelImpl_implPosition (JNIEnv *env, jobject); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_seek (JNIEnv *env, jobject, jlong); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_implTruncate (JNIEnv *env, jobject, jlong); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_unlock (JNIEnv *env, jobject, jlong, jlong); -JNIEXPORT jlong JNICALL Java_gnu_java_nio_channels_FileChannelImpl_size (JNIEnv *env, jobject); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_implCloseChannel (JNIEnv *env, jobject); -JNIEXPORT jint JNICALL Java_gnu_java_nio_channels_FileChannelImpl_read__ (JNIEnv *env, jobject); -JNIEXPORT jint JNICALL Java_gnu_java_nio_channels_FileChannelImpl_read___3BII (JNIEnv *env, jobject, jbyteArray, jint, jint); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_write___3BII (JNIEnv *env, jobject, jbyteArray, jint, jint); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_write__I (JNIEnv *env, jobject, jint); -JNIEXPORT jobject JNICALL Java_gnu_java_nio_channels_FileChannelImpl_mapImpl (JNIEnv *env, jobject, jchar, jlong, jint); -JNIEXPORT void JNICALL Java_gnu_java_nio_channels_FileChannelImpl_force (JNIEnv *env, jobject); -JNIEXPORT jboolean JNICALL Java_gnu_java_nio_channels_FileChannelImpl_lock (JNIEnv *env, jobject, jlong, jlong, jboolean, jboolean); -#undef gnu_java_nio_channels_FileChannelImpl_READ -#define gnu_java_nio_channels_FileChannelImpl_READ 1L -#undef gnu_java_nio_channels_FileChannelImpl_WRITE -#define gnu_java_nio_channels_FileChannelImpl_WRITE 2L -#undef gnu_java_nio_channels_FileChannelImpl_APPEND -#define gnu_java_nio_channels_FileChannelImpl_APPEND 4L -#undef gnu_java_nio_channels_FileChannelImpl_EXCL -#define gnu_java_nio_channels_FileChannelImpl_EXCL 8L -#undef gnu_java_nio_channels_FileChannelImpl_SYNC -#define gnu_java_nio_channels_FileChannelImpl_SYNC 16L -#undef gnu_java_nio_channels_FileChannelImpl_DSYNC -#define gnu_java_nio_channels_FileChannelImpl_DSYNC 32L - -#ifdef __cplusplus -} -#endif - -#endif /* __gnu_java_nio_channels_FileChannelImpl__ */ diff --git a/java/awt/FlowLayout.java b/java/awt/FlowLayout.java index 8c9919528..70c98a29a 100644 --- a/java/awt/FlowLayout.java +++ b/java/awt/FlowLayout.java @@ -337,7 +337,10 @@ public class FlowLayout implements LayoutManager, Serializable Insets ins = parent.getInsets (); - w += (num + 1) * hgap + ins.left + ins.right; + if (num == 0) + w += 2 * hgap + ins.left + ins.right; + else + w += (num + 1) * hgap + ins.left + ins.right; h += 2 * vgap + ins.top + ins.bottom; return new Dimension (w, h); diff --git a/java/awt/TextComponent.java b/java/awt/TextComponent.java index 4fc62a951..8fdd94139 100644 --- a/java/awt/TextComponent.java +++ b/java/awt/TextComponent.java @@ -391,7 +391,9 @@ public class TextComponent extends Component */ public synchronized void setSelectionStart(int selectionStart) { - select(selectionStart, getSelectionEnd()); + select(selectionStart, + (getSelectionEnd() < selectionStart) + ? selectionStart : getSelectionEnd()); } /** diff --git a/java/awt/TextField.java b/java/awt/TextField.java index 2aff0ca64..b1df66f7c 100644 --- a/java/awt/TextField.java +++ b/java/awt/TextField.java @@ -264,9 +264,12 @@ public class TextField extends TextComponent */ public Dimension minimumSize(int columns) { + if (isMinimumSizeSet()) + return new Dimension(minSize); + TextFieldPeer peer = (TextFieldPeer) getPeer (); if (peer == null) - return null; // FIXME: What do we do if there is no peer? + return new Dimension(getWidth(), getHeight()); return peer.getMinimumSize (columns); } @@ -316,10 +319,13 @@ public class TextField extends TextComponent */ public Dimension preferredSize(int columns) { + if (isPreferredSizeSet()) + return new Dimension(prefSize); + TextFieldPeer peer = (TextFieldPeer) getPeer (); if (peer == null) - return new Dimension (0, 0); - + return new Dimension (getWidth(), getHeight()); + return peer.getPreferredSize (columns); } diff --git a/java/awt/Toolkit.java b/java/awt/Toolkit.java index 9eb4da216..5ac9e2766 100644 --- a/java/awt/Toolkit.java +++ b/java/awt/Toolkit.java @@ -41,6 +41,7 @@ package java.awt; import gnu.classpath.SystemProperties; import gnu.java.awt.peer.GLightweightPeer; +import gnu.java.awt.peer.headless.HeadlessToolkit; import java.awt.datatransfer.Clipboard; import java.awt.dnd.DragGestureEvent; @@ -554,6 +555,14 @@ public abstract class Toolkit { if (toolkit != null) return toolkit; + + // Check for the headless property. + if (GraphicsEnvironment.isHeadless()) + { + toolkit = new HeadlessToolkit(); + return toolkit; + } + String toolkit_name = SystemProperties.getProperty("awt.toolkit", default_toolkit_name); try diff --git a/java/beans/SimpleBeanInfo.java b/java/beans/SimpleBeanInfo.java index cfb960484..56b1f7aa7 100644 --- a/java/beans/SimpleBeanInfo.java +++ b/java/beans/SimpleBeanInfo.java @@ -1,5 +1,5 @@ /* java.beans.SimpleBeanInfo - Copyright (C) 1998 Free Software Foundation, Inc. + Copyright (C) 1998, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,6 +40,7 @@ package java.beans; import java.awt.Image; import java.awt.Toolkit; +import java.net.URL; /** ** SimpleBeanInfo is a class you may extend to more easily @@ -130,10 +131,16 @@ public class SimpleBeanInfo implements BeanInfo { ** and its BeanInfo are both loaded by the same ** ClassLoader, generally a reasonable assumption. ** @param location the URL relative - ** @return the Image in question. + ** @return the Image in question (possibly null). **/ - public Image loadImage(String location) { - return Toolkit.getDefaultToolkit().getImage(getClass().getResource(location)); + public Image loadImage(String location) + { + if (location == null) + return null; + URL url = getClass().getResource(location); + if (url == null) + return null; + return Toolkit.getDefaultToolkit().getImage(url); } } diff --git a/java/beans/beancontext/BeanContextSupport.java b/java/beans/beancontext/BeanContextSupport.java index a12c078df..2dc2a4e4a 100644 --- a/java/beans/beancontext/BeanContextSupport.java +++ b/java/beans/beancontext/BeanContextSupport.java @@ -144,42 +144,61 @@ public class BeanContextSupport extends BeanContextChildSupport */ public BeanContextSupport () { - this (null, null, true, true); + this (null, null, false, true); } /** * Construct a BeanContextSupport instance. + * + * @param peer the bean context peer (null permitted). */ - public BeanContextSupport (BeanContext peer) + public BeanContextSupport(BeanContext peer) { - this (peer, null, true, true); + this (peer, null, false, true); } /** * Construct a BeanContextSupport instance. + * + * @param peer the bean context peer (null permitted). + * @param locale the locale (null permitted, equivalent to + * the default locale). */ - public BeanContextSupport (BeanContext peer, Locale lcle) + public BeanContextSupport (BeanContext peer, Locale locale) { - this (peer, lcle, true, true); + this (peer, locale, false, true); } /** * Construct a BeanContextSupport instance. + * + * @param peer the bean context peer (null permitted). + * @param locale the locale (null permitted, equivalent to + * the default locale). + * @param dtime a flag indicating whether or not the bean context is in + * design time mode. */ - public BeanContextSupport (BeanContext peer, Locale lcle, boolean dtime) + public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime) { - this (peer, lcle, dtime, true); + this (peer, locale, dtime, true); } /** * Construct a BeanContextSupport instance. + * + * @param peer the bean context peer (null permitted). + * @param locale the locale (null permitted, equivalent to + * the default locale). + * @param dtime a flag indicating whether or not the bean context is in + * design time mode. + * @param visible initial value of the okToUseGui flag. */ - public BeanContextSupport (BeanContext peer, Locale lcle, boolean dtime, + public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime, boolean visible) { super(peer); - locale = lcle == null ? Locale.getDefault() : lcle; + this.locale = locale == null ? Locale.getDefault() : locale; designTime = dtime; okToUseGui = visible; @@ -447,16 +466,40 @@ public class BeanContextSupport extends BeanContextChildSupport } } - public BeanContext getBeanContextPeer () - throws NotImplementedException + /** + * Returns the bean context peer. + * + * @return The bean context peer. + * + * @see BeanContextChildSupport#beanContextChildPeer + */ + public BeanContext getBeanContextPeer() { - throw new Error ("Not implemented"); + return (BeanContext) beanContextChildPeer; } - protected static final BeanContextChild getChildBeanContextChild (Object child) - throws NotImplementedException - { - throw new Error ("Not implemented"); + /** + * Returns the {@link BeanContextChild} implementation for the given child. + * + * @param child the child (null permitted). + * + * @return The bean context child. + * + * @throws IllegalArgumentException if child implements both + * the {@link BeanContextChild} and {@link BeanContextProxy} interfaces. + */ + protected static final BeanContextChild getChildBeanContextChild(Object child) + { + if (child == null) + return null; + if (child instanceof BeanContextChild && child instanceof BeanContextProxy) + throw new IllegalArgumentException("Child cannot implement " + + "BeanContextChild and BeanContextProxy simultaneously."); + if (child instanceof BeanContextChild) + return (BeanContextChild) child; + if (child instanceof BeanContextProxy) + return ((BeanContextProxy) child).getBeanContextProxy(); + return null; } protected static final BeanContextMembershipListener getChildBeanContextMembershipListener (Object child) diff --git a/java/io/OutputStreamWriter.java b/java/io/OutputStreamWriter.java index 572683834..26363401f 100644 --- a/java/io/OutputStreamWriter.java +++ b/java/io/OutputStreamWriter.java @@ -223,6 +223,7 @@ public class OutputStreamWriter extends Writer encoder.onMalformedInput(CodingErrorAction.REPLACE); encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); outputBuffer = CharBuffer.allocate(BUFFER_SIZE); + encodingName = EncodingHelper.getOldCanonical(cs.name()); } /** @@ -240,6 +241,11 @@ public class OutputStreamWriter extends Writer this.out = out; encoder = enc; outputBuffer = CharBuffer.allocate(BUFFER_SIZE); + Charset cs = enc.charset(); + if (cs == null) + encodingName = "US-ASCII"; + else + encodingName = EncodingHelper.getOldCanonical(cs.name()); } /** diff --git a/java/util/Collections.java b/java/util/Collections.java index cd4a6fb40..c15fa092b 100644 --- a/java/util/Collections.java +++ b/java/util/Collections.java @@ -2068,10 +2068,11 @@ public class Collections * sorts the array, and then iterates over the list setting each element from * the array. * - * @param l the List to sort + * @param l the List to sort (null not permitted) * @throws ClassCastException if some items are not mutually comparable * @throws UnsupportedOperationException if the List is not modifiable - * @throws NullPointerException if some element is null + * @throws NullPointerException if the list is null, or contains + * some element that is null. * @see Arrays#sort(Object[]) */ public static > void sort(List l) @@ -2087,13 +2088,15 @@ public class Collections * sorts the array, and then iterates over the list setting each element from * the array. * - * @param l the List to sort + * @param l the List to sort (null not permitted) * @param c the Comparator specifying the ordering for the elements, or - * null for natural ordering + * null for natural ordering * @throws ClassCastException if c will not compare some pair of items * @throws UnsupportedOperationException if the List is not modifiable - * @throws NullPointerException if null is compared by natural ordering - * (only possible when c is null) + * @throws NullPointerException if the List is null or + * null is compared by natural ordering (only possible + * when c is null) + * * @see Arrays#sort(Object[], Comparator) */ public static void sort(List l, Comparator c) diff --git a/java/util/regex/Matcher.java b/java/util/regex/Matcher.java index 3ddd42547..bf833673b 100644 --- a/java/util/regex/Matcher.java +++ b/java/util/regex/Matcher.java @@ -278,6 +278,7 @@ public final class Matcher implements MatchResult public Matcher reset (CharSequence input) { this.input = input; + this.inputCharIndexed = RE.makeCharIndexed(input, 0); return reset(); } diff --git a/javax/swing/JLabel.java b/javax/swing/JLabel.java index 3e0f28ed7..721287b21 100644 --- a/javax/swing/JLabel.java +++ b/javax/swing/JLabel.java @@ -431,11 +431,11 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * Creates a new vertically and horizontally centered * JLabel object with no text and the given icon. * - * @param image The icon to use with the label. + * @param image The icon to use with the label, null permitted. */ public JLabel(Icon image) { - this("", image, CENTER); + this(null, image, CENTER); } /** @@ -443,19 +443,21 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * given icon and horizontal alignment. By default, the text is TRAILING * the image. * - * @param image The icon to use with the label. - * @param horizontalAlignment The horizontal alignment of the label. + * @param image The icon to use with the label, null premitted. + * @param horizontalAlignment The horizontal alignment of the label, must be + * either CENTER, LEFT, RIGHT, + * LEADING or TRAILING. */ public JLabel(Icon image, int horizontalAlignment) { - this("", image, horizontalAlignment); + this(null, image, horizontalAlignment); } /** * Creates a new horizontally leading and vertically centered JLabel * object with no icon and the given text. * - * @param text The text to use with the label. + * @param text The text to use with the label, null permitted. */ public JLabel(String text) { @@ -466,8 +468,10 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * Creates a new vertically centered JLabel object with no icon and the * given text and horizontal alignment. * - * @param text The text to use with the label. - * @param horizontalAlignment The horizontal alignment of the label. + * @param text The text to use with the label, null permitted. + * @param horizontalAlignment The horizontal alignment of the label, must be + * either CENTER, LEFT, RIGHT, + * LEADING or TRAILING. */ public JLabel(String text, int horizontalAlignment) { @@ -478,12 +482,21 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * Creates a new vertically centered JLabel object with the given text, * icon, and horizontal alignment. * - * @param text The text to use with the label. - * @param icon The icon to use with the label. - * @param horizontalAlignment The horizontal alignment of the label. + * @param text The text to use with the label, null permitted. + * @param icon The icon to use with the label, null premitted. + * @param horizontalAlignment The horizontal alignment of the label, must be + * either CENTER, LEFT, RIGHT, + * LEADING or TRAILING. */ public JLabel(String text, Icon icon, int horizontalAlignment) { + if (horizontalAlignment != SwingConstants.LEFT + && horizontalAlignment != SwingConstants.RIGHT + && horizontalAlignment != SwingConstants.CENTER + && horizontalAlignment != SwingConstants.LEADING + && horizontalAlignment != SwingConstants.TRAILING) + throw new IllegalArgumentException(); + this.text = text; this.icon = icon; this.horizontalAlignment = horizontalAlignment; diff --git a/javax/swing/JTree.java b/javax/swing/JTree.java index c6f08b49c..332ec7424 100644 --- a/javax/swing/JTree.java +++ b/javax/swing/JTree.java @@ -1230,8 +1230,32 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public void treeNodesRemoved(TreeModelEvent ev) { - // TODO: The API docs suggest that this method should do something - // but I cannot really see what has to be done here ... + if (ev != null) + { + TreePath parent = ev.getTreePath(); + Object[] children = ev.getChildren(); + TreeSelectionModel sm = getSelectionModel(); + if (children != null) + { + TreePath path; + Vector toRemove = new Vector(); + // Collect items that we must remove. + for (int i = children.length - 1; i >= 0; i--) + { + path = parent.pathByAddingChild(children[i]); + if (nodeStates.containsKey(path)) + toRemove.add(path); + // Clear selection while we are at it. + if (sm != null) + removeDescendantSelectedPaths(path, true); + } + if (toRemove.size() > 0) + removeDescendantToggledPaths(toRemove.elements()); + TreeModel model = getModel(); + if (model == null || model.isLeaf(parent.getLastPathComponent())) + nodeStates.remove(parent); + } + } } /** @@ -1243,9 +1267,38 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public void treeStructureChanged(TreeModelEvent ev) { - // Set state of new path. - TreePath path = ev.getTreePath(); - setExpandedState(path, isExpanded(path)); + if (ev != null) + { + TreePath parent = ev.getTreePath(); + if (parent != null) + { + if (parent.getPathCount() == 1) + { + // We have a new root, clear everything. + clearToggledPaths(); + Object root = treeModel.getRoot(); + if (root != null && treeModel.isLeaf(root)) + nodeStates.put(parent, Boolean.TRUE); + } + else if (nodeStates.containsKey(parent)) + { + Vector toRemove = new Vector(); + boolean expanded = isExpanded(parent); + toRemove.add(parent); + removeDescendantToggledPaths(toRemove.elements()); + if (expanded) + { + TreeModel model = getModel(); + if (model != null + || model.isLeaf(parent.getLastPathComponent())) + collapsePath(parent); + else + nodeStates.put(parent, Boolean.TRUE); + } + } + removeDescendantSelectedPaths(parent, false); + } + } } } @@ -1399,8 +1452,10 @@ public class JTree extends JComponent implements Scrollable, Accessible * This contains the state of all nodes in the tree. Al/ entries map the * TreePath of a note to to its state. Valid states are EXPANDED and * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED. + * + * This is package private to avoid accessor methods. */ - private Hashtable nodeStates = new Hashtable(); + Hashtable nodeStates = new Hashtable(); protected transient TreeCellEditor cellEditor; @@ -2201,20 +2256,35 @@ public class JTree extends JComponent implements Scrollable, Accessible public void setSelectionPath(TreePath path) { + clearSelectionPathStates(); selectionModel.setSelectionPath(path); } public void setSelectionPaths(TreePath[] paths) { + clearSelectionPathStates(); selectionModel.setSelectionPaths(paths); } + + /** + * This method, and all calls to it, should be removed once the + * DefaultTreeModel fires events properly. Maintenance of the nodeStates + * table should really be done in the TreeModelHandler. + */ + private void clearSelectionPathStates() + { + TreePath[] oldPaths = selectionModel.getSelectionPaths(); + if (oldPaths != null) + for (int i = 0; i < oldPaths.length; i++) + nodeStates.remove(oldPaths[i]); + } public void setSelectionRow(int row) { TreePath path = getPathForRow(row); if (path != null) - selectionModel.setSelectionPath(path); + setSelectionPath(path); } public void setSelectionRows(int[] rows) @@ -2289,11 +2359,13 @@ public class JTree extends JComponent implements Scrollable, Accessible public void removeSelectionPath(TreePath path) { + clearSelectionPathStates(); selectionModel.removeSelectionPath(path); } public void removeSelectionPaths(TreePath[] paths) { + clearSelectionPathStates(); selectionModel.removeSelectionPaths(paths); } @@ -2302,7 +2374,7 @@ public class JTree extends JComponent implements Scrollable, Accessible TreePath path = getPathForRow(row); if (path != null) - selectionModel.removeSelectionPath(path); + removeSelectionPath(path); } public void removeSelectionRows(int[] rows) diff --git a/javax/swing/text/ComponentView.java b/javax/swing/text/ComponentView.java index 555120396..8de4de60f 100644 --- a/javax/swing/text/ComponentView.java +++ b/javax/swing/text/ComponentView.java @@ -397,7 +397,24 @@ public class ComponentView extends View { public void run() { - setParentImpl(); + Document doc = getDocument(); + try + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + setParentImpl(); + Container host = getContainer(); + if (host != null) + { + preferenceChanged(null, true, true); + host.repaint(); + } + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } } }); } diff --git a/javax/swing/text/CompositeView.java b/javax/swing/text/CompositeView.java index ab587a9e1..d4467f314 100644 --- a/javax/swing/text/CompositeView.java +++ b/javax/swing/text/CompositeView.java @@ -134,7 +134,7 @@ public abstract class CompositeView public void setParent(View parent) { super.setParent(parent); - if (parent != null && ((children == null) || children.length == 0)) + if (parent != null && numChildren == 0) loadChildren(getViewFactory()); } diff --git a/javax/swing/text/FlowView.java b/javax/swing/text/FlowView.java index cee5bb126..9609f3fc8 100644 --- a/javax/swing/text/FlowView.java +++ b/javax/swing/text/FlowView.java @@ -189,7 +189,7 @@ public abstract class FlowView extends BoxView // Then remove all views from the flow view. fv.removeAll(); - + for (int rowIndex = 0; start < end; rowIndex++) { View row = fv.createRow(); @@ -318,8 +318,8 @@ public abstract class FlowView extends BoxView int rowIndex) { View logicalView = getLogicalView(fv); - // FIXME: Handle the bias thing correctly. - int index = logicalView.getViewIndex(startOffset, Position.Bias.Forward); + int index = logicalView.getViewIndex(startOffset, + Position.Bias.Forward); View retVal = logicalView.getView(index); if (retVal.getStartOffset() != startOffset) retVal = retVal.createFragment(startOffset, retVal.getEndOffset()); @@ -603,6 +603,7 @@ public abstract class FlowView extends BoxView { super(element, axis); strategy = sharedStrategy; + layoutSpan = Short.MAX_VALUE; } /** @@ -651,7 +652,7 @@ public abstract class FlowView extends BoxView */ public int getFlowStart(int index) { - return getLeftInset(); // TODO: Is this correct? + return 0; } /** @@ -678,8 +679,8 @@ public abstract class FlowView extends BoxView if (layoutPool == null) { layoutPool = new LogicalView(getElement()); - layoutPool.setParent(this); } + layoutPool.setParent(this); // Initialize the flow strategy. strategy.insertUpdate(this, null, null); } @@ -696,21 +697,17 @@ public abstract class FlowView extends BoxView protected void layout(int width, int height) { int flowAxis = getFlowAxis(); + int span; if (flowAxis == X_AXIS) - { - if (layoutSpan != width) - { - layoutChanged(Y_AXIS); - layoutSpan = width; - } - } + span = (int) width; else + span = (int) height; + + if (layoutSpan != span) { - if (layoutSpan != height) - { - layoutChanged(X_AXIS); - layoutSpan = height; - } + layoutChanged(flowAxis); + layoutChanged(getAxis()); + layoutSpan = span; } if (! isLayoutValid(flowAxis)) diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java index cb7f8f05d..35c8dd5d7 100644 --- a/javax/swing/text/GlyphView.java +++ b/javax/swing/text/GlyphView.java @@ -252,6 +252,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ static class DefaultGlyphPainter extends GlyphPainter { + FontMetrics fontMetrics; + /** * Returns the full height of the rendered text. * @@ -259,9 +261,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ public float getHeight(GlyphView view) { - Font font = view.getFont(); - FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font); - float height = metrics.getHeight(); + updateFontMetrics(view); + float height = fontMetrics.getHeight(); return height; } @@ -341,16 +342,16 @@ public class GlyphView extends View implements TabableView, Cloneable Shape a) throws BadLocationException { + updateFontMetrics(view); Element el = view.getElement(); - Font font = view.getFont(); - FontMetrics fm = view.getContainer().getFontMetrics(font); Segment txt = view.getText(el.getStartOffset(), pos); Rectangle bounds = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); TabExpander expander = view.getTabExpander(); - int width = Utilities.getTabbedTextWidth(txt, fm, bounds.x, expander, + int width = Utilities.getTabbedTextWidth(txt, fontMetrics, bounds.x, + expander, view.getStartOffset()); - int height = fm.getHeight(); + int height = fontMetrics.getHeight(); Rectangle result = new Rectangle(bounds.x + width, bounds.y, 0, height); return result; @@ -375,10 +376,10 @@ public class GlyphView extends View implements TabableView, Cloneable public float getSpan(GlyphView view, int p0, int p1, TabExpander te, float x) { - Font font = view.getFont(); - FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font); + updateFontMetrics(view); Segment txt = view.getText(p0, p1); - int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0); + int span = Utilities.getTabbedTextWidth(txt, fontMetrics, (int) x, te, + p0); return span; } @@ -395,9 +396,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ public float getAscent(GlyphView v) { - Font font = v.getFont(); - FontMetrics fm = v.getContainer().getFontMetrics(font); - return fm.getAscent(); + updateFontMetrics(v); + return fontMetrics.getAscent(); } /** @@ -413,9 +413,8 @@ public class GlyphView extends View implements TabableView, Cloneable */ public float getDescent(GlyphView v) { - Font font = v.getFont(); - FontMetrics fm = v.getContainer().getFontMetrics(font); - return fm.getDescent(); + updateFontMetrics(v); + return fontMetrics.getDescent(); } /** @@ -430,16 +429,10 @@ public class GlyphView extends View implements TabableView, Cloneable */ public int getBoundedPosition(GlyphView v, int p0, float x, float len) { + updateFontMetrics(v); TabExpander te = v.getTabExpander(); Segment txt = v.getText(p0, v.getEndOffset()); - Font font = v.getFont(); - Container c = v.getContainer(); - FontMetrics fm; - if (c != null) - fm = c.getFontMetrics(font); - else - fm = Toolkit.getDefaultToolkit().getFontMetrics(font); - int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x, + int pos = Utilities.getTabbedTextOffset(txt, fontMetrics, (int) x, (int) (x + len), te, p0, false); return pos + p0; } @@ -458,9 +451,33 @@ public class GlyphView extends View implements TabableView, Cloneable public int viewToModel(GlyphView v, float x, float y, Shape a, Bias[] biasRet) { - Rectangle b = a.getBounds(); - int pos = getBoundedPosition(v, v.getStartOffset(), b.x, x - b.x); - return pos + v.getStartOffset(); + Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + int p0 = v.getStartOffset(); + int p1 = v.getEndOffset(); + TabExpander te = v.getTabExpander(); + Segment s = v.getText(p0, p1); + int offset = Utilities.getTabbedTextOffset(s, fontMetrics, r.x, (int) x, + te, p0); + int ret = p0 + offset; + if (ret == p1) + ret--; + biasRet[0] = Position.Bias.Forward; + return ret; + } + + private void updateFontMetrics(GlyphView v) + { + Font font = v.getFont(); + if (fontMetrics == null || ! font.equals(fontMetrics.getFont())) + { + Container c = v.getContainer(); + FontMetrics fm; + if (c != null) + fm = c.getFontMetrics(font); + else + fm = Toolkit.getDefaultToolkit().getFontMetrics(font); + fontMetrics = fm; + } } } diff --git a/javax/swing/text/ParagraphView.java b/javax/swing/text/ParagraphView.java index 6a13b2a3e..fb4ac65d8 100644 --- a/javax/swing/text/ParagraphView.java +++ b/javax/swing/text/ParagraphView.java @@ -38,6 +38,9 @@ exception statement from your version. */ package javax.swing.text; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; import java.awt.Shape; import javax.swing.SizeRequirements; @@ -103,19 +106,6 @@ public class ParagraphView extends FlowView implements TabExpander return align; } - /** - * Allows rows to span the whole parent view. - */ - public float getMaximumSpan(int axis) - { - float max; - if (axis == X_AXIS) - max = Float.MAX_VALUE; - else - max = super.getMaximumSpan(axis); - return max; - } - /** * Overridden because child views are not necessarily laid out in model * order. diff --git a/javax/swing/text/View.java b/javax/swing/text/View.java index aafd76a4f..dc611fe49 100644 --- a/javax/swing/text/View.java +++ b/javax/swing/text/View.java @@ -92,7 +92,14 @@ public abstract class View implements SwingConstants { int numChildren = getViewCount(); for (int i = 0; i < numChildren; i++) - getView(i).setParent(null); + { + View child = getView(i); + // It is important that we only reset the parent on views that + // actually belong to us. In FlowView the child may already be + // reparented. + if (child.getParent() == this) + child.setParent(null); + } } this.parent = parent; @@ -262,7 +269,7 @@ public abstract class View implements SwingConstants public void removeAll() { - replace(0, getViewCount(), new View[0]); + replace(0, getViewCount(), null); } public void remove(int index) @@ -618,10 +625,12 @@ public abstract class View implements SwingConstants DocumentEvent ev, Shape shape) { if (ec != null && shape != null) - preferenceChanged(null, true, true); - Container c = getContainer(); - if (c != null) - c.repaint(); + { + preferenceChanged(null, true, true); + Container c = getContainer(); + if (c != null) + c.repaint(); + } } /** diff --git a/javax/swing/text/html/BlockView.java b/javax/swing/text/html/BlockView.java index 6274e7b17..d7519ef9a 100644 --- a/javax/swing/text/html/BlockView.java +++ b/javax/swing/text/html/BlockView.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.Length; + import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; @@ -55,7 +57,24 @@ import javax.swing.text.ViewFactory; */ public class BlockView extends BoxView { - + + /** + * The attributes for this view. + */ + private AttributeSet attributes; + + /** + * The box painter for this view. + */ + private StyleSheet.BoxPainter painter; + + /** + * The width and height as specified in the stylesheet, null if not + * specified. The first value is the X_AXIS, the second the Y_AXIS. You + * can index this directly by the X_AXIS and Y_AXIS constants. + */ + private Length[] cssSpans; + /** * Creates a new view that represents an html box. * This can be used for a number of elements. @@ -66,8 +85,9 @@ public class BlockView extends BoxView public BlockView(Element elem, int axis) { super(elem, axis); + cssSpans = new Length[2]; } - + /** * Creates the parent view for this. It is called before * any other methods, if the parent view is working properly. @@ -99,12 +119,27 @@ public class BlockView extends BoxView protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) { - SizeRequirements sr = super.calculateMajorAxisRequirements(axis, r); - // FIXME: adjust it if the CSS width or height attribute is specified - // and applicable - return sr; + if (r == null) + r = new SizeRequirements(); + + if (setCSSSpan(r, axis)) + { + // If we have set the span from CSS, then we need to adjust + // the margins. + SizeRequirements parent = super.calculateMajorAxisRequirements(axis, + null); + int margin = axis == X_AXIS ? getLeftInset() + getRightInset() + : getTopInset() + getBottomInset(); + r.minimum -= margin; + r.preferred -= margin; + r.maximum -= margin; + constrainSize(axis, r, parent); + } + else + r = super.calculateMajorAxisRequirements(axis, r); + return r; } - + /** * Calculates the requirements along the minor axis. * This is implemented to call the superclass and then @@ -118,12 +153,73 @@ public class BlockView extends BoxView protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { - SizeRequirements sr = super.calculateMinorAxisRequirements(axis, r); - // FIXME: adjust it if the CSS width or height attribute is specified - // and applicable. - return sr; + if (r == null) + r = new SizeRequirements(); + + if (setCSSSpan(r, axis)) + { + // If we have set the span from CSS, then we need to adjust + // the margins. + SizeRequirements parent = super.calculateMinorAxisRequirements(axis, + null); + int margin = axis == X_AXIS ? getLeftInset() + getRightInset() + : getTopInset() + getBottomInset(); + r.minimum -= margin; + r.preferred -= margin; + r.maximum -= margin; + constrainSize(axis, r, parent); + } + else + r = super.calculateMinorAxisRequirements(axis, r); + return r; } - + + /** + * Sets the span on the SizeRequirements object according to the + * according CSS span value, when it is set. + * + * @param r the size requirements + * @param axis the axis + * + * @return true when the CSS span has been set, + * false otherwise + */ + private boolean setCSSSpan(SizeRequirements r, int axis) + { + boolean ret = false; + Length span = cssSpans[axis]; + // We can't set relative CSS spans here because we don't know + // yet about the allocated span. Instead we use the view's + // normal requirements. + if (span != null && ! span.isPercentage()) + { + r.minimum = (int) span.getValue(); + r.preferred = (int) span.getValue(); + r.maximum = (int) span.getValue(); + ret = true; + } + return ret; + } + + /** + * Constrains the r requirements according to + * min. + * + * @param axis the axis + * @param r the requirements to constrain + * @param min the constraining requirements + */ + private void constrainSize(int axis, SizeRequirements r, + SizeRequirements min) + { + if (min.minimum > r.minimum) + { + r.minimum = min.minimum; + r.preferred = min.minimum; + r.maximum = Math.max(r.maximum, min.maximum); + } + } + /** * Lays out the box along the minor axis (the axis that is * perpendicular to the axis that it represents). The results @@ -142,10 +238,40 @@ public class BlockView extends BoxView protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - // FIXME: Not implemented. - super.layoutMinorAxis(targetSpan, axis, offsets, spans); + int viewCount = getViewCount(); + CSS.Attribute spanAtt = axis == X_AXIS ? CSS.Attribute.WIDTH + : CSS.Attribute.HEIGHT; + for (int i = 0; i < viewCount; i++) + { + View view = getView(i); + int min = (int) view.getMinimumSpan(axis); + int max; + // Handle CSS span value of child. + AttributeSet atts = view.getAttributes(); + Length length = (Length) atts.getAttribute(spanAtt); + if (length != null) + { + min = Math.max((int) length.getValue(targetSpan), min); + max = min; + } + else + max = (int) view.getMaximumSpan(axis); + + if (max < targetSpan) + { + // Align child. + float align = view.getAlignment(axis); + offsets[i] = (int) ((targetSpan - max) * align); + spans[i] = max; + } + else + { + offsets[i] = 0; + spans[i] = Math.max(min, targetSpan); + } + } } - + /** * Paints using the given graphics configuration and shape. * This delegates to the css box painter to paint the @@ -156,11 +282,8 @@ public class BlockView extends BoxView */ public void paint(Graphics g, Shape a) { - Rectangle rect = (Rectangle) a; - // FIXME: not fully implemented - getStyleSheet().getBoxPainter(getAttributes()).paint(g, rect.x, rect.y, - rect.width, - rect.height, this); + Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + painter.paint(g, rect.x, rect.y, rect.width, rect.height, this); super.paint(g, a); } @@ -171,7 +294,9 @@ public class BlockView extends BoxView */ public AttributeSet getAttributes() { - return getStyleSheet().getViewAttributes(this); + if (attributes == null) + attributes = getStyleSheet().getViewAttributes(this); + return attributes; } /** @@ -206,8 +331,11 @@ public class BlockView extends BoxView if (getViewCount() == 0) return 0.0F; float prefHeight = getPreferredSpan(Y_AXIS); - float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS); - return (firstRowHeight / 2.F) / prefHeight; + View first = getView(0); + float firstRowHeight = first.getPreferredSpan(Y_AXIS); + return prefHeight != 0 ? (firstRowHeight * first.getAlignment(Y_AXIS)) + / prefHeight + : 0; } throw new IllegalArgumentException("Invalid Axis"); } @@ -227,7 +355,8 @@ public class BlockView extends BoxView // If more elements were added, then need to set the properties for them int currPos = ev.getOffset(); - if (currPos <= getStartOffset() && (currPos + ev.getLength()) >= getEndOffset()) + if (currPos <= getStartOffset() + && (currPos + ev.getLength()) >= getEndOffset()) setPropertiesFromAttributes(); } @@ -284,9 +413,27 @@ public class BlockView extends BoxView */ protected void setPropertiesFromAttributes() { - // FIXME: Not implemented (need to use StyleSheet). + // Fetch attributes. + StyleSheet ss = getStyleSheet(); + attributes = ss.getViewAttributes(this); + + // Fetch painter. + painter = ss.getBoxPainter(attributes); + + // Update insets. + if (attributes != null) + { + setInsets((short) painter.getInset(TOP, this), + (short) painter.getInset(LEFT, this), + (short) painter.getInset(BOTTOM, this), + (short) painter.getInset(RIGHT, this)); + } + + // Fetch width and height. + cssSpans[X_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.WIDTH); + cssSpans[Y_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.HEIGHT); } - + /** * Gets the default style sheet. * @@ -294,8 +441,7 @@ public class BlockView extends BoxView */ protected StyleSheet getStyleSheet() { - StyleSheet styleSheet = new StyleSheet(); - styleSheet.importStyleSheet(getClass().getResource(HTMLEditorKit.DEFAULT_CSS)); - return styleSheet; + HTMLDocument doc = (HTMLDocument) getDocument(); + return doc.getStyleSheet(); } } diff --git a/javax/swing/text/html/CSS.java b/javax/swing/text/html/CSS.java index 20a2debbc..6461dca9a 100644 --- a/javax/swing/text/html/CSS.java +++ b/javax/swing/text/html/CSS.java @@ -37,6 +37,7 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.BorderWidth; import gnu.javax.swing.text.html.css.CSSColor; import gnu.javax.swing.text.html.css.FontSize; import gnu.javax.swing.text.html.css.FontStyle; @@ -45,6 +46,9 @@ import gnu.javax.swing.text.html.css.Length; import java.io.Serializable; import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.swing.text.MutableAttributeSet; /** * Provides CSS attributes to be used by the HTML view classes. The constants @@ -394,6 +398,24 @@ public class CSS implements Serializable public static final Attribute WORD_SPACING = new Attribute("word-spacing", true, "normal"); + // Some GNU Classpath specific extensions. + static final Attribute BORDER_TOP_STYLE = + new Attribute("border-top-style", false, null); + static final Attribute BORDER_BOTTOM_STYLE = + new Attribute("border-bottom-style", false, null); + static final Attribute BORDER_LEFT_STYLE = + new Attribute("border-left-style", false, null); + static final Attribute BORDER_RIGHT_STYLE = + new Attribute("border-right-style", false, null); + static final Attribute BORDER_TOP_COLOR = + new Attribute("border-top-color", false, null); + static final Attribute BORDER_BOTTOM_COLOR = + new Attribute("border-bottom-color", false, null); + static final Attribute BORDER_LEFT_COLOR = + new Attribute("border-left-color", false, null); + static final Attribute BORDER_RIGHT_COLOR = + new Attribute("border-right-color", false, null); + /** * The attribute string. */ @@ -484,14 +506,44 @@ public class CSS implements Serializable o = new FontWeight(v); else if (att == Attribute.FONT_STYLE) o = new FontStyle(v); - else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR) + else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR + || att == Attribute.BORDER_COLOR + || att == Attribute.BORDER_TOP_COLOR + || att == Attribute.BORDER_BOTTOM_COLOR + || att == Attribute.BORDER_LEFT_COLOR + || att == Attribute.BORDER_RIGHT_COLOR) o = new CSSColor(v); else if (att == Attribute.MARGIN || att == Attribute.MARGIN_BOTTOM || att == Attribute.MARGIN_LEFT || att == Attribute.MARGIN_RIGHT - || att == Attribute.MARGIN_TOP) + || att == Attribute.MARGIN_TOP || att == Attribute.WIDTH + || att == Attribute.HEIGHT) o = new Length(v); + else if (att == Attribute.BORDER_WIDTH || att == Attribute.BORDER_TOP_WIDTH + || att == Attribute.BORDER_LEFT_WIDTH + || att == Attribute.BORDER_RIGHT_WIDTH + || att == Attribute.BORDER_BOTTOM_WIDTH) + o = new BorderWidth(v); else o = v; return o; } + + static void addInternal(MutableAttributeSet atts, Attribute a, String v) + { + if (a == Attribute.BACKGROUND) + parseBackgroundShorthand(atts, v); + } + + private static void parseBackgroundShorthand(MutableAttributeSet atts, + String v) + { + StringTokenizer tokens = new StringTokenizer(v, " "); + while (tokens.hasMoreElements()) + { + String token = tokens.nextToken(); + if (CSSColor.isValidColor(token)) + atts.addAttribute(Attribute.BACKGROUND_COLOR, + getValue(Attribute.BACKGROUND_COLOR, token)); + } + } } diff --git a/javax/swing/text/html/CSSBorder.java b/javax/swing/text/html/CSSBorder.java new file mode 100644 index 000000000..540955494 --- /dev/null +++ b/javax/swing/text/html/CSSBorder.java @@ -0,0 +1,420 @@ +/* CSSBorder.java -- A border for rendering CSS border styles + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import gnu.javax.swing.text.html.css.BorderWidth; +import gnu.javax.swing.text.html.css.CSSColor; +import gnu.javax.swing.text.html.css.Length; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.border.Border; +import javax.swing.text.AttributeSet; + +/** + * A border implementation to render CSS border styles. + */ +class CSSBorder + implements Border +{ + + /** + * The CSS border styles. + */ + + private static final int STYLE_NOT_SET = -1; + private static final int STYLE_NONE = 0; + private static final int STYLE_HIDDEN = 1; + private static final int STYLE_DOTTED = 2; + private static final int STYLE_DASHED = 3; + private static final int STYLE_SOLID = 4; + private static final int STYLE_DOUBLE = 5; + private static final int STYLE_GROOVE = 6; + private static final int STYLE_RIDGE = 7; + private static final int STYLE_INSET = 8; + private static final int STYLE_OUTSET = 9; + + /** + * The left insets. + */ + private int left; + + /** + * The right insets. + */ + private int right; + + /** + * The top insets. + */ + private int top; + + /** + * The bottom insets. + */ + private int bottom; + + /** + * The border style on the left. + */ + private int leftStyle; + + /** + * The border style on the right. + */ + private int rightStyle; + + /** + * The border style on the top. + */ + private int topStyle; + + /** + * The color for the top border. + */ + private Color topColor; + + /** + * The color for the bottom border. + */ + private Color bottomColor; + + /** + * The color for the left border. + */ + private Color leftColor; + + /** + * The color for the right border. + */ + private Color rightColor; + + /** + * The border style on the bottom. + */ + private int bottomStyle; + + /** + * Creates a new CSS border and fetches its attributes from the specified + * attribute set. + * + * @param atts the attribute set that contains the border spec + */ + CSSBorder(AttributeSet atts) + { + // Determine the border styles. + int style = getBorderStyle(atts, CSS.Attribute.BORDER_STYLE); + if (style == STYLE_NOT_SET) + style = STYLE_NONE; // Default to none. + topStyle = bottomStyle = leftStyle = rightStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_TOP_STYLE); + if (style != STYLE_NOT_SET) + topStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_BOTTOM_STYLE); + if (style != STYLE_NOT_SET) + bottomStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_LEFT_STYLE); + if (style != STYLE_NOT_SET) + leftStyle = style; + style = getBorderStyle(atts, CSS.Attribute.BORDER_RIGHT_STYLE); + if (style != STYLE_NOT_SET) + rightStyle = style; + + // Determine the border colors. + Color color = getBorderColor(atts, CSS.Attribute.BORDER_COLOR); + if (color == null) + color = Color.BLACK; + topColor = bottomColor = leftColor = rightColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_TOP_COLOR); + if (color != null) + topColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_BOTTOM_COLOR); + if (color != null) + bottomColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_LEFT_COLOR); + if (color != null) + leftColor = color; + color = getBorderColor(atts, CSS.Attribute.BORDER_RIGHT_COLOR); + if (color != null) + rightColor = color; + + // Determine the border widths. + int width = getBorderWidth(atts, CSS.Attribute.BORDER_WIDTH); + if (width == -1) + width = 0; + top = bottom = left = right = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_TOP_WIDTH); + if (width >= 0) + top = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_BOTTOM_WIDTH); + if (width >= 0) + bottom = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_LEFT_WIDTH); + if (width >= 0) + left = width; + width = getBorderWidth(atts, CSS.Attribute.BORDER_RIGHT_WIDTH); + if (width >= 0) + right = width; + } + + /** + * Determines the border style for a given CSS attribute. + * + * @param atts the attribute set + * @param key the CSS key + * + * @return the border style according to the constants defined in this class + */ + private int getBorderStyle(AttributeSet atts, CSS.Attribute key) + { + int style = STYLE_NOT_SET; + Object o = atts.getAttribute(key); + if (o != null) + { + String cssStyle = o.toString(); + if (cssStyle.equals("none")) + style = STYLE_NONE; + else if (cssStyle.equals("hidden")) + style = STYLE_HIDDEN; + else if (cssStyle.equals("dotted")) + style = STYLE_DOTTED; + else if (cssStyle.equals("dashed")) + style = STYLE_DASHED; + else if (cssStyle.equals("solid")) + style = STYLE_SOLID; + else if (cssStyle.equals("double")) + style = STYLE_DOUBLE; + else if (cssStyle.equals("groove")) + style = STYLE_GROOVE; + else if (cssStyle.equals("ridge")) + style = STYLE_RIDGE; + else if (cssStyle.equals("inset")) + style = STYLE_INSET; + else if (cssStyle.equals("outset")) + style = STYLE_OUTSET; + } + return style; + } + + /** + * Determines the border color for the specified key. + * + * @param atts the attribute set from which to fetch the color + * @param key the CSS key + * + * @return the border color + */ + private Color getBorderColor(AttributeSet atts, CSS.Attribute key) + { + Object o = atts.getAttribute(key); + Color color = null; + if (o instanceof CSSColor) + { + CSSColor cssColor = (CSSColor) o; + color = cssColor.getValue(); + } + return color; + } + + /** + * Returns the width for the specified key. + * + * @param atts the attributes to fetch the width from + * @param key the CSS key + * + * @return the width, or -1 of none has been set + */ + private int getBorderWidth(AttributeSet atts, CSS.Attribute key) + { + int width = -1; + Object o = atts.getAttribute(key); + if (o instanceof BorderWidth) + { + width = (int) ((BorderWidth) o).getValue(); + } + return width; + } + + /** + * Returns the border insets. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(top, left, bottom, right); + } + + /** + * CSS borders are generally opaque so return true here. + */ + public boolean isBorderOpaque() + { + return true; + } + + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) + { + // Top border. + paintBorderLine(g, x, y + top / 2, x + width, y + top / 2, topStyle, top, + topColor, false); + // Left border. + paintBorderLine(g, x + left / 2, y, x + left / 2, y + height, leftStyle, + left, leftColor, true); + // Bottom border. + paintBorderLine(g, x, y + height - bottom / 2, x + width, + y + height - bottom / 2, topStyle, bottom, bottomColor, + false); + // Right border. + paintBorderLine(g, x + width - right / 2, y, x + width - right / 2, + y + height, topStyle, right, rightColor, true); + + } + + private void paintBorderLine(Graphics g, int x1, int y1, int x2, int y2, + int style, int width, Color color, + boolean vertical) + { + switch (style) + { + case STYLE_DOTTED: + paintDottedLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_DASHED: + paintDashedLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_SOLID: + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_DOUBLE: + paintDoubleLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_GROOVE: + paintGrooveLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_RIDGE: + paintRidgeLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_OUTSET: + paintOutsetLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_INSET: + paintInsetLine(g, x1, y1, x2, y2, width, color, vertical); + break; + case STYLE_NONE: + case STYLE_HIDDEN: + default: + // Nothing to do in these cases. + } + } + + private void paintDottedLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintDashedLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintSolidLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + int x = Math.min(x1, x2); + int y = Math.min(y1, y1); + int w = Math.abs(x2 - x1); + int h = Math.abs(y2 - y1); + if (vertical) + { + w = width; + x -= width / 2; + } + else + { + h = width; + y -= width / 2; + } + g.setColor(color); + g.fillRect(x, y, w, h); + } + + private void paintDoubleLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintGrooveLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintRidgeLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintOutsetLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + + private void paintInsetLine(Graphics g, int x1, int y1, int x2, int y2, + int width, Color color, boolean vertical) + { + // FIXME: Implement this. + paintSolidLine(g, x1, y1, x2, y2, width, color, vertical); + } + +} diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index 2e2eb3abc..26e3fb4bc 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -39,10 +39,10 @@ exception statement from your version. */ package javax.swing.text.html; import gnu.classpath.NotImplementedException; -import gnu.javax.swing.text.html.parser.htmlAttributeSet; import java.io.IOException; import java.io.StringReader; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -570,6 +570,16 @@ public class HTMLDocument extends DefaultStyledDocument */ boolean inPreTag = false; + /** + * True when we are inside a paragraph (P, H1-H6, P-IMPLIED). + */ + boolean inParagraph = false; + + /** + * True when we are currently inside an implied paragraph. + */ + boolean inImpliedParagraph = false; + /** * This is true when we are inside a style tag. This will add text * content inside this style tag beeing parsed as CSS. @@ -600,12 +610,6 @@ public class HTMLDocument extends DefaultStyledDocument */ Document textAreaDocument; - void print (String line) - { - if (debug) - System.out.println (line); - } - public class TagAction { /** @@ -813,6 +817,7 @@ public class HTMLDocument extends DefaultStyledDocument public void start(HTML.Tag t, MutableAttributeSet a) { blockOpen(t, a); + inParagraph = true; } /** @@ -822,6 +827,7 @@ public class HTMLDocument extends DefaultStyledDocument public void end(HTML.Tag t) { blockClose(t); + inParagraph = false; } } @@ -882,7 +888,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("AreaAction.start not implemented"); } /** @@ -893,7 +898,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("AreaAction.end not implemented"); } } @@ -942,7 +946,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("BaseAction.start not implemented"); } /** @@ -953,7 +956,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("BaseAction.end not implemented"); } } @@ -967,7 +969,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("HeadAction.start not implemented: "+t); super.start(t, a); } @@ -992,29 +993,71 @@ public class HTMLDocument extends DefaultStyledDocument } } - class LinkAction extends TagAction + class LinkAction extends HiddenAction { /** * This method is called when a start tag is seen for one of the types * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) - throws NotImplementedException { - // FIXME: Implement. - print ("LinkAction.start not implemented"); + super.start(t, a); + String type = (String) a.getAttribute(HTML.Attribute.TYPE); + if (type == null) + type = "text/css"; + if (type.equals("text/css")) + { + String rel = (String) a.getAttribute(HTML.Attribute.REL); + String media = (String) a.getAttribute(HTML.Attribute.MEDIA); + String title = (String) a.getAttribute(HTML.Attribute.TITLE); + if (media == null) + media = "all"; + else + media = media.toLowerCase(); + if (rel != null) + { + rel = rel.toLowerCase(); + if ((media.indexOf("all") != -1 + || media.indexOf("screen") != -1) + && (rel.equals("stylesheet"))) + { + String href = (String) a.getAttribute(HTML.Attribute.HREF); + URL url = null; + try + { + url = new URL(baseURL, href); + } + catch (MalformedURLException ex) + { + try + { + url = new URL(href); + } + catch (MalformedURLException ex2) + { + url = null; + } + } + if (url != null) + { + try + { + getStyleSheet().importStyleSheet(url); + } + catch (Exception ex) + { + // Don't let exceptions and runtime exceptions + // in CSS parsing disprupt the HTML parsing + // process. But inform the user/developer + // on the console about it. + ex.printStackTrace(); + } + } + } + } + } } - /** - * Called when an end tag is seen for one of the types of tags associated - * with this Action. - */ - public void end(HTML.Tag t) - throws NotImplementedException - { - // FIXME: Implement. - print ("LinkAction.end not implemented"); - } } class MapAction extends TagAction @@ -1027,7 +1070,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MapAction.start not implemented"); } /** @@ -1038,7 +1080,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MapAction.end not implemented"); } } @@ -1052,7 +1093,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MetaAction.start not implemented"); } /** @@ -1063,7 +1103,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("MetaAction.end not implemented"); } } @@ -1098,7 +1137,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("TitleAction.start not implemented"); } /** @@ -1109,7 +1147,6 @@ public class HTMLDocument extends DefaultStyledDocument throws NotImplementedException { // FIXME: Implement. - print ("TitleAction.end not implemented"); } } @@ -1121,9 +1158,6 @@ public class HTMLDocument extends DefaultStyledDocument public HTMLReader(int offset, int popDepth, int pushDepth, HTML.Tag insertTag) { - print ("HTMLReader created with pop: "+popDepth - + " push: "+pushDepth + " offset: "+offset - + " tag: "+insertTag); this.insertTag = insertTag; this.offset = offset; this.popDepth = popDepth; @@ -1351,8 +1385,7 @@ public class HTMLDocument extends DefaultStyledDocument TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT); if (action != null) { - action.start(HTML.Tag.COMMENT, - htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET); + action.start(HTML.Tag.COMMENT, new SimpleAttributeSet()); action.end(HTML.Tag.COMMENT); } } @@ -1414,7 +1447,6 @@ public class HTMLDocument extends DefaultStyledDocument public void handleEndOfLineString(String eol) { // FIXME: Implement. - print ("HTMLReader.handleEndOfLineString not implemented yet"); } /** @@ -1475,7 +1507,9 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void blockOpen(HTML.Tag t, MutableAttributeSet attr) { - printBuffer(); + if (inImpliedParagraph) + blockClose(HTML.Tag.IMPLIED); + DefaultStyledDocument.ElementSpec element; parseStack.push(t); @@ -1485,7 +1519,6 @@ public class HTMLDocument extends DefaultStyledDocument element = new DefaultStyledDocument.ElementSpec(copy, DefaultStyledDocument.ElementSpec.StartTagType); parseBuffer.addElement(element); - printBuffer(); } /** @@ -1496,9 +1529,16 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void blockClose(HTML.Tag t) { - printBuffer(); DefaultStyledDocument.ElementSpec element; + if (inImpliedParagraph) + { + inImpliedParagraph = false; + inParagraph = false; + if (t != HTML.Tag.IMPLIED) + blockClose(HTML.Tag.IMPLIED); + } + // If the previous tag is a start tag then we insert a synthetic // content tag. DefaultStyledDocument.ElementSpec prev; @@ -1519,7 +1559,6 @@ public class HTMLDocument extends DefaultStyledDocument element = new DefaultStyledDocument.ElementSpec(null, DefaultStyledDocument.ElementSpec.EndTagType); parseBuffer.addElement(element); - printBuffer(); if (parseStack.size() > 0) parseStack.pop(); } @@ -1550,6 +1589,13 @@ public class HTMLDocument extends DefaultStyledDocument protected void addContent(char[] data, int offs, int length, boolean generateImpliedPIfNecessary) { + if (generateImpliedPIfNecessary && (! inParagraph) && (! inPreTag)) + { + blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); + inParagraph = true; + inImpliedParagraph = true; + } + AbstractDocument.AttributeContext ctx = getAttributeContext(); DefaultStyledDocument.ElementSpec element; AttributeSet attributes = null; @@ -1566,10 +1612,8 @@ public class HTMLDocument extends DefaultStyledDocument DefaultStyledDocument.ElementSpec.ContentType, data, offs, length); - printBuffer(); // Add the element to the buffer parseBuffer.addElement(element); - printBuffer(); if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold()) { @@ -1592,29 +1636,25 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a) { + if (t != HTML.Tag.FRAME && ! inParagraph && ! inImpliedParagraph) + { + blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); + inParagraph = true; + inImpliedParagraph = true; + } + a.addAttribute(StyleConstants.NameAttribute, t); - // Migrate from the rather htmlAttributeSet to the faster, lighter and - // unchangeable alternative implementation. - AttributeSet copy = a.copyAttributes(); - // The two spaces are required because some special elements like HR // must be broken. At least two characters are needed to break into the // two parts. DefaultStyledDocument.ElementSpec spec = - new DefaultStyledDocument.ElementSpec(copy, + new DefaultStyledDocument.ElementSpec(a.copyAttributes(), DefaultStyledDocument.ElementSpec.ContentType, new char[] {' ', ' '}, 0, 2 ); parseBuffer.add(spec); } - void printBuffer() - { - print ("\n*********BUFFER**********"); - for (int i = 0; i < parseBuffer.size(); i ++) - print (" "+parseBuffer.get(i)); - print ("***************************"); - } } /** diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java index c541a4d34..85d5221d3 100644 --- a/javax/swing/text/html/HTMLEditorKit.java +++ b/javax/swing/text/html/HTMLEditorKit.java @@ -82,7 +82,7 @@ import javax.swing.text.html.parser.ParserDelegator; /* Move these imports here after javax.swing.text.html to make it compile with jikes. */ import gnu.javax.swing.text.html.parser.GnuParserDelegator; -import gnu.javax.swing.text.html.parser.HTML_401Swing; +import gnu.javax.swing.text.html.parser.HTML_401F; /** * @author Lillian Angel (langel at redhat dot com) @@ -646,15 +646,12 @@ public class HTMLEditorKit else if (tag.equals(HTML.Tag.IMG)) view = new ImageView(element); - // FIXME: Uncomment when the views have been implemented else if (tag.equals(HTML.Tag.CONTENT)) view = new InlineView(element); else if (tag == HTML.Tag.HEAD) view = new NullView(element); else if (tag.equals(HTML.Tag.TABLE)) view = new javax.swing.text.html.TableView(element); - else if (tag.equals(HTML.Tag.TD)) - view = new ParagraphView(element); else if (tag.equals(HTML.Tag.HR)) view = new HRuleView(element); else if (tag.equals(HTML.Tag.BR)) @@ -663,10 +660,11 @@ public class HTMLEditorKit || tag.equals(HTML.Tag.TEXTAREA)) view = new FormView(element); - /* else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) view = new ListView(element); + // FIXME: Uncomment when the views have been implemented + /* else if (tag.equals(HTML.Tag.OBJECT)) view = new ObjectView(element); else if (tag.equals(HTML.Tag.FRAMESET)) @@ -973,7 +971,7 @@ public class HTMLEditorKit { if (parser == null) { - parser = new GnuParserDelegator(HTML_401Swing.getInstance()); + parser = new GnuParserDelegator(HTML_401F.getInstance()); } return parser; } diff --git a/javax/swing/text/html/HTMLWriter.java b/javax/swing/text/html/HTMLWriter.java index 16e9a7163..44119c732 100644 --- a/javax/swing/text/html/HTMLWriter.java +++ b/javax/swing/text/html/HTMLWriter.java @@ -608,28 +608,8 @@ public class HTMLWriter closeOutUnwantedEmbeddedTags(attrSet); - // NOTE: 20061030 - fchoong - GNU CP uses a different implimentation of - // the IMPLIED tag. - boolean fg_gnu_cp_implied_tag = false; - - if (matchNameAttribute(attrSet, HTML.Tag.P)) - { - //writeAllAttributes(attrSet); - - Enumeration attrNameEnum = attrSet.getAttributeNames(); - - while (attrNameEnum.hasMoreElements()) - { - Object key = attrNameEnum.nextElement(); - Object value = attrSet.getAttribute(key); - - if (key.equals("_implied_") && value.toString().equals("true")) - fg_gnu_cp_implied_tag = true; - } // while(attrNameEnum.hasMoreElements()) - } // if(matchNameAttribute(attrSet, HTML.Tag.P)) - // handle the tag - if (synthesizedElement(paramElem) || fg_gnu_cp_implied_tag) + if (synthesizedElement(paramElem)) { if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) { @@ -640,8 +620,7 @@ public class HTMLWriter { comment(currElem); } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) - else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED) - || fg_gnu_cp_implied_tag) // NOTE: GNU CP specific + else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) { int child_elem_count = currElem.getElementCount(); @@ -782,28 +761,8 @@ public class HTMLWriter if (fg_is_fragment_parent_elem || (fg_pass_start_elem && fg_pass_end_elem == false) || fg_is_start_and_end_elem) { - // NOTE: 20061030 - fchoong - GNU CP uses a different implimentation of - // the IMPLIED tag. - boolean fg_gnu_cp_implied_tag = false; - - if (matchNameAttribute(attrSet, HTML.Tag.P)) - { - //writeAllAttributes(attrSet); - - Enumeration attrNameEnum = attrSet.getAttributeNames(); - - while (attrNameEnum.hasMoreElements()) - { - Object key = attrNameEnum.nextElement(); - Object value = attrSet.getAttribute(key); - - if (key.equals("_implied_") && value.toString().equals("true")) - fg_gnu_cp_implied_tag = true; - } // while(attrNameEnum.hasMoreElements()) - } // if(matchNameAttribute(attrSet, HTML.Tag.P)) - // handle the tag - if (synthesizedElement(paramElem) || fg_gnu_cp_implied_tag) + if (synthesizedElement(paramElem)) { if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) { @@ -862,8 +821,7 @@ public class HTMLWriter { comment(currElem); } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) - else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED) - || fg_gnu_cp_implied_tag) // NOTE: GNU CP specific + else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) { int child_elem_count = currElem.getElementCount(); diff --git a/javax/swing/text/html/InlineView.java b/javax/swing/text/html/InlineView.java index 31eaa129c..6b134ae39 100644 --- a/javax/swing/text/html/InlineView.java +++ b/javax/swing/text/html/InlineView.java @@ -38,13 +38,17 @@ exception statement from your version. */ package javax.swing.text.html; +import java.awt.FontMetrics; import java.awt.Shape; +import java.text.BreakIterator; import javax.swing.event.DocumentEvent; import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.LabelView; +import javax.swing.text.Segment; import javax.swing.text.View; import javax.swing.text.ViewFactory; @@ -64,6 +68,18 @@ public class InlineView */ private AttributeSet attributes; + /** + * The span of the longest word in this view. + * + * @see #getLongestWord() + */ + private float longestWord; + + /** + * Indicates if we may wrap or not. + */ + private boolean nowrap; + /** * Creates a new InlineView that renders the specified element. * @@ -144,8 +160,13 @@ public class InlineView public int getBreakWeight(int axis, float pos, float len) { - // FIXME: Implement this. - return super.getBreakWeight(axis, pos, len); + int weight; + if (nowrap) { if (getText(getStartOffset(), getEndOffset()).toString().contains("Web")) + System.err.println("Web NOWRAP"); + weight = BadBreakWeight;} + else + weight = super.getBreakWeight(axis, pos, len); + return weight; } public View breakView(int axis, int offset, float pos, float len) @@ -190,7 +211,12 @@ public class InlineView b = true; setSuperscript(b); - // TODO: Handle white-space: nowrap property. + // Fetch nowrap setting. + o = atts.getAttribute(CSS.Attribute.WHITE_SPACE); + if (o != null && o.equals("nowrap")) + nowrap = true; + else + nowrap = false; } /** @@ -207,4 +233,74 @@ public class InlineView styleSheet = ((HTMLDocument) doc).getStyleSheet(); return styleSheet; } + + /** + * Returns the minimum span for the specified axis. This returns the + * width of the longest word for the X axis and the super behaviour for + * the Y axis. This is a slight deviation from the reference implementation. + * IMO this should improve rendering behaviour so that an InlineView never + * gets smaller than the longest word in it. + */ + public float getMinimumSpan(int axis) + { + float min = super.getMinimumSpan(axis); + if (axis == X_AXIS) + min = Math.max(getLongestWord(), min); + return min; + } + + /** + * Returns the span of the longest word in this view. + * + * @return the span of the longest word in this view + */ + private float getLongestWord() + { + if (longestWord == -1) + longestWord = calculateLongestWord(); + return longestWord; + } + + /** + * Calculates the span of the longest word in this view. + * + * @return the span of the longest word in this view + */ + private float calculateLongestWord() + { + float span = 0; + try + { + Document doc = getDocument(); + int p0 = getStartOffset(); + int p1 = getEndOffset(); + Segment s = new Segment(); + doc.getText(p0, p1 - p0, s); + BreakIterator iter = BreakIterator.getWordInstance(); + iter.setText(s); + int wordStart = p0; + int wordEnd = p0; + int start = iter.first(); + for (int end = iter.next(); end != BreakIterator.DONE; + start = end, end = iter.next()) + { + if ((end - start) > (wordEnd - wordStart)) + { + wordStart = start; + wordEnd = end; + } + } + if (wordEnd - wordStart > 0) + { + FontMetrics fm = getFontMetrics(); + int offset = s.offset + wordStart - s.getBeginIndex(); + span = fm.charsWidth(s.array, offset, wordEnd - wordStart); + } + } + catch (BadLocationException ex) + { + // Return 0. + } + return span; + } } diff --git a/javax/swing/text/html/ListView.java b/javax/swing/text/html/ListView.java index c07d3598c..3e809bbd2 100644 --- a/javax/swing/text/html/ListView.java +++ b/javax/swing/text/html/ListView.java @@ -94,9 +94,6 @@ public class ListView public void paint(Graphics g, Shape allocation) { super.paint(g, allocation); - // FIXME: Why is this overridden? I think that painting would be done - // by the superclass and the stylesheet... Maybe find out when this - // stuff is implemented properly. } /** diff --git a/javax/swing/text/html/ParagraphView.java b/javax/swing/text/html/ParagraphView.java index 951f70b60..e3f2817be 100644 --- a/javax/swing/text/html/ParagraphView.java +++ b/javax/swing/text/html/ParagraphView.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.Length; + import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; @@ -70,6 +72,16 @@ public class ParagraphView */ private StyleSheet.BoxPainter painter; + /** + * The width as specified in the stylesheet or null if not specified. + */ + private Length cssWidth; + + /** + * The height as specified in the stylesheet or null if not specified. + */ + private Length cssHeight; + /** * Creates a new ParagraphView for the specified element. * @@ -116,29 +128,34 @@ public class ParagraphView super.setPropertiesFromAttributes(); // Fetch CSS attributes. - AttributeSet atts = getAttributes(); - Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN); - if (o != null) + attributes = getAttributes(); + if (attributes != null) { - String align = o.toString(); - if (align.equals("left")) - setJustification(StyleConstants.ALIGN_LEFT); - else if (align.equals("right")) - setJustification(StyleConstants.ALIGN_RIGHT); - else if (align.equals("center")) - setJustification(StyleConstants.ALIGN_CENTER); - else if (align.equals("justify")) - setJustification(StyleConstants.ALIGN_JUSTIFIED); - } + super.setPropertiesFromAttributes(); + Object o = attributes.getAttribute(CSS.Attribute.TEXT_ALIGN); + if (o != null) + { + String align = o.toString(); + if (align.equals("left")) + setJustification(StyleConstants.ALIGN_LEFT); + else if (align.equals("right")) + setJustification(StyleConstants.ALIGN_RIGHT); + else if (align.equals("center")) + setJustification(StyleConstants.ALIGN_CENTER); + else if (align.equals("justify")) + setJustification(StyleConstants.ALIGN_JUSTIFIED); + } - // Fetch StyleSheet's box painter. - painter = getStyleSheet().getBoxPainter(atts); - setInsets((short) painter.getInset(TOP, this), - (short) painter.getInset(LEFT, this), - (short) painter.getInset(BOTTOM, this), - (short) painter.getInset(RIGHT, this)); + // Fetch StyleSheet's box painter. + painter = getStyleSheet().getBoxPainter(attributes); + setInsets((short) painter.getInset(TOP, this), + (short) painter.getInset(LEFT, this), + (short) painter.getInset(BOTTOM, this), + (short) painter.getInset(RIGHT, this)); - // TODO: Handle CSS width and height attributes somehow. + cssWidth = (Length) attributes.getAttribute(CSS.Attribute.WIDTH); + cssHeight = (Length) attributes.getAttribute(CSS.Attribute.WIDTH); + } } /** @@ -169,8 +186,66 @@ public class ParagraphView protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { - // FIXME: Implement the above specified behaviour. - return super.calculateMinorAxisRequirements(axis, r); + r = super.calculateMinorAxisRequirements(axis, r); + if (setCSSSpan(r, axis)) + { + // If we have set the span from CSS, then we need to adjust + // the margins. + SizeRequirements parent = super.calculateMinorAxisRequirements(axis, + null); + int margin = axis == X_AXIS ? getLeftInset() + getRightInset() + : getTopInset() + getBottomInset(); + r.minimum -= margin; + r.preferred -= margin; + r.maximum -= margin; + } + else + { + float min = 0; + int n = getLayoutViewCount(); + for (int i = 0; i < n; i++) + min = Math.max(getLayoutView(i).getMinimumSpan(axis), min); + r.minimum = (int) min; + r.preferred = Math.max(r.preferred, r.minimum); + r.maximum = Math.max(r.maximum, r.preferred); + } + return r; + } + + /** + * Sets the span on the SizeRequirements object according to the + * according CSS span value, when it is set. + * + * @param r the size requirements + * @param axis the axis + * + * @return true when the CSS span has been set, + * false otherwise + */ + private boolean setCSSSpan(SizeRequirements r, int axis) + { + boolean ret = false; + if (axis == X_AXIS) + { + if (cssWidth != null && ! cssWidth.isPercentage()) + { + r.minimum = (int) cssWidth.getValue(); + r.preferred = (int) cssWidth.getValue(); + r.maximum = (int) cssWidth.getValue(); + ret = true; + } + } + else + { + if (cssHeight != null && ! cssWidth.isPercentage()) + { + r.minimum = (int) cssHeight.getValue(); + r.preferred = (int) cssHeight.getValue(); + r.maximum = (int) cssHeight.getValue(); + ret = true; + } + } + return ret; } /** diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java index 703a3864a..add22e01c 100644 --- a/javax/swing/text/html/StyleSheet.java +++ b/javax/swing/text/html/StyleSheet.java @@ -45,21 +45,27 @@ import gnu.javax.swing.text.html.css.FontSize; import gnu.javax.swing.text.html.css.FontStyle; import gnu.javax.swing.text.html.css.FontWeight; import gnu.javax.swing.text.html.css.Length; +import gnu.javax.swing.text.html.css.Selector; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.StringTokenizer; +import javax.swing.border.Border; import javax.swing.event.ChangeListener; import javax.swing.text.AttributeSet; import javax.swing.text.Element; @@ -86,7 +92,7 @@ import javax.swing.text.View; * * The rules are stored as named styles, and other information is stored to * translate the context of an element to a rule. - * + * * @author Lillian Angel (langel@redhat.com) */ public class StyleSheet extends StyleContext @@ -101,21 +107,35 @@ public class StyleSheet extends StyleContext implements CSSParserCallback { /** - * The selector for which the rules are currently parsed. + * The current style. + */ + private CSSStyle style; + + /** + * The precedence of the stylesheet to be parsed. */ - private String[] selector; + private int precedence; + + /** + * Creates a new CSS parser. This parser parses a CSS stylesheet with + * the specified precedence. + * + * @param prec the precedence, according to the constants defined in + * CSSStyle + */ + CSSStyleSheetParserCallback(int prec) + { + precedence = prec; + } /** * Called at the beginning of a statement. * * @param sel the selector */ - public void startStatement(String sel) + public void startStatement(Selector sel) { - StringTokenizer tokens = new StringTokenizer(sel); - selector = new String[tokens.countTokens()]; - for (int index = 0; tokens.hasMoreTokens(); index++) - selector[index] = tokens.nextToken(); + style = new CSSStyle(precedence, sel); } /** @@ -123,7 +143,8 @@ public class StyleSheet extends StyleContext */ public void endStatement() { - selector = null; + css.add(style); + style = null; } /** @@ -134,23 +155,13 @@ public class StyleSheet extends StyleContext */ public void declaration(String property, String value) { - for (int i = 0; i < selector.length; i++) - { - CSSStyle style = (CSSStyle) css.get(selector[i]); - if (style == null) - { - style = new CSSStyle(); - css.put(selector[i], style); - } - CSS.Attribute cssAtt = CSS.getAttribute(property); - Object val = CSS.getValue(cssAtt, value); - if (cssAtt != null) - style.addAttribute(cssAtt, val); - // else // For debugging only. - // System.err.println("no mapping for: " + property); - } + CSS.Attribute cssAtt = CSS.getAttribute(property); + Object val = CSS.getValue(cssAtt, value); + CSS.addInternal(style, cssAtt, value); + if (cssAtt != null) + style.addAttribute(cssAtt, val); } - + } /** @@ -158,9 +169,33 @@ public class StyleSheet extends StyleContext */ private class CSSStyle extends SimpleAttributeSet - implements Style + implements Style, Comparable { + static final int PREC_UA = 400000; + static final int PREC_NORM = 300000; + static final int PREC_AUTHOR_NORMAL = 200000; + static final int PREC_AUTHOR_IMPORTANT = 100000; + static final int PREC_USER_IMPORTANT = 0; + + /** + * The priority of this style when matching CSS selectors. + */ + private int precedence; + + /** + * The selector for this rule. + * + * This is package private to avoid accessor methods. + */ + Selector selector; + + CSSStyle(int prec, Selector sel) + { + precedence = prec; + selector = sel; + } + public String getName() { // TODO: Implement this for correctness. @@ -176,6 +211,17 @@ public class StyleSheet extends StyleContext { // TODO: Implement this for correctness. } + + /** + * Sorts the rule according to the style's precedence and the + * selectors specificity. + */ + public int compareTo(Object o) + { + CSSStyle other = (CSSStyle) o; + return other.precedence + other.selector.getSpecificity() + - precedence - selector.getSpecificity(); + } } @@ -192,7 +238,7 @@ public class StyleSheet extends StyleContext * Maps element names (selectors) to AttributSet (the corresponding style * information). */ - HashMap css = new HashMap(); + ArrayList css = new ArrayList(); /** * Maps selectors to their resolved styles. @@ -371,14 +417,17 @@ public class StyleSheet extends StyleContext // the default.css. int count = tags.length; ArrayList styles = new ArrayList(); - for (int i = 0; i < count; i++) + for (Iterator i = css.iterator(); i.hasNext();) { - Style style = (Style) css.get(tags[i]); - if (style != null) + CSSStyle style = (CSSStyle) i.next(); + if (style.selector.matches(tags, classes, ids)) styles.add(style); - // FIXME: Handle ID and CLASS attributes. } + + // Sort selectors. + Collections.sort(styles); Style[] styleArray = new Style[styles.size()]; + styleArray = (Style[]) styles.toArray(styleArray); Style resolved = new MultiStyle(selector, (Style[]) styles.toArray(styleArray)); resolvedStyles.put(selector, resolved); @@ -395,9 +444,15 @@ public class StyleSheet extends StyleContext */ public Style getRule(String selector) { - // FIXME: This is a very rudimentary implementation. Should - // be extended to conform to the CSS spec. - return (Style) css.get(selector); + Selector sel = new Selector(selector); + CSSStyle best = null; + for (Iterator i = css.iterator(); i.hasNext();) + { + CSSStyle style = (CSSStyle) i.next(); + if (style.compareTo(best) < 0) + best = style; + } + return best; } /** @@ -408,7 +463,8 @@ public class StyleSheet extends StyleContext */ public void addRule(String rule) { - CSSStyleSheetParserCallback cb = new CSSStyleSheetParserCallback(); + CSSStyleSheetParserCallback cb = + new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL); // FIXME: Handle ref. StringReader in = new StringReader(rule); CSSParser parser = new CSSParser(in, cb); @@ -419,7 +475,7 @@ public class StyleSheet extends StyleContext catch (IOException ex) { // Shouldn't happen. And if, then we - assert false; + System.err.println("IOException while parsing stylesheet: " + ex.getMessage()); } } @@ -451,7 +507,8 @@ public class StyleSheet extends StyleContext public void loadRules(Reader in, URL ref) throws IOException { - CSSStyleSheetParserCallback cb = new CSSStyleSheetParserCallback(); + CSSStyleSheetParserCallback cb = + new CSSStyleSheetParserCallback(CSSStyle.PREC_UA); // FIXME: Handle ref. CSSParser parser = new CSSParser(in, cb); parser.parse(); @@ -543,13 +600,26 @@ public class StyleSheet extends StyleContext /** * Imports a style sheet from the url. The rules are directly added to the - * receiver. + * receiver. This is usually called when a tag is resolved in an + * HTML document. * - * @param url - the URL to import the StyleSheet from. + * @param url the URL to import the StyleSheet from */ public void importStyleSheet(URL url) { - // FIXME: Not implemented + try + { + InputStream in = url.openStream(); + Reader r = new BufferedReader(new InputStreamReader(in)); + CSSStyleSheetParserCallback cb = + new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL); + CSSParser parser = new CSSParser(r, cb); + parser.parse(); + } + catch (IOException ex) + { + // We can't do anything about it I guess. + } } /** @@ -585,6 +655,7 @@ public class StyleSheet extends StyleContext String value) { Object val = CSS.getValue(key, value); + CSS.addInternal(attr, key, value); attr.addAttribute(key, val); } @@ -615,11 +686,31 @@ public class StyleSheet extends StyleContext */ public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) { - // FIXME: Really convert HTML to CSS here. AttributeSet cssAttr = htmlAttrSet.copyAttributes(); - MutableAttributeSet cssStyle = addStyle(null, null); - cssStyle.addAttributes(cssAttr); - return cssStyle; + + // The HTML align attribute maps directly to the CSS text-align attribute. + Object o = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.TEXT_ALIGN, o); + + // The HTML width attribute maps directly to CSS width. + o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH, + CSS.getValue(CSS.Attribute.WIDTH, o.toString())); + + // The HTML height attribute maps directly to CSS height. + o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT, + CSS.getValue(CSS.Attribute.HEIGHT, o.toString())); + + o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP); + if (o != null) + cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap"); + + // TODO: Add more mappings. + return cssAttr; } /** @@ -802,7 +893,7 @@ public class StyleSheet extends StyleContext */ public BoxPainter getBoxPainter(AttributeSet a) { - return new BoxPainter(a); + return new BoxPainter(a, this); } /** @@ -813,7 +904,7 @@ public class StyleSheet extends StyleContext */ public ListPainter getListPainter(AttributeSet a) { - return new ListPainter(a); + return new ListPainter(a, this); } /** @@ -920,17 +1011,42 @@ public class StyleSheet extends StyleContext public static class BoxPainter extends Object implements Serializable { + /** + * The left inset. + */ private float leftInset; + + /** + * The right inset. + */ private float rightInset; + + /** + * The top inset. + */ private float topInset; + + /** + * The bottom inset. + */ private float bottomInset; + /** + * The border of the box. + */ + private Border border; + + /** + * The background color. + */ + private Color background; + /** * Package-private constructor. * * @param as - AttributeSet for painter */ - BoxPainter(AttributeSet as) + BoxPainter(AttributeSet as, StyleSheet ss) { Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT); if (l != null) @@ -944,6 +1060,13 @@ public class StyleSheet extends StyleContext l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM); if (l != null) bottomInset = l.getValue(); + + // Determine border. + border = new CSSBorder(as); + + // Determine background. + background = ss.getBackground(as); + } @@ -965,15 +1088,23 @@ public class StyleSheet extends StyleContext { case View.TOP: inset = topInset; + if (border != null) + inset += border.getBorderInsets(null).top; break; case View.BOTTOM: inset = bottomInset; + if (border != null) + inset += border.getBorderInsets(null).bottom; break; case View.LEFT: inset = leftInset; + if (border != null) + inset += border.getBorderInsets(null).left; break; case View.RIGHT: inset = rightInset; + if (border != null) + inset += border.getBorderInsets(null).right; break; default: inset = 0.0F; @@ -994,7 +1125,16 @@ public class StyleSheet extends StyleContext */ public void paint(Graphics g, float x, float y, float w, float h, View v) { - // FIXME: Not implemented. + + if (background != null) + { + g.setColor(background); + g.fillRect((int) x, (int) y, (int) w, (int) h); + } + if (border != null) + { + border.paintBorder(null, g, (int) x, (int) y, (int) w, (int) h); + } } } @@ -1005,24 +1145,36 @@ public class StyleSheet extends StyleContext * * @author Lillian Angel (langel@redhat.com) */ - public static class ListPainter extends Object implements Serializable + public static class ListPainter implements Serializable { - + /** * Attribute set for painter */ - AttributeSet as; - + private AttributeSet attributes; + + /** + * The associated style sheet. + */ + private StyleSheet styleSheet; + + /** + * The bullet type. + */ + private String type; + /** * Package-private constructor. * * @param as - AttributeSet for painter */ - ListPainter(AttributeSet as) + ListPainter(AttributeSet as, StyleSheet ss) { - this.as = as; + attributes = as; + styleSheet = ss; + type = (String) as.getAttribute(CSS.Attribute.LIST_STYLE_TYPE); } - + /** * Paints the CSS list decoration according to the attributes given. * @@ -1037,7 +1189,19 @@ public class StyleSheet extends StyleContext public void paint(Graphics g, float x, float y, float w, float h, View v, int item) { - // FIXME: Not implemented. + // FIXME: This is a very simplistic list rendering. We still need + // to implement different bullet types (see type field) and custom + // bullets via images. + View itemView = v.getView(item); + AttributeSet viewAtts = itemView.getAttributes(); + Object tag = viewAtts.getAttribute(StyleConstants.NameAttribute); + // Only paint something here when the child view is an LI tag + // and the calling view is some of the list tags then). + if (tag != null && tag == HTML.Tag.LI) + { + g.setColor(Color.BLACK); + g.fillOval((int) x - 15, (int) (h / 2 - 3 + y), 6, 6); + } } } diff --git a/javax/swing/text/html/TableView.java b/javax/swing/text/html/TableView.java index c2edc8cdd..2bd11ffcf 100644 --- a/javax/swing/text/html/TableView.java +++ b/javax/swing/text/html/TableView.java @@ -38,49 +38,185 @@ exception statement from your version. */ package javax.swing.text.html; -import javax.swing.text.Document; +import gnu.javax.swing.text.html.css.Length; + +import javax.swing.SizeRequirements; +import javax.swing.text.AttributeSet; +import javax.swing.text.BoxView; import javax.swing.text.Element; +import javax.swing.text.StyleConstants; import javax.swing.text.View; import javax.swing.text.ViewFactory; /** - * A conrete implementation of TableView that renders HTML tables. - * - * @author Roman Kennke (kennke@aicas.com) + * A view implementation that renders HTML tables. + * + * This is basically a vertical BoxView that contains the rows of the table + * and the rows are horizontal BoxViews that contain the actual columns. */ class TableView - extends javax.swing.text.TableView + extends BoxView + implements ViewFactory { + /** * Represents a single table row. */ - public class RowView extends TableRow + class RowView + extends BlockView { /** - * Creates a new instance of the RowView. + * Creates a new RowView. * - * @param el the element for which to create a row view + * @param el the element for the row view + */ + RowView(Element el) + { + super(el, X_AXIS); + } + + /** + * Overridden to make rows not resizable along the Y axis. + */ + public float getMaximumSpan(int axis) + { + float span; + if (axis == Y_AXIS) + span = super.getPreferredSpan(axis); + else + span = super.getMaximumSpan(axis); + return span; + } + + /** + * Calculates the overall size requirements for the row along the + * major axis. This will be the sum of the column requirements. + */ + protected SizeRequirements calculateMajorAxisRequirements(int axis, + SizeRequirements r) + { + if (r == null) + r = new SizeRequirements(); + r.minimum = totalColumnRequirements.minimum; + r.preferred = totalColumnRequirements.preferred; + r.maximum = totalColumnRequirements.maximum; + r.alignment = 0.0F; + return r; + } + + /** + * Lays out the columns in this row. */ - public RowView(Element el) + protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, + int spans[]) { - super(el); + int numCols = offsets.length; + int realColumn = 0; + for (int i = 0; i < numCols; i++) + { + View v = getView(i); + if (v instanceof CellView) + { + CellView cv = (CellView) v; + offsets[i] = columnOffsets[realColumn]; + spans[i] = 0; + for (int j = 0; j < cv.colSpan; j++, realColumn++) + { + spans[i] += columnSpans[realColumn]; + } + } + } } - + } + /** - * Get the associated style sheet from the document. - * - * @return the associated style sheet. + * A view that renders HTML table cells (TD and TH tags). */ - protected StyleSheet getStyleSheet() + class CellView + extends BlockView + { + + /** + * The number of columns that this view spans. + */ + int colSpan; + + /** + * Creates a new CellView for the specified element. + * + * @param el the element for which to create the colspan + */ + CellView(Element el) { - Document d = getElement().getDocument(); - if (d instanceof HTMLDocument) - return ((HTMLDocument) d).getStyleSheet(); - else - return null; - } + super(el, Y_AXIS); + } + + /** + * Overridden to fetch the columnSpan attibute. + */ + protected void setPropertiesFromAttributes() + { + super.setPropertiesFromAttributes(); + colSpan = 1; + AttributeSet atts = getAttributes(); + Object o = atts.getAttribute(HTML.Attribute.COLSPAN); + if (o != null) + { + try + { + colSpan = Integer.parseInt(o.toString()); + } + catch (NumberFormatException ex) + { + // Couldn't parse the colspan, assume 1. + colSpan = 1; + } + } + } } + + /** + * The attributes of this view. + */ + private AttributeSet attributes; + + /** + * The column requirements. + */ + private SizeRequirements[] columnRequirements; + + /** + * The overall requirements across all columns. + * + * Package private to avoid accessor methods. + */ + SizeRequirements totalColumnRequirements; + + /** + * The column layout, offsets. + * + * Package private to avoid accessor methods. + */ + int[] columnOffsets; + + /** + * The column layout, spans. + * + * Package private to avoid accessor methods. + */ + int[] columnSpans; + + /** + * The widths of the columns that have been explicitly specified. + */ + Length[] columnWidths; + + /** + * Indicates if the grid setup is ok. + */ + private boolean gridValid; + /** * Creates a new HTML table view for the specified element. * @@ -88,50 +224,424 @@ class TableView */ public TableView(Element el) { - super(el); + super(el, Y_AXIS); + totalColumnRequirements = new SizeRequirements(); } - + /** - * Get the associated style sheet from the document. - * - * @return the associated style sheet. + * Implementation of the ViewFactory interface for creating the + * child views correctly. */ - protected StyleSheet getStyleSheet() + public View create(Element elem) { - Document d = getElement().getDocument(); - if (d instanceof HTMLDocument) - return ((HTMLDocument) d).getStyleSheet(); - else - return null; - } - + View view = null; + AttributeSet atts = elem.getAttributes(); + Object name = atts.getAttribute(StyleConstants.NameAttribute); + if (name instanceof HTML.Tag) + { + HTML.Tag tag = (HTML.Tag) name; + if (tag == HTML.Tag.TR) + view = new RowView(elem); + else if (tag == HTML.Tag.TD || tag == HTML.Tag.TH) + view = new CellView(elem); + else if (tag == HTML.Tag.CAPTION) + view = new ParagraphView(elem); + } + + // If we haven't mapped the element, then fall back to the standard + // view factory. + if (view == null) + { + View parent = getParent(); + if (parent != null) + { + ViewFactory vf = parent.getViewFactory(); + if (vf != null) + view = vf.create(elem); + } + } + return view; + } + /** - * Creates a view for a table row. - * - * @param el the element that represents the table row - * @return a view for rendering the table row - * (and instance of {@link RowView}). + * Returns this object as view factory so that we get our TR, TD, TH + * and CAPTION subelements created correctly. */ - protected TableRow createTableRow(Element el) + public ViewFactory getViewFactory() { - return new RowView(el); - } - + return this; + } + /** - * Loads the children of the Table. This completely bypasses the ViewFactory - * and creates instances of TableRow instead. + * Returns the attributes of this view. This is overridden to provide + * the attributes merged with the CSS stuff. + */ + public AttributeSet getAttributes() + { + if (attributes == null) + attributes = getStyleSheet().getViewAttributes(this); + return attributes; + } + + /** + * Returns the stylesheet associated with this view. * - * @param vf ignored + * @return the stylesheet associated with this view */ - protected void loadChildren(ViewFactory vf) + private StyleSheet getStyleSheet() { - Element el = getElement(); - int numChildren = el.getElementCount(); - View[] rows = new View[numChildren]; - for (int i = 0; i < numChildren; ++i) + HTMLDocument doc = (HTMLDocument) getDocument(); + return doc.getStyleSheet(); + } + + /** + * Overridden to calculate the size requirements according to the + * columns distribution. + */ + protected SizeRequirements calculateMinorAxisRequirements(int axis, + SizeRequirements r) + { + updateGrid(); + calculateColumnRequirements(); + + // Calculate the horizontal requirements according to the superclass. + // This will return the maximum of the row's widths. + r = super.calculateMinorAxisRequirements(axis, r); + + // Try to set the CSS width if it fits. + AttributeSet atts = getAttributes(); + Length l = (Length) atts.getAttribute(CSS.Attribute.WIDTH); + if (l != null) + { + int width = (int) l.getValue(); + if (r.minimum < width) + r.minimum = width; + } + + // Apply the alignment. + Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN); + r.alignment = 0.0F; + if (o != null) { - rows[i] = createTableRow(el.getElement(i)); + String al = o.toString(); + if (al.equals("left")) + r.alignment = 0.0F; + else if (al.equals("center")) + r.alignment = 0.5F; + else if (al.equals("right")) + r.alignment = 1.0F; } - replace(0, getViewCount(), rows); + + return r; + } + + /** + * Overridden to perform the table layout before calling the super + * implementation. + */ + protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, + int[] spans) + { + updateGrid(); + layoutColumns(targetSpan); + super.layoutMinorAxis(targetSpan, axis, offsets, spans); + } + + /** + * Calculates the size requirements for the columns. + */ + private void calculateColumnRequirements() + { + int numRows = getViewCount(); + totalColumnRequirements.minimum = 0; + totalColumnRequirements.preferred = 0; + totalColumnRequirements.maximum = 0; + + // In this first pass we find out a suitable total width to fit in + // all columns of all rows. + for (int r = 0; r < numRows; r++) + { + RowView rowView = (RowView) getView(r); + int numCols = rowView.getViewCount(); + + // We collect the normal (non-relative) column requirements in the + // total variable and the relative requirements in the relTotal + // variable. In the end we create the maximum of both to get the + // real requirements. + SizeRequirements total = new SizeRequirements(); + SizeRequirements relTotal = new SizeRequirements(); + float totalPercent = 0.F; + for (int c = 0; c < numCols; ) + { + View v = rowView.getView(c); + if (v instanceof CellView) + { + CellView cellView = (CellView) v; + int colSpan = cellView.colSpan; + if (colSpan > 1) + { + int cellMin = (int) cellView.getMinimumSpan(X_AXIS); + int cellPref = (int) cellView.getPreferredSpan(X_AXIS); + int cellMax = (int) cellView.getMaximumSpan(X_AXIS); + int currentMin = 0; + int currentPref = 0; + long currentMax = 0; + for (int i = 0; i < colSpan; i++) + { + SizeRequirements req = columnRequirements[c + i]; + currentMin += req.minimum; + currentPref += req.preferred; + currentMax += req.maximum; + } + int deltaMin = cellMin - currentMin; + int deltaPref = cellPref - currentPref; + int deltaMax = (int) (cellMax - currentMax); + // Distribute delta. + for (int i = 0; i < colSpan; i++) + { + SizeRequirements req = columnRequirements[c + i]; + if (deltaMin > 0) + req.minimum += deltaMin / colSpan; + if (deltaPref > 0) + req.preferred += deltaPref / colSpan; + if (deltaMax > 0) + req.maximum += deltaMax / colSpan; + if (columnWidths[c + i] == null + || ! columnWidths[c + i].isPercentage()) + { + total.minimum += req.minimum; + total.preferred += req.preferred; + total.maximum += req.maximum; + } + else + { + relTotal.minimum = + Math.max(relTotal.minimum, + (int) (req.minimum + * columnWidths[c + i].getValue())); + relTotal.preferred = + Math.max(relTotal.preferred, + (int) (req.preferred + * columnWidths[c + i].getValue())); + relTotal.maximum = + Math.max(relTotal.maximum, + (int) (req.maximum + * columnWidths[c + i].getValue())); + totalPercent += columnWidths[c + i].getValue(); + } + } + } + else + { + // Shortcut for colSpan == 1. + SizeRequirements req = columnRequirements[c]; + req.minimum = Math.max(req.minimum, + (int) cellView.getMinimumSpan(X_AXIS)); + req.preferred = Math.max(req.preferred, + (int) cellView.getPreferredSpan(X_AXIS)); + req.maximum = Math.max(req.maximum, + (int) cellView.getMaximumSpan(X_AXIS)); + if (columnWidths[c] == null + || ! columnWidths[c].isPercentage()) + { + total.minimum += columnRequirements[c].minimum; + total.preferred += columnRequirements[c].preferred; + total.maximum += columnRequirements[c].maximum; + } + else + { + relTotal.minimum = + Math.max(relTotal.minimum, + (int) (req.minimum + / columnWidths[c].getValue())); + relTotal.preferred = + Math.max(relTotal.preferred, + (int) (req.preferred + / columnWidths[c].getValue())); + relTotal.maximum = + Math.max(relTotal.maximum, + (int) (req.maximum + / columnWidths[c].getValue())); + totalPercent += columnWidths[c].getValue(); + } + } + c += colSpan; + } + else + c++; + } + + // Update the total requirements as follows: + // 1. Multiply the absolute requirements with 1 - totalPercent. This + // gives the total requirements based on the wishes of the absolute + // cells. + // 2. Take the maximum of this value and the total relative + // requirements. Now we should have enough space for whatever cell + // in this column. + // 3. Take the maximum of this value and the previous maximum value. + total.minimum *= 1.F / (1.F - totalPercent); + total.preferred *= 1.F / (1.F - totalPercent); + total.maximum *= 1.F / (1.F - totalPercent); + + int rowTotalMin = Math.max(total.minimum, relTotal.minimum); + int rowTotalPref = Math.max(total.preferred, relTotal.preferred); + int rowTotalMax = Math.max(total.maximum, relTotal.maximum); + totalColumnRequirements.minimum = + Math.max(totalColumnRequirements.minimum, rowTotalMin); + totalColumnRequirements.preferred = + Math.max(totalColumnRequirements.preferred, rowTotalPref); + totalColumnRequirements.maximum = + Math.max(totalColumnRequirements.maximum, rowTotalMax); + } + + // Now we know what we want and can fix up the actual relative + // column requirements. + int numCols = columnRequirements.length; + for (int i = 0; i < numCols; i++) + { + if (columnWidths[i] != null) + { + columnRequirements[i].minimum = (int) + columnWidths[i].getValue(totalColumnRequirements.minimum); + columnRequirements[i].preferred = (int) + columnWidths[i].getValue(totalColumnRequirements.preferred); + columnRequirements[i].maximum = (int) + columnWidths[i].getValue(totalColumnRequirements.maximum); + } + } + } + + /** + * Lays out the columns. + * + * @param targetSpan the target span into which the table is laid out + */ + private void layoutColumns(int targetSpan) + { + // Set the spans to the preferred sizes. Determine the space + // that we have to adjust the sizes afterwards. + long sumPref = 0; + int n = columnRequirements.length; + for (int i = 0; i < n; i++) + { + SizeRequirements col = columnRequirements[i]; + if (columnWidths[i] != null) + columnSpans[i] = (int) columnWidths[i].getValue(targetSpan); + else + columnSpans[i] = col.preferred; + sumPref += columnSpans[i]; + } + + // Try to adjust the spans so that we fill the targetSpan. + long diff = targetSpan - sumPref; + float factor = 0.0F; + int[] diffs = null; + if (diff != 0) + { + long total = 0; + diffs = new int[n]; + for (int i = 0; i < n; i++) + { + // Only adjust the width if we haven't set a column width here. + if (columnWidths[i] == null) + { + SizeRequirements col = columnRequirements[i]; + int span; + if (diff < 0) + { + span = col.minimum; + diffs[i] = columnSpans[i] - span; + } + else + { + span = col.maximum; + diffs[i] = span - columnSpans[i]; + } + total += span; + } + else + total += columnSpans[i]; + } + + float maxAdjust = Math.abs(total - sumPref); + factor = diff / maxAdjust; + factor = Math.min(factor, 1.0F); + factor = Math.max(factor, -1.0F); + } + + // Actually perform adjustments. + int totalOffs = 0; + for (int i = 0; i < n; i++) + { + columnOffsets[i] = totalOffs; + if (diff != 0) + { + float adjust = factor * diffs[i]; + columnSpans[i] += Math.round(adjust); + } + // Avoid overflow here. + totalOffs = (int) Math.min((long) totalOffs + (long) columnSpans[i], + Integer.MAX_VALUE); + } + } + + /** + * Updates the arrays that contain the row and column data in response + * to a change to the table structure. + */ + private void updateGrid() + { + if (! gridValid) + { + int maxColumns = 0; + int numRows = getViewCount(); + for (int r = 0; r < numRows; r++) + { + RowView rowView = (RowView) getView(r); + int numCols = rowView.getViewCount(); + maxColumns = Math.max(numCols, maxColumns); + } + columnWidths = new Length[maxColumns]; + for (int r = 0; r < numRows; r++) + { + RowView rowView = (RowView) getView(r); + int numCols = rowView.getViewCount(); + int colIndex = 0; + for (int c = 0; c < numCols; c++) + { + View v = rowView.getView(c); + if (v instanceof CellView) + { + CellView cv = (CellView) v; + Object o = + cv.getAttributes().getAttribute(CSS.Attribute.WIDTH); + if (o != null && columnWidths[colIndex] == null + && o instanceof Length) + columnWidths[colIndex]= (Length) o; + colIndex += cv.colSpan; + } + } + } + columnRequirements = new SizeRequirements[maxColumns]; + for (int i = 0; i < maxColumns; i++) + columnRequirements[i] = new SizeRequirements(); + columnOffsets = new int[maxColumns]; + columnSpans = new int[maxColumns]; + + gridValid = true; + } + } + + /** + * Overridden to restrict the table width to the preferred size. + */ + public float getMaximumSpan(int axis) + { + float span; + if (axis == X_AXIS) + span = super.getPreferredSpan(axis); + else + span = super.getMaximumSpan(axis); + return span; } } diff --git a/javax/swing/text/html/parser/DocumentParser.java b/javax/swing/text/html/parser/DocumentParser.java index 062606d17..f717d69cb 100644 --- a/javax/swing/text/html/parser/DocumentParser.java +++ b/javax/swing/text/html/parser/DocumentParser.java @@ -38,13 +38,13 @@ exception statement from your version. */ package javax.swing.text.html.parser; -import gnu.javax.swing.text.html.parser.htmlAttributeSet; import javax.swing.text.html.parser.Parser; import java.io.IOException; import java.io.Reader; import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.html.HTMLEditorKit; /** @@ -117,7 +117,7 @@ public class DocumentParser protected final void handleStartTag(TagElement tag) { parser.handleStartTag(tag); - htmlAttributeSet attributes = gnu.getAttributes(); + SimpleAttributeSet attributes = gnu.getAttributes(); if (tag.fictional()) attributes.addAttribute(HTMLEditorKit.ParserCallback.IMPLIED, diff --git a/javax/swing/text/html/parser/ParserDelegator.java b/javax/swing/text/html/parser/ParserDelegator.java index 70636d929..cdd339b8f 100644 --- a/javax/swing/text/html/parser/ParserDelegator.java +++ b/javax/swing/text/html/parser/ParserDelegator.java @@ -38,13 +38,13 @@ exception statement from your version. */ package javax.swing.text.html.parser; import gnu.javax.swing.text.html.parser.HTML_401F; -import gnu.javax.swing.text.html.parser.htmlAttributeSet; import java.io.IOException; import java.io.Reader; import java.io.Serializable; import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit.ParserCallback; @@ -93,7 +93,7 @@ public class ParserDelegator protected final void handleStartTag(TagElement tag) { - htmlAttributeSet attributes = gnu.getAttributes(); + SimpleAttributeSet attributes = gnu.getAttributes(); if (tag.fictional()) attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE); diff --git a/native/jni/java-net/gnu_java_net_VMPlainDatagramSocketImpl.c b/native/jni/java-net/gnu_java_net_VMPlainDatagramSocketImpl.c deleted file mode 100644 index 3a451c763..000000000 --- a/native/jni/java-net/gnu_java_net_VMPlainDatagramSocketImpl.c +++ /dev/null @@ -1,406 +0,0 @@ -/* VMPlainDatagramSocketImpl.c - Native methods for PlainDatagramSocketImpl - Copyright (C) 2005, 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. */ - -/* do not move; needed here because of some macro definitions */ -#include - -#include -#include -#include - -#include -#include - -#include "cpnative.h" -#include "cpnet.h" - -#include "javanet.h" - -#include "gnu_java_net_VMPlainDatagramSocketImpl.h" - -/* - * Note that most of the functions in this module simply redirect to another - * internal function. Why? Because many of these functions are shared - * with PlainSocketImpl. - */ - -/*************************************************************************/ - -/* - * Creates a new datagram socket - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_create(JNIEnv *env, - jclass klass __attribute__ ((__unused__)) - , jobject obj) -{ - -#ifndef WITHOUT_NETWORK - _javanet_create(env, obj, 0); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * Close the socket. - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_close(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) -{ - -#ifndef WITHOUT_NETWORK - _javanet_close(env, obj, 0); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * Connects to the specified destination. - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_connect(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jobject addr, jint port) -{ -#ifndef WITHOUT_NETWORK - - _javanet_connect(env, obj, addr, port, 0); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * This method binds the specified address to the specified local port. - * Note that we have to set the local address and local port public instance - * variables. - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_bind(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint port, jobject addr) -{ - -#ifndef WITHOUT_NETWORK - _javanet_bind(env, obj, addr, port, 0); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * This method sets the specified option for a socket - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_setOption(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint option_id, - jobject val) -{ - -#ifndef WITHOUT_NETWORK - _javanet_set_option(env, obj, option_id, val); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * This method sets the specified option for a socket - */ -JNIEXPORT jobject JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_getOption(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint option_id) -{ - -#ifndef WITHOUT_NETWORK - return(_javanet_get_option(env, obj, option_id)); -#else /* not WITHOUT_NETWORK */ - return NULL; -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * Reads a buffer from a remote host - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_nativeReceive(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jbyteArray arr, - jint offset, - jint length, - jbyteArray receivedFromAddress, - jintArray receivedFromPort, - jintArray receivedLength) -{ -#ifndef WITHOUT_NETWORK - jint *port, *bytes_read; - cpnet_address *addr; - jbyte *addressBytes; - - addr = 0; - - port = (jint*)(*env)->GetIntArrayElements(env, receivedFromPort, NULL); - if (port == NULL) - { - JCL_ThrowException(env, IO_EXCEPTION, "Internal error: could not access receivedFromPort array"); - return; - } - - bytes_read = (jint*)(*env)->GetIntArrayElements(env, receivedLength, NULL); - if (bytes_read == NULL) - { - (*env)->ReleaseIntArrayElements(env, receivedFromPort, (jint*)port, 0); - JCL_ThrowException(env, IO_EXCEPTION, "Internal error: could not access receivedLength array"); - return; - } - - /* Receive the packet */ - /* should we try some sort of validation on the length? */ - (*bytes_read) = _javanet_recvfrom(env, obj, arr, offset, length, &addr); - - /* Special case the strange situation where the receiver didn't want any - bytes. */ - if (length == 0 && (*bytes_read) == -1) - *bytes_read = 0; - - if ((*bytes_read) == -1) - { - (*env)->ReleaseIntArrayElements(env, receivedFromPort, (jint*)port, 0); - (*env)->ReleaseIntArrayElements(env, receivedLength, (jint*)bytes_read, 0); - JCL_ThrowException(env, IO_EXCEPTION, "Internal error: receive"); - return; - } - - if ((*env)->ExceptionOccurred(env)) - return; - - *port = cpnet_addressGetPort (addr); - - /* Store the address */ - addressBytes = (jbyte*)(*env)->GetPrimitiveArrayCritical(env, receivedFromAddress, NULL); - cpnet_IPV4AddressToBytes (addr, addressBytes); - (*env)->ReleasePrimitiveArrayCritical(env, receivedFromAddress, addressBytes, 0); - - cpnet_freeAddress (env, addr); - - (*env)->ReleaseIntArrayElements(env, receivedFromPort, (jint*)port, 0); - (*env)->ReleaseIntArrayElements(env, receivedLength, (jint*)bytes_read, 0); - - DBG("PlainDatagramSocketImpl.receive(): Received packet\n"); - -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * Writes a buffer to the remote host - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_nativeSendTo(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jobject addr, - jint port, - jarray buf, - jint offset, - jint len) -{ -#ifndef WITHOUT_NETWORK - cpnet_address *netAddress; - - /* check if address given, tr 7.3.2005 */ - if (addr != NULL ) - { - netAddress = _javanet_get_ip_netaddr(env, addr); - if ((*env)->ExceptionOccurred(env)) - { - return; - } - if (port == 0) - { - JCL_ThrowException(env, IO_EXCEPTION, - "Invalid port number"); - cpnet_freeAddress(env, netAddress); - return; - } - cpnet_addressSetPort (netAddress, port); - } - else - { - netAddress = NULL; - } - - DBG("PlainDatagramSocketImpl.sendto(): have addr\n"); - - _javanet_sendto(env, obj, buf, offset, len, netAddress); - if (netAddress != NULL) - cpnet_freeAddress(env, netAddress); - if ((*env)->ExceptionOccurred(env)) - { - return; - } - - DBG("PlainDatagramSocketImpl.sendto(): finished\n"); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * Joins a multicast group - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_join(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jobject addr) -{ -#ifndef WITHOUT_NETWORK - cpnet_address *netAddress; - int fd; - int result; - - /* check if address given, tr 7.3.2005 */ - if (addr != NULL) - { - netAddress = _javanet_get_ip_netaddr(env, addr); - if ((*env)->ExceptionOccurred(env)) - { - JCL_ThrowException(env, IO_EXCEPTION, "Internal error"); - return; - } - } - else - { - netAddress = NULL; - } - - fd = _javanet_get_int_field(env, obj, "native_fd"); - if ((*env)->ExceptionOccurred(env)) - { - JCL_ThrowException(env, IO_EXCEPTION, "Internal error"); - return; - } - - DBG("PlainDatagramSocketImpl.join(): have native fd\n"); - - result = cpnet_addMembership (env, fd, netAddress); - if (result != CPNATIVE_OK) - { - JCL_ThrowException(env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return; - } - - DBG("PlainDatagramSocketImpl.join(): finished\n"); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - -/*************************************************************************/ - -/* - * Leaves a multicast group - */ -JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainDatagramSocketImpl_leave(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jobject addr) -{ -#ifndef WITHOUT_NETWORK - cpnet_address *netAddress; - int fd; - int result; - - /* check if address given, tr 7.3.2005 */ - if (addr != NULL) - { - netAddress = _javanet_get_ip_netaddr(env, addr); - if ((*env)->ExceptionOccurred(env)) - { - JCL_ThrowException(env, IO_EXCEPTION, "Internal error"); - return; - } - } - else - { - netAddress = 0; - } - - fd = _javanet_get_int_field(env, obj, "native_fd"); - if ((*env)->ExceptionOccurred(env)) - { - JCL_ThrowException(env, IO_EXCEPTION, "Internal error"); - return; - } - - DBG("PlainDatagramSocketImpl.leave(): have native fd\n"); - - result = cpnet_dropMembership (env, fd, netAddress); - if (result != CPNATIVE_OK) - { - JCL_ThrowException(env, IO_EXCEPTION, cpnative_getErrorString (result)); - return; - } - - DBG("PlainDatagramSocketImpl.leave(): finished\n"); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ -} - diff --git a/native/jni/java-nio/Makefile.am b/native/jni/java-nio/Makefile.am index a4b830cd4..9f2db83f2 100644 --- a/native/jni/java-nio/Makefile.am +++ b/native/jni/java-nio/Makefile.am @@ -5,7 +5,6 @@ libjavanio_la_SOURCES = gnu_java_nio_VMPipe.c \ gnu_java_nio_VMSelector.c \ gnu_java_nio_charset_iconv_IconvDecoder.c \ gnu_java_nio_charset_iconv_IconvEncoder.c \ - gnu_java_nio_channels_FileChannelImpl.c \ java_nio_MappedByteBufferImpl.c \ java_nio_VMDirectByteBuffer.c \ gnu_java_nio_EpollSelectorImpl.c \ diff --git a/native/jni/java-nio/gnu_java_nio_VMChannel.c b/native/jni/java-nio/gnu_java_nio_VMChannel.c index 33a4f66de..c49a3184f 100644 --- a/native/jni/java-nio/gnu_java_nio_VMChannel.c +++ b/native/jni/java-nio/gnu_java_nio_VMChannel.c @@ -1272,7 +1272,7 @@ Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__ { addr6 = (struct sockaddr_in6 *) sockaddr; memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16); - memcpy (nameptr, &(addr6->sin6_port), 2); + memcpy (nameptr + 16, &(addr6->sin6_port), 2); return 16; } #endif /* HAVE_INET6 */ @@ -1331,7 +1331,7 @@ Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__ { addr6 = (struct sockaddr_in6 *) sockaddr; memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16); - memcpy (nameptr, &(addr6->sin6_port), 2); + memcpy (nameptr + 16, &(addr6->sin6_port), 2); return 16; } #endif /* HAVE_INET6 */ diff --git a/native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c b/native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c deleted file mode 100644 index 644b334d3..000000000 --- a/native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c +++ /dev/null @@ -1,773 +0,0 @@ -/* gnu_java_nio_channels_FileChannelImpl.c - - Copyright (C) 2003, 2004, 2005, 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. */ - -/* do not move; needed here because of some macro definitions */ -#include - -#include -#include - -#include -#include - -#include "cpnative.h" -#include "cpio.h" - -#include "gnu_java_nio_channels_FileChannelImpl.h" - -#ifdef HAVE_FCNTL_H -#include -#endif /* HAVE_FCNTL_H */ - -#ifdef HAVE_SYS_MMAN_H -#include -#endif /* HAVE_SYS_MMAN_H */ - -#if defined(HAVE_UNISTD_H) -#include -#endif - -/* These values must be kept in sync with FileChannelImpl.java. */ -#define FILECHANNELIMPL_READ 1 -#define FILECHANNELIMPL_WRITE 2 -#define FILECHANNELIMPL_APPEND 4 - -/* These values must be kept in sync with FileChannelImpl.java. */ -/* #define FILECHANNELIMPL_FILESEEK_SET 0 */ -/* #define FILECHANNELIMPL_FILESEEK_CUR 1 */ -/* #define FILECHANNELIMPL_FILESEEK_END 2 */ - -#define FILECHANNELIMPL_FILEOPEN_FLAG_READ 1 -#define FILECHANNELIMPL_FILEOPEN_FLAG_WRITE 2 -#define FILECHANNELIMPL_FILEOPEN_FLAG_APPEND 4 -#define FILECHANNELIMPL_FILEOPEN_FLAG_EXCL 8 -#define FILECHANNELIMPL_FILEOPEN_FLAG_SYNC 16 -#define FILECHANNELIMPL_FILEOPEN_FLAG_DSYNC 32 - -#define IO_EXCEPTION "java/io/IOException" - -/* Align a value up or down to a multiple of the pagesize. */ -#define ALIGN_DOWN(p,s) ((p) - ((p) % (s))) -#define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s)))) - -/* cached fieldID of gnu.java.nio.channels.FileChannelImpl.fd */ -static jfieldID native_fd_fieldID; - -static jint -get_native_fd (JNIEnv * env, jobject obj) -{ - return (*env)->GetIntField (env, obj, native_fd_fieldID); -} - -/* - * Library initialization routine. Called as part of java.io.FileDescriptor - * static initialization. - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_init (JNIEnv * env, - jclass clazz - __attribute__ ((__unused__))) -{ - jclass clazz_fc; - jfieldID field; - - /* Initialize native_fd_fieldID so we only compute it once! */ - clazz_fc = (*env)->FindClass (env, "gnu/java/nio/channels/FileChannelImpl"); - if (!clazz_fc) - { - JCL_ThrowException (env, IO_EXCEPTION, "Internal error"); - return; - } - - field = (*env)->GetFieldID (env, clazz_fc, "fd", "I"); - if (!field) - { - JCL_ThrowException (env, IO_EXCEPTION, "Internal error"); - return; - } - - native_fd_fieldID = field; -} - -/* - * Open the specified file and return a native file descriptor - */ -JNIEXPORT jint JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_open (JNIEnv * env, - jobject obj - __attribute__ ((__unused__)), - jstring name, jint mode) -{ - const char *filename; - int flags; - int permissions; - int native_fd; - int result; - - filename = JCL_jstring_to_cstring (env, name); - if (filename == NULL) - return (-1); /* Exception will already have been thrown */ - - /* get file/permission flags for open() */ - if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_READ) - && (mode & FILECHANNELIMPL_FILEOPEN_FLAG_WRITE)) - { - /* read/write */ - flags = CPFILE_FLAG_CREATE | CPFILE_FLAG_READWRITE; - permissions = CPFILE_PERMISSION_NORMAL; - } - else if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_READ)) - { - /* read */ - flags = CPFILE_FLAG_READ; - permissions = CPFILE_PERMISSION_NORMAL; - } - else - { - /* write */ - flags = CPFILE_FLAG_CREATE | CPFILE_FLAG_WRITE; - if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_APPEND)) - { - flags |= CPFILE_FLAG_APPEND; - } - else - { - flags |= CPFILE_FLAG_TRUNCATE; - } - permissions = CPFILE_PERMISSION_NORMAL; - } - - if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_SYNC)) - { - flags |= CPFILE_FLAG_SYNC; - } - - if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_DSYNC)) - { - flags |= CPFILE_FLAG_DSYNC; - } - flags |= CPFILE_FLAG_BINARY; - - result = cpio_openFile (filename, &native_fd, flags, permissions); - if (result != CPNATIVE_OK) - { - char message[256]; /* Fixed size we don't need to malloc. */ - const char *error_string = cpnative_getErrorString (result); - - snprintf(message, 256, "%s: %s", error_string, filename); - /* We are only allowed to throw FileNotFoundException. */ - JCL_ThrowException (env, - "java/io/FileNotFoundException", - message); - JCL_free_cstring (env, name, filename); - return -1; - } - - JCL_free_cstring (env, name, filename); - return native_fd; -} - -/* - * Closes the specified file descriptor and return status code. - * Exception on error - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_implCloseChannel (JNIEnv * env, - jobject obj) -{ - int native_fd; - int result; - - native_fd = get_native_fd (env, obj); - - do - { - result = cpio_closeFile (native_fd); - if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return; - } - } - while (result != CPNATIVE_OK); -} - -/* - * Return number of bytes that can be read from the file w/o blocking. - * Exception on error - */ -JNIEXPORT jint JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_available (JNIEnv * env, - jobject obj) -{ - int native_fd; - jlong bytes_available; - int result; - - native_fd = get_native_fd (env, obj); - - do - { - result = cpio_availableBytes (native_fd, &bytes_available); - if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return 0; - } - } - while (result != CPNATIVE_OK); - - /* FIXME NYI ??? why only jint and not jlong? */ - return (jint)bytes_available; -} - -JNIEXPORT jlong JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_size (JNIEnv * env, jobject obj) -{ - int native_fd; - jlong file_size; - int result; - - native_fd = get_native_fd (env, obj); - - result = cpio_getFileSize (native_fd, &file_size); - if (result != CPNATIVE_OK) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return -1; - } - - return file_size; -} - -/* - * Return the current position of the file pointer - * Exception on error - */ -JNIEXPORT jlong JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_implPosition (JNIEnv * env, - jobject obj) -{ - int native_fd; - jlong current_offset; - int result; - - native_fd = get_native_fd (env, obj); - - result = cpio_getFilePosition (native_fd, ¤t_offset); - if (result != CPNATIVE_OK) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return -1; - } - - return current_offset; -} - -/* - * Wrapper around lseek call. Return new file position - * Exception on error - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_seek (JNIEnv * env, jobject obj, - jlong offset) -{ - int native_fd; - int result; - - native_fd = get_native_fd (env, obj); - -#if 0 - /* Should there be such an exception? All native layer macros should - be accepting 64bit-values if needed. It some target is not able - to handle such values it should simply operate with 32bit-values - and convert 64bit-values appriopated. In this case I assume - problems should not occurre: if some specific target is not able - to handle 64bit-values the system is limited to 32bit at all, thus - the application can not do a seek() or something else beyond the - 32bit limit. It this true? - */ - - /* FIXME: What do we do if offset > the max value of off_t on this 32bit - * system? How do we detect that and what do we do? */ - if (CONVERT_OFF_T_TO_JLONG (native_offset) != offset) - { - JCL_ThrowException (env, IO_EXCEPTION, - "Cannot represent position correctly on this system"); - } -#endif /* 0 */ - - result = cpio_setFilePosition (native_fd, offset); - if (result != CPNATIVE_OK) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - } -} - -/* - * Set the length of the file - * Exception on error - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_implTruncate (JNIEnv * env, - jobject obj, - jlong len) -{ - int native_fd; - int result; - - native_fd = get_native_fd (env, obj); - -#if 0 - /* Should there be such an exception? All native layer macros should - be accepting 64bit-values if needed. It some target is not able - to handle such values it should simply operate with 32bit-values - and convert 64bit-values appriopated. In this case I assume - problems should not occurre: if some specific target is not able - to handle 64bit-values the system is limited to 32bit at all, thus - the application can not do a seek() or something else beyond the - 32bit limit. It this true? - */ - - /* FIXME: What do we do if len > the max value of off_t on this 32bit - * system? How do we detect that and what do we do? */ - if (CONVERT_OFF_T_TO_JLONG (native_len) != len) - { - JCL_ThrowException (env, IO_EXCEPTION, - "Cannot represent position correctly on this system"); - return; - } -#endif /* 0 */ - - result = cpio_setFileSize (native_fd, len); - if (result != CPNATIVE_OK) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - } -} - -JNIEXPORT jobject JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_mapImpl (JNIEnv *env, jobject obj, - jchar mode, jlong position, jint size) -{ -#ifdef HAVE_MMAP - jclass MappedByteBufferImpl_class; - jmethodID MappedByteBufferImpl_init = NULL; - jobject Pointer_instance; - volatile jobject buffer; - long pagesize; - int prot, flags; - int fd; - void *p; - void *address; - - /* FIXME: should we just assume we're on an OS modern enough to - have 'sysconf'? And not check for 'getpagesize'? */ -#if defined(HAVE_GETPAGESIZE) - pagesize = getpagesize (); -#elif defined(HAVE_SYSCONF) - pagesize = sysconf (_SC_PAGESIZE); -#else - JCL_ThrowException (env, IO_EXCEPTION, - "can't determine memory page size"); - return NULL; -#endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */ - - if ((*env)->ExceptionOccurred (env)) - { - return NULL; - } - - fd = get_native_fd (env, obj); - - prot = PROT_READ; - if (mode == '+' || mode == 'c') - { - /* When writing we need to make sure the file is big enough, - otherwise the result of mmap is undefined. */ - jlong filesize; - filesize = Java_gnu_java_nio_channels_FileChannelImpl_size(env, obj); - if (filesize == -1) - return NULL; - if (position + size > filesize) - if (ftruncate(fd, position + size) == -1) - { - JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); - return NULL; - } - prot |= PROT_WRITE; - } - - flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED); - p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags, - fd, ALIGN_DOWN (position, pagesize)); - if (p == MAP_FAILED) - { - JCL_ThrowException (env, IO_EXCEPTION, cpnative_getErrorString (errno)); - return NULL; - } - - /* Unalign the mapped value back up, since we aligned offset - down to a multiple of the page size. */ - address = (void *) ((char *) p + (position % pagesize)); - - Pointer_instance = JCL_NewRawDataObject(env, address); - - MappedByteBufferImpl_class = (*env)->FindClass (env, - "java/nio/MappedByteBufferImpl"); - if (MappedByteBufferImpl_class != NULL) - { - MappedByteBufferImpl_init = - (*env)->GetMethodID (env, MappedByteBufferImpl_class, - "", "(Lgnu/classpath/Pointer;IZ)V"); - } - - if ((*env)->ExceptionOccurred (env)) - { - munmap (p, ALIGN_UP (size, pagesize)); - return NULL; - } - if (MappedByteBufferImpl_init == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "could not get MappedByteBufferImpl constructor"); - munmap (p, ALIGN_UP (size, pagesize)); - return NULL; - } - - buffer = (*env)->NewObject (env, MappedByteBufferImpl_class, - MappedByteBufferImpl_init, Pointer_instance, - (jint) size, mode == 'r'); - return buffer; -#else - (void) obj; - (void) mode; - (void) position; - (void) size; - JCL_ThrowException (env, IO_EXCEPTION, - "memory-mapped files not implemented"); - return 0; -#endif /* HAVE_MMAP */ -} - -/* - * Read a single byte from the file descriptor - * Return byte read or -1 on eof, exception on error - */ -JNIEXPORT jint JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_read__ (JNIEnv * env, jobject obj) -{ - int native_fd; - char data; - jint bytes_read; - int result; - - native_fd = get_native_fd (env, obj); - - bytes_read = 0; - do - { - result = cpio_read (native_fd, &data, 1, &bytes_read); - if ((result == CPNATIVE_OK) && (bytes_read == 0)) - return -1; - - if ((result != CPNATIVE_OK) && (result != CPNATIVE_EINTR)) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return -1; - } - } - while (result != CPNATIVE_OK); - - return ((jint) (data & 0xFF)); -} - -/* - * Reads to a byte buffer from the specified file descriptor - * Return number of bytes read or -1 on eof, exception on error - */ -JNIEXPORT jint JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_read___3BII (JNIEnv * env, - jobject obj, - jbyteArray buffer, - jint offset, - jint length) -{ - int native_fd; - jbyte *bufptr; - jint bytes_read; - jint n; - int result; - - native_fd = get_native_fd (env, obj); - - /* Must return 0 if an attempt is made to read 0 bytes. */ - if (length == 0) - return 0; - - if (offset < 0) - { - JCL_ThrowException (env, IO_EXCEPTION, "negative offset"); - return -1; - } - - bufptr = (*env)->GetByteArrayElements (env, buffer, 0); - if (!bufptr) - { - JCL_ThrowException (env, IO_EXCEPTION, "Unexpected JNI error"); - return (-1); - } - - if (length + offset > (*env)->GetArrayLength (env, buffer)) - { - JCL_ThrowException (env, IO_EXCEPTION, - "length + offset > buffer.length"); - return -1; - } - - bytes_read = 0; - do - { - result = cpio_read (native_fd, (bufptr + offset + bytes_read), - (length - bytes_read), &n); - if ((result == CPNATIVE_OK) && (n == 0)) - { - (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); - if (bytes_read == 0) - return -1; /* Signal end of file to Java */ - else - return bytes_read; - } - if ((result != CPNATIVE_OK) && (result != CPNATIVE_EINTR)) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); - return -1; - } - if (result == CPNATIVE_OK) - bytes_read += n; - } - while (bytes_read < 1); - - (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); - return bytes_read; -} - -/* - * Writes a single byte to the specified file descriptor - * Return status code, exception on error - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_write__I (JNIEnv * env, - jobject obj, jint b) -{ - int native_fd; - char native_data; - jint bytes_written; - int result; - - native_fd = get_native_fd (env, obj); - native_data = (char) (b & 0xFF); - - do - { - result = cpio_write (native_fd, &native_data, 1, &bytes_written); - if ((result != CPNATIVE_OK) && (result != CPNATIVE_EINTR)) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - return; - } - } - while (result != CPNATIVE_OK); -} - -/* - * Copies all parts of a file to disk. - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_force (JNIEnv * env, - jobject obj) -{ - int native_fd; - int result; - native_fd = get_native_fd (env, obj); - - result = cpio_fsync (native_fd); - if (result != CPNATIVE_OK) - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); -} - -/* - * Writes a byte buffer to the specified file descriptor - * Return status code, exception on error - */ -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_write___3BII (JNIEnv * env, - jobject obj, - jbyteArray buffer, - jint offset, - jint length) -{ - int native_fd; - jbyte *bufptr; - jint bytes_written; - jint n; - int result; - - native_fd = get_native_fd (env, obj); - - /* Just return if an attempt is made to write 0 bytes. */ - if (length == 0) - return; - - bufptr = (*env)->GetByteArrayElements (env, buffer, 0); - if (!bufptr) - { - JCL_ThrowException (env, IO_EXCEPTION, "Unexpected JNI error"); - return; - } - - bytes_written = 0; - while (bytes_written < length) - { - result = cpio_write (native_fd, (bufptr + offset + bytes_written), - (length - bytes_written), &n); - if ((result != CPNATIVE_OK) && (result != CPNATIVE_EINTR)) - { - JCL_ThrowException (env, IO_EXCEPTION, - cpnative_getErrorString (result)); - (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); - return; - } - if (result == CPNATIVE_OK) - bytes_written += n; - } - - (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); -} - -JNIEXPORT jboolean JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_lock (JNIEnv *env, jobject obj, - jlong position, jlong size, - jboolean shared, jboolean wait) -{ -#ifdef HAVE_FCNTL - int fd = get_native_fd (env, obj); - int cmd = wait ? F_SETLKW : F_SETLK; - struct flock flock; - int ret; - - flock.l_type = shared ? F_RDLCK : F_WRLCK; - flock.l_whence = SEEK_SET; - flock.l_start = (off_t) position; - /* Long.MAX_VALUE means lock everything possible starting at pos. */ - if (size == 9223372036854775807LL) - flock.l_len = 0; - else - flock.l_len = (off_t) size; - - ret = fcntl (fd, cmd, &flock); - /* fprintf(stderr, "fd %d, wait %d, shared %d, ret %d, position %lld, size %lld, l_start %ld, l_len %ld\n", fd, wait, shared,ret, position, size, (long) flock.l_start, (long) flock.l_len); */ - if (ret) - { - /* Linux man pages for fcntl state that errno might be either - EACCES or EAGAIN if we try F_SETLK, and another process has - an overlapping lock. We should not get an unexpected errno. */ - if (errno != EACCES && errno != EAGAIN) - { - JCL_ThrowException (env, "java/lang/InternalError", - cpnative_getErrorString (errno)); - } - return JNI_FALSE; - } - return JNI_TRUE; -#else - (void) obj; - (void) position; - (void) size; - (void) shared; - (void) wait; - JCL_ThrowException (env, "java/lang/UnsupportedOperationException", - "file locks not implemented on this platform"); - return JNI_FALSE; -#endif /* HAVE_FCNTL */ -} - -JNIEXPORT void JNICALL -Java_gnu_java_nio_channels_FileChannelImpl_unlock (JNIEnv *env, - jobject obj, - jlong position, - jlong length) -{ -#ifdef HAVE_FCNTL - int fd = get_native_fd (env, obj); - struct flock flock; - int ret; - - flock.l_type = F_UNLCK; - flock.l_whence = SEEK_SET; - flock.l_start = (off_t) position; - /* Long.MAX_VALUE means unlock everything possible starting at pos. */ - if (length == 9223372036854775807LL) - flock.l_len = 0; - else - flock.l_len = (off_t) length; - - ret = fcntl (fd, F_SETLK, &flock); - if (ret) - { - JCL_ThrowException (env, "java/lang/InternalError", - cpnative_getErrorString (errno)); - } -#else - (void) obj; - (void) position; - (void) length; - JCL_ThrowException (env, "java/lang/UnsupportedOperationException", - "file locks not implemented on this platform"); -#endif /* HAVE_FCNTL */ -} -- cgit v1.2.1