diff options
author | Thomas Fitzsimmons <fitzsim@redhat.com> | 2006-06-09 16:07:07 +0000 |
---|---|---|
committer | Thomas Fitzsimmons <fitzsim@gcc.gnu.org> | 2006-06-09 16:07:07 +0000 |
commit | 02440ca432f1aa4de7aeda563d2493a20148554b (patch) | |
tree | 0802013820f309170e8ae5584b09e9672bab2cb6 /libjava/classpath/gnu/java/awt/peer | |
parent | 6c65d7577ca4e36675571fd8bad43ef6d34e2831 (diff) | |
download | gcc-02440ca432f1aa4de7aeda563d2493a20148554b.zip gcc-02440ca432f1aa4de7aeda563d2493a20148554b.tar.gz gcc-02440ca432f1aa4de7aeda563d2493a20148554b.tar.bz2 |
String.java, [...]: Merge from GNU Classpath HEAD.
2006-06-09 Thomas Fitzsimmons <fitzsim@redhat.com>
* java/lang/String.java, classpath/native/jni/classpath/jcl.h,
classpath/native/jni/qt-peer/eventmethods.h,
classpath/native/jni/qt-peer/qtmenupeer.cpp,
classpath/native/jni/qt-peer/.cvsignore,
classpath/native/jni/gtk-peer/gdkdisplay.h,
classpath/native/jni/gtk-peer/cairographics2d.h,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_FreetypeGlyphVector.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_ComponentGraphicsCopy.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_ComponentGraphics.c,
classpath/native/jni/gtk-peer/.cvsignore,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkVolatileImage.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCanvasPeer.c,
classpath/native/jni/gtk-peer/gtkpeer.h,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoSurface.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkTextLayout.c,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFramePeer.c,
classpath/native/jni/gtk-peer/Makefile.am,
classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c,
classpath/native/jawt/Makefile.am,
classpath/native/jawt/.cvsignore,
classpath/native/target/Linux/Makefile.in,
classpath/native/plugin/gcjwebplugin.cc,
classpath/native/plugin/Makefile.am,
classpath/native/plugin/.cvsignore,
classpath/resource/Makefile.in,
classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java,
classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,
classpath/gnu/java/awt/peer/gtk/CairoSurface.java,
classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java,
classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java,
classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java,
classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java,
classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java,
classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java,
classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java,
classpath/gnu/java/awt/peer/gtk/GdkGraphics.java,
classpath/gnu/java/awt/peer/gtk/GtkToolkit.java,
classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java,
classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java,
classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java,
classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java,
classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java,
classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java,
classpath/gnu/java/awt/peer/gtk/GtkImage.java,
classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java,
classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java,
classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java,
classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java,
classpath/gnu/java/awt/peer/swing/SwingComponent.java,
classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java,
classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java,
classpath/gnu/java/awt/peer/swing/SwingFramePeer.java,
classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java,
classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java,
classpath/gnu/java/awt/print/JavaPrinterJob.java,
classpath/gnu/java/awt/print/PostScriptGraphics2D.java,
classpath/gnu/java/awt/print/SpooledDocument.java,
classpath/gnu/java/awt/print/JavaPrinterGraphics.java,
classpath/gnu/java/awt/BitwiseXORComposite.java,
classpath/gnu/java/awt/font/GNUGlyphVector.java,
classpath/gnu/java/awt/font/opentype/NameDecoder.java,
classpath/gnu/java/awt/java2d/RasterGraphics.java,
classpath/gnu/java/awt/java2d/TexturePaintContext.java,
classpath/gnu/java/awt/java2d/PolyEdge.java,
classpath/gnu/java/awt/java2d/AbstractGraphics2D.java,
classpath/gnu/java/awt/java2d/AlphaCompositeContext.java,
classpath/gnu/java/awt/java2d/ImagePaint.java,
classpath/gnu/java/awt/Buffers.java,
classpath/gnu/classpath/Configuration.java.in,
classpath/gnu/javax/swing/text/html/CombinedAttributes.java,
classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java,
classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java,
classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java,
classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java,
classpath/tools/toolwrapper.c,
classpath/tools/gnu/classpath/tools/native2ascii/Native2ASCII.java,
classpath/tools/gnu/classpath/tools/native2ascii/Messages.java,
classpath/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java,
classpath/tools/gnu/classpath/tools/getopt/OptionGroup.java,
classpath/tools/gnu/classpath/tools/getopt/OptionException.java,
classpath/tools/gnu/classpath/tools/getopt/Messages.java,
classpath/tools/gnu/classpath/tools/getopt/Option.java,
classpath/tools/gnu/classpath/tools/getopt/Parser.java,
classpath/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java,
classpath/tools/gnu/classpath/tools/jarsigner/JarSigner.java,
classpath/tools/gnu/classpath/tools/jarsigner/Main.java,
classpath/tools/gnu/classpath/tools/jarsigner/Messages.java,
classpath/tools/gnu/classpath/tools/jarsigner/package.html,
classpath/tools/gnu/classpath/tools/keytool/ListCmd.java,
classpath/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java,
classpath/tools/gnu/classpath/tools/keytool/ExportCmd.java,
classpath/tools/gnu/classpath/tools/keytool/GenKeyCmd.java,
classpath/tools/gnu/classpath/tools/keytool/Messages.java,
classpath/tools/gnu/classpath/tools/keytool/package.html,
classpath/tools/gnu/classpath/tools/keytool/Command.java,
classpath/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java,
classpath/tools/gnu/classpath/tools/keytool/Main.java,
classpath/tools/gnu/classpath/tools/keytool/DeleteCmd.java,
classpath/tools/gnu/classpath/tools/keytool/CertReqCmd.java,
classpath/tools/gnu/classpath/tools/keytool/SelfCertCmd.java,
classpath/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java,
classpath/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java,
classpath/tools/gnu/classpath/tools/keytool/ImportCmd.java,
classpath/tools/gnu/classpath/tools/keytool/PrintCertCmd.java,
classpath/tools/gnu/classpath/tools/rmi/registry/package.html,
classpath/tools/gnu/classpath/tools/rmi/RMIC.txt,
classpath/tools/gnu/classpath/tools/rmi/RMIC.java,
classpath/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java,
classpath/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java,
classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java,
classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java,
classpath/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java,
classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java,
classpath/tools/gnu/classpath/tools/appletviewer/AppletWarning.java,
classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java,
classpath/tools/gnu/classpath/tools/appletviewer/AppletTag.java,
classpath/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java,
classpath/tools/gnu/classpath/tools/appletviewer/Main.java,
classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java,
classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java,
classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java,
classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java,
classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java,
classpath/tools/gnu/classpath/tools/serialver/Messages.java,
classpath/tools/gnu/classpath/tools/serialver/SerialVer.java,
classpath/tools/gnu/classpath/tools/jar/Creator.java,
classpath/tools/gnu/classpath/tools/jar/Entry.java,
classpath/tools/gnu/classpath/tools/jar/Lister.java,
classpath/tools/gnu/classpath/tools/jar/Main.java,
classpath/tools/gnu/classpath/tools/jar/Updater.java,
classpath/tools/gnu/classpath/tools/jar/Messages.java,
classpath/tools/gnu/classpath/tools/jar/Extractor.java,
classpath/tools/gnu/classpath/tools/jar/Action.java,
classpath/tools/gnu/classpath/tools/jar/Indexer.java,
classpath/tools/gnu/classpath/tools/jar/WorkSet.java,
classpath/tools/gnu/classpath/tools/giop/GRMIC.txt,
classpath/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java,
classpath/tools/gnu/classpath/tools/giop/GRMIC.java,
classpath/tools/Makefile.am, classpath/tools/jarsigner.in,
classpath/tools/keytool.in, classpath/tools/appletviewer.in,
classpath/tools/.cvsignore, classpath/configure.ac,
classpath/javax/swing/JTabbedPane.java,
classpath/javax/swing/AbstractButton.java,
classpath/javax/swing/JViewport.java,
classpath/javax/swing/KeyboardManager.java,
classpath/javax/swing/JMenuItem.java,
classpath/javax/swing/JMenuBar.java,
classpath/javax/swing/MenuSelectionManager.java,
classpath/javax/swing/JOptionPane.java,
classpath/javax/swing/JSpinner.java,
classpath/javax/swing/JCheckBoxMenuItem.java,
classpath/javax/swing/JEditorPane.java,
classpath/javax/swing/JFormattedTextField.java,
classpath/javax/swing/JTree.java,
classpath/javax/swing/CellRendererPane.java,
classpath/javax/swing/JScrollPane.java,
classpath/javax/swing/tree/VariableHeightLayoutCache.java,
classpath/javax/swing/tree/TreeNode.java,
classpath/javax/swing/tree/FixedHeightLayoutCache.java,
classpath/javax/swing/tree/DefaultTreeCellEditor.java,
classpath/javax/swing/tree/TreePath.java,
classpath/javax/swing/tree/RowMapper.java,
classpath/javax/swing/tree/DefaultMutableTreeNode.java,
classpath/javax/swing/tree/DefaultTreeModel.java,
classpath/javax/swing/tree/AbstractLayoutCache.java,
classpath/javax/swing/tree/TreeSelectionModel.java,
classpath/javax/swing/tree/DefaultTreeSelectionModel.java,
classpath/javax/swing/tree/DefaultTreeCellRenderer.java,
classpath/javax/swing/tree/ExpandVetoException.java,
classpath/javax/swing/JList.java,
classpath/javax/swing/table/JTableHeader.java,
classpath/javax/swing/table/AbstractTableModel.java,
classpath/javax/swing/table/DefaultTableModel.java,
classpath/javax/swing/table/TableCellEditor.java,
classpath/javax/swing/table/TableCellRenderer.java,
classpath/javax/swing/ProgressMonitor.java,
classpath/javax/swing/JToolBar.java,
classpath/javax/swing/TransferHandler.java,
classpath/javax/swing/DefaultCellEditor.java,
classpath/javax/swing/DefaultButtonModel.java,
classpath/javax/swing/JLayeredPane.java,
classpath/javax/swing/text/DefaultEditorKit.java,
classpath/javax/swing/text/DefaultCaret.java,
classpath/javax/swing/text/FieldView.java,
classpath/javax/swing/text/JTextComponent.java,
classpath/javax/swing/text/TextAction.java,
classpath/javax/swing/text/StyleContext.java,
classpath/javax/swing/text/html/HTMLDocument.java,
classpath/javax/swing/text/html/MinimalHTMLWriter.java,
classpath/javax/swing/text/html/ImageView.java,
classpath/javax/swing/text/html/HTMLEditorKit.java,
classpath/javax/swing/text/AbstractWriter.java,
classpath/javax/swing/text/GapContent.java,
classpath/javax/swing/text/Utilities.java,
classpath/javax/swing/text/PlainView.java,
classpath/javax/swing/UIManager.java,
classpath/javax/swing/JSplitPane.java,
classpath/javax/swing/JComponent.java,
classpath/javax/swing/SwingUtilities.java,
classpath/javax/swing/border/AbstractBorder.java,
classpath/javax/swing/border/CompoundBorder.java,
classpath/javax/swing/border/TitledBorder.java,
classpath/javax/swing/border/MatteBorder.java,
classpath/javax/swing/border/BevelBorder.java,
classpath/javax/swing/RepaintManager.java,
classpath/javax/swing/JTable.java,
classpath/javax/swing/UIDefaults.java,
classpath/javax/swing/DefaultDesktopManager.java,
classpath/javax/swing/JMenu.java,
classpath/javax/swing/JLabel.java,
classpath/javax/swing/JSlider.java,
classpath/javax/swing/plaf/basic/BasicToolBarUI.java,
classpath/javax/swing/plaf/basic/BasicButtonUI.java,
classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java,
classpath/javax/swing/plaf/basic/BasicTextAreaUI.java,
classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java,
classpath/javax/swing/plaf/basic/BasicSpinnerUI.java,
classpath/javax/swing/plaf/basic/BasicSliderUI.java,
classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java,
classpath/javax/swing/plaf/basic/BasicComboPopup.java,
classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java,
classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java,
classpath/javax/swing/plaf/basic/BasicProgressBarUI.java,
classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java,
classpath/javax/swing/plaf/basic/BasicPanelUI.java,
classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java,
classpath/javax/swing/plaf/basic/BasicTreeUI.java,
classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java,
classpath/javax/swing/plaf/basic/BasicFileChooserUI.java,
classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java,
classpath/javax/swing/plaf/basic/BasicComboBoxUI.java,
classpath/javax/swing/plaf/basic/BasicListUI.java,
classpath/javax/swing/plaf/basic/BasicIconFactory.java,
classpath/javax/swing/plaf/basic/BasicTextUI.java,
classpath/javax/swing/plaf/basic/BasicLookAndFeel.java,
classpath/javax/swing/plaf/basic/BasicDirectoryModel.java,
classpath/javax/swing/plaf/basic/BasicRootPaneUI.java,
classpath/javax/swing/plaf/basic/BasicTableUI.java,
classpath/javax/swing/plaf/basic/SharedUIDefaults.java,
classpath/javax/swing/plaf/multi/MultiComboBoxUI.java,
classpath/javax/swing/plaf/multi/MultiListUI.java,
classpath/javax/swing/plaf/multi/MultiSplitPaneUI.java,
classpath/javax/swing/plaf/multi/MultiFileChooserUI.java,
classpath/javax/swing/plaf/multi/MultiOptionPaneUI.java,
classpath/javax/swing/plaf/multi/MultiTabbedPaneUI.java,
classpath/javax/swing/plaf/multi/MultiLookAndFeel.java,
classpath/javax/swing/plaf/metal/MetalSliderUI.java,
classpath/javax/swing/plaf/metal/MetalIconFactory.java,
classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java,
classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java,
classpath/javax/swing/plaf/metal/MetalLookAndFeel.java,
classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java,
classpath/javax/swing/plaf/metal/MetalSeparatorUI.java,
classpath/javax/swing/plaf/metal/MetalBorders.java,
classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java,
classpath/javax/swing/plaf/metal/MetalScrollBarUI.java,
classpath/javax/swing/plaf/metal/MetalRootPaneUI.java,
classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java,
classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java,
classpath/javax/swing/plaf/metal/MetalToolTipUI.java,
classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java,
classpath/javax/swing/plaf/metal/MetalFileChooserUI.java,
classpath/javax/swing/plaf/metal/MetalUtils.java,
classpath/javax/swing/plaf/metal/MetalComboBoxButton.java,
classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java,
classpath/javax/swing/plaf/metal/MetalButtonUI.java,
classpath/javax/swing/JPopupMenu.java,
classpath/javax/swing/JProgressBar.java,
classpath/javax/swing/WindowConstants.java,
classpath/javax/swing/JFrame.java,
classpath/javax/swing/JFileChooser.java,
classpath/javax/swing/JComboBox.java,
classpath/javax/swing/event/EventListenerList.java,
classpath/javax/swing/ListSelectionModel.java,
classpath/javax/swing/JScrollBar.java,
classpath/java/text/SimpleDateFormat.java,
classpath/java/text/NumberFormat.java,
classpath/java/text/class-dependencies.conf,
classpath/java/awt/image/ColorModel.java,
classpath/java/awt/image/BufferedImage.java,
classpath/java/awt/Window.java,
classpath/java/awt/ContainerOrderFocusTraversalPolicy.java,
classpath/java/awt/LightweightDispatcher.java,
classpath/java/awt/EventDispatchThread.java,
classpath/java/awt/BasicStroke.java,
classpath/java/awt/ColorPaintContext.java,
classpath/java/awt/Container.java,
classpath/java/awt/TexturePaint.java,
classpath/java/awt/Component.java, classpath/java/awt/Font.java,
classpath/java/awt/GraphicsConfiguration.java,
classpath/java/awt/DefaultKeyboardFocusManager.java,
classpath/java/awt/print/PrinterJob.java,
classpath/java/awt/im/InputContext.java,
classpath/java/awt/dnd/DragGestureRecognizer.java,
classpath/java/awt/Toolkit.java,
classpath/java/awt/font/GraphicAttribute.java,
classpath/java/awt/font/ImageGraphicAttribute.java,
classpath/java/awt/font/GlyphVector.java,
classpath/java/awt/font/GlyphMetrics.java,
classpath/java/awt/font/ShapeGraphicAttribute.java,
classpath/java/awt/Graphics2D.java,
classpath/include/gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.h,
classpath/include/gnu_java_awt_peer_gtk_ComponentGraphics.h,
classpath/include/gnu_java_awt_peer_gtk_CairoGraphics2D.h,
classpath/include/gnu_java_awt_peer_gtk_FreetypeGlyphVector.h,
classpath/include/gnu_java_awt_peer_gtk_GtkCanvasPeer.h,
classpath/include/config.h.in,
classpath/include/gnu_java_awt_peer_gtk_GdkTextLayout.h,
classpath/include/gnu_java_awt_peer_gtk_GtkComponentPeer.h,
classpath/include/gnu_java_awt_peer_gtk_GdkFontPeer.h,
classpath/include/gnu_java_awt_peer_gtk_ComponentGraphicsCopy.h,
classpath/include/gnu_java_awt_peer_gtk_GtkVolatileImage.h,
classpath/include/gnu_java_awt_peer_gtk_GtkImage.h,
classpath/include/gnu_java_awt_peer_gtk_CairoSurface.h,
classpath/include/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.h:
Merge from GNU Classpath HEAD.
From-SVN: r114510
Diffstat (limited to 'libjava/classpath/gnu/java/awt/peer')
28 files changed, 3134 insertions, 2360 deletions
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java new file mode 100644 index 0000000..d9d300d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java @@ -0,0 +1,258 @@ +/* BufferedImageGraphics.java + 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.gtk; + +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.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; +import java.util.WeakHashMap; + +/** + * Implementation of Graphics2D on a Cairo surface. + * + * Simutanously maintains a CairoSurface and updates the + * BufferedImage from that after each drawing operation. + */ +public class BufferedImageGraphics extends CairoGraphics2D +{ + /** + * the buffered Image. + */ + private BufferedImage image; + + /** + * Image size. + */ + private int imageWidth, imageHeight; + + /** + * The cairo surface that we actually draw on. + */ + CairoSurface surface; + + /** + * Cache BufferedImageGraphics surfaces. + */ + static WeakHashMap bufferedImages = new WeakHashMap(); + + /** + * Its corresponding cairo_t. + */ + private long cairo_t; + + /** + * Colormodels we recognize for fast copying. + */ + static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF); + static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, + 0xFF000000); + private boolean hasFastCM; + private boolean hasAlpha; + + + public BufferedImageGraphics(BufferedImage bi) + { + this.image = bi; + imageWidth = bi.getWidth(); + imageHeight = bi.getHeight(); + if(bi.getColorModel().equals(rgb32)) + { + hasFastCM = true; + hasAlpha = false; + } + else if(bi.getColorModel().equals(argb32)) + { + hasFastCM = true; + hasAlpha = false; + } + else + hasFastCM = false; + + // Cache surfaces. + if( bufferedImages.get( bi ) != null ) + surface = (CairoSurface)bufferedImages.get( bi ); + else + { + surface = new CairoSurface( imageWidth, imageHeight ); + bufferedImages.put(bi, surface); + } + + cairo_t = surface.newCairoContext(); + + DataBuffer db = bi.getRaster().getDataBuffer(); + int[] pixels; + // get pixels + + if(db instanceof CairoSurface) + pixels = ((CairoSurface)db).getPixels(imageWidth * imageHeight); + else + { + if( hasFastCM ) + { + pixels = ((DataBufferInt)db).getData(); + if( !hasAlpha ) + for(int i = 0; i < pixels.length; i++) + pixels[i] &= 0xFFFFFFFF; + } + else + { + pixels = CairoGraphics2D.findSimpleIntegerArray + (image.getColorModel(),image.getData()); + } + } + surface.setPixels( pixels ); + + setup( cairo_t ); + setClip(0, 0, imageWidth, imageHeight); + } + + BufferedImageGraphics(BufferedImageGraphics copyFrom) + { + surface = copyFrom.surface; + cairo_t = surface.newCairoContext(); + imageWidth = copyFrom.imageWidth; + imageHeight = copyFrom.imageHeight; + copy( copyFrom, cairo_t ); + setClip(0, 0, surface.width, surface.height); + } + + /** + * Update a rectangle of the bufferedImage. This can be improved upon a lot. + */ + private void updateBufferedImage(int x, int y, int width, int height) + { + int[] pixels = surface.getPixels(imageWidth * imageHeight); + + if( x > imageWidth || y > imageHeight ) + return; + // Clip edges. + if( x < 0 ){ width = width + x; x = 0; } + if( y < 0 ){ height = height + y; y = 0; } + if( x + width > imageWidth ) + width = imageWidth - x; + if( y + height > imageHeight ) + height = imageHeight - y; + + if( !hasFastCM ) + image.setRGB(x, y, width, height, pixels, + x + y * imageWidth, imageWidth); + else + System.arraycopy(pixels, y * imageWidth, + ((DataBufferInt)image.getRaster().getDataBuffer()). + getData(), y * imageWidth, height * imageWidth); + } + + /** + * Abstract methods. + */ + public Graphics create() + { + return new BufferedImageGraphics(this); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return null; + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0.0, 0.0, imageWidth, imageHeight); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); + updateBufferedImage(x + dx, y + dy, width, height); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + super.draw(s); + Rectangle r = s.getBounds(); + updateBufferedImage(r.x, r.y, r.width, r.height); + } + + public void fill(Shape s) + { + super.fill(s); + Rectangle r = s.getBounds(); + updateBufferedImage(r.x, r.y, r.width, r.height); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + super.drawRenderedImage(image, xform); + updateBufferedImage(0, 0, imageWidth, imageHeight); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + boolean rv = super.drawImage(img, xform, bgcolor, obs); + updateBufferedImage(0, 0, imageWidth, imageHeight); + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + super.drawGlyphVector(gv, x, y); + updateBufferedImage(0, 0, imageWidth, imageHeight); + } +} + diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java index dcebc2f..3179d33 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -1,5 +1,5 @@ -/* GdkGraphics2D.java -- - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +/* CairoGraphics2D.java -- + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -58,17 +58,21 @@ import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; +import java.awt.Polygon; import java.awt.TexturePaint; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Line2D; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; @@ -92,92 +96,141 @@ import java.util.HashMap; import java.util.Map; import java.util.Stack; -public class GdkGraphics2D extends Graphics2D +/** + * This is an abstract implementation of Graphics2D on Cairo. + * + * It should be subclassed for different Cairo contexts. + * + * Note for subclassers: Apart from the constructor (see comments below), + * The following abstract methods must be implemented: + * + * Graphics create() + * GraphicsConfiguration getDeviceConfiguration() + * copyArea(int x, int y, int width, int height, int dx, int dy) + * + * Also, dispose() must be overloaded to free any native datastructures + * used by subclass and in addition call super.dispose() to free the + * native cairographics2d structure and cairo_t. + * + * @author Sven de Marothy + */ +public abstract class CairoGraphics2D extends Graphics2D { - ////////////////////////////////////// - ////// State Management Methods ////// - ////////////////////////////////////// - static { - if (! Configuration.GTK_CAIRO_ENABLED) - throw new Error("Graphics2D not implemented. " - + "Cairo was not found or disabled at configure time"); - System.loadLibrary("gtkpeer"); - - initStaticState(); } - - static native void initStaticState(); - - private final int native_state = GtkGenericPeer.getUniqueInteger(); - // These are package-private to avoid accessor methods. + /** + * Important: This is a pointer to the native cairographics2d structure + * + * DO NOT CHANGE WITHOUT CHANGING NATIVE CODE. + */ + long nativePointer; + + // Drawing state variables + /** + * The current paint + */ Paint paint; + + /** + * The current stroke + */ Stroke stroke; - Color fg; - Color bg; + + /* + * Current foreground and background color. + */ + Color fg, bg; + + /** + * Current clip shape. + */ Shape clip; + + /** + * Current transform. + */ AffineTransform transform; - private GtkComponentPeer component; - // This is package-private to avoid an accessor method. + + /** + * Current font. + */ Font font; - private RenderingHints hints; - private BufferedImage bimage; - private boolean pixelConversionRequired; - private int[] pixelBuffer; - // This is package-private to avoid an accessor method. + + /** + * The current compositing context, if any. + */ Composite comp; - private Stack stateStack; - - private native void initStateUnlocked(GtkComponentPeer component); - private native void initState(GtkComponentPeer component); - private native void initState(int width, int height); - private native void initState(int[] pixes, int width, int height); - private native void copyState(GdkGraphics2D g); - public native void dispose(); - private native void cairoSurfaceSetFilter(int filter); - private native void cairoSurfaceSetFilterUnlocked(int filter); - native void connectSignals(GtkComponentPeer component); - public void finalize() - { - dispose(); - } + /** + * Rendering hint map. + */ + private RenderingHints hints; - public Graphics create() - { - return new GdkGraphics2D(this); - } + /** + * Some operations (drawing rather than filling) require that their + * coords be shifted to land on 0.5-pixel boundaries, in order to land on + * "middle of pixel" coordinates and light up complete pixels. + */ + private boolean shiftDrawCalls = false; + + /** + * Keep track if the first clip to be set, which is restored on setClip(null); + */ + private boolean firstClip = true; + private Shape originalClip; + + /** + * Stroke used for 3DRects + */ + private static BasicStroke draw3DRectStroke = new BasicStroke(); - public Graphics create(int x, int y, int width, int height) + static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF); + static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, + 0xFF000000); + + /** + * Constructor does nothing. + */ + public CairoGraphics2D() { - return new GdkGraphics2D(this, x, y, width, height); } - private void fail_g2d () - { - System.err.println ("Attempted to instantiate GdkGraphics2D" - + " but Graphics2D not enabled. Try again with" - + " -Dgnu.java.awt.peer.gtk.Graphics=Graphics2D"); - System.exit (1); + /** + * Sets up the default values and allocates the native cairographics2d structure + * @param cairo_t_pointer, a native pointer to a cairo_t of the context. + */ + public void setup(long cairo_t_pointer) + { + nativePointer = init(cairo_t_pointer); + setRenderingHints(new RenderingHints(getDefaultHints())); + font = new Font("SansSerif", Font.PLAIN, 12); + setColor(Color.black); + setBackground(Color.white); + setPaint(Color.black); + setStroke(new BasicStroke()); + setTransform(new AffineTransform()); } - GdkGraphics2D(GdkGraphics2D g) + /** + * Same as above, but copies the state of another CairoGraphics2D. + */ + public void copy(CairoGraphics2D g, long cairo_t_pointer) { - if (!GtkToolkit.useGraphics2D ()) - fail_g2d (); - + nativePointer = init(cairo_t_pointer); paint = g.paint; stroke = g.stroke; setRenderingHints(g.hints); + + Color foreground; if (g.fg.getAlpha() != -1) - fg = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(), + foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(), g.fg.getAlpha()); else - fg = new Color(g.fg.getRGB()); + foreground = new Color(g.fg.getRGB()); if (g.bg != null) { @@ -199,496 +252,319 @@ public class GdkGraphics2D extends Graphics2D transform = new AffineTransform(g.transform); font = g.font; - component = g.component; - copyState(g); - setColor(fg); + setColor(foreground); setBackground(bg); setPaint(paint); setStroke(stroke); setTransform(transform); - setClip(clip); - stateStack = new Stack(); } - GdkGraphics2D(GdkGraphics2D g, int x, int y, int widht, int height) - { - this(g); - translate(x, y); - clipRect(0, 0, widht, height); - } - - GdkGraphics2D(int width, int height) - { - if (!GtkToolkit.useGraphics2D ()) - fail_g2d (); - - initState(width, height); - - setColor(Color.black); - setBackground(new Color(0, 0, 0, 0)); - setPaint(getColor()); - setFont(new Font("SansSerif", Font.PLAIN, 12)); - setTransform(new AffineTransform()); - setStroke(new BasicStroke()); - setRenderingHints(getDefaultHints()); - - stateStack = new Stack(); - } - - GdkGraphics2D(GtkComponentPeer component) + /** + * Generic destructor - call the native dispose() method. + */ + public void finalize() { - if (!GtkToolkit.useGraphics2D ()) - fail_g2d (); - - this.component = component; - - if (component.isRealized()) - initComponentGraphics2D(); - else - connectSignals(component); + dispose(); } - void initComponentGraphics2D() - { - initState(component); - - setColor(component.awtComponent.getForeground()); - setBackground(component.awtComponent.getBackground()); - setPaint(getColor()); - setTransform(new AffineTransform()); - setStroke(new BasicStroke()); - setRenderingHints(getDefaultHints()); - setFont(new Font("SansSerif", Font.PLAIN, 12)); - - stateStack = new Stack(); + /** + * Disposes the native cairographics2d structure, including the + * cairo_t and any gradient stuff, if allocated. + * Subclasses should of course overload and call this if + * they have additional native structures. + */ + public void dispose() + { + disposeNative(); + nativePointer = 0; } - void initComponentGraphics2DUnlocked() - { - initStateUnlocked(component); - - setColorUnlocked(component.awtComponent.getForeground()); - setBackgroundUnlocked(component.awtComponent.getBackground()); - setPaintUnlocked(getColorUnlocked()); - setTransformUnlocked(new AffineTransform()); - setStrokeUnlocked(new BasicStroke()); - setRenderingHintsUnlocked(getDefaultHints()); - setFontUnlocked(new Font("SansSerif", Font.PLAIN, 12)); - - stateStack = new Stack(); - } + /** + * Allocate the cairographics2d structure and set the cairo_t pointer in it. + * @param pointer - a cairo_t pointer, casted to a long. + */ + private native long init(long pointer); - GdkGraphics2D(BufferedImage bimage) - { - this.bimage = bimage; - this.pixelBuffer = findSimpleIntegerArray(bimage.getColorModel(), - bimage.getRaster()); - if (this.pixelBuffer == null) - { - this.pixelBuffer = new int[bimage.getRaster().getWidth() * bimage.getRaster() - .getHeight()]; - this.pixelConversionRequired = true; - } - else - { - this.pixelConversionRequired = false; - } + /** + * These are declared abstract as there may be context-specific issues. + */ + public abstract Graphics create(); - initState(this.pixelBuffer, bimage.getWidth(), bimage.getHeight()); + public abstract GraphicsConfiguration getDeviceConfiguration(); - setColor(Color.black); - setBackground(new Color(0, 0, 0, 0)); - setPaint(getColor()); - setFont(new Font("SansSerif", Font.PLAIN, 12)); - setTransform(new AffineTransform()); - setStroke(new BasicStroke()); - setRenderingHints(getDefaultHints()); + protected abstract void copyAreaImpl(int x, int y, + int width, int height, int dx, int dy); - stateStack = new Stack(); - // draw current buffered image to the pixmap associated - // with it, if the image is not equal to our paint buffer. - if (pixelConversionRequired) - drawImage(bimage, new AffineTransform(1, 0, 0, 1, 0, 0), bg, null); - } + protected abstract Rectangle2D getRealBounds(); - //////////////////////////////////// - ////// Native Drawing Methods ////// - //////////////////////////////////// + ////// Native Methods //////////////////////////////////////////////////// - // GDK drawing methods - private native void gdkDrawDrawable(GdkGraphics2D other, int x, int y); + /** + * Dispose of allocate native resouces. + */ + public native void disposeNative(); - // drawing utility methods + /** + * Draw pixels as an RGBA int matrix + * @param w, h - width and height + * @param stride - stride of the array width + * @param i2u - affine transform array + */ private native void drawPixels(int[] pixels, int w, int h, int stride, double[] i2u); - private native void setTexturePixelsUnlocked(int[] pixels, int w, int h, int stride); - private native void setTexturePixels(int[] pixels, int w, int h, int stride); + private native void setGradient(double x1, double y1, double x2, double y2, int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2, boolean cyclic); - private native void setGradientUnlocked(double x1, double y1, double x2, double y2, - int r1, int g1, int b1, int a1, int r2, - int g2, int b2, int a2, boolean cyclic); + + private native void setTexturePixels(int[] pixels, int w, int h, int stride); - // simple passthroughs to cairo - private native void cairoSave(); - private native void cairoRestore(); + /** + * Set the current transform matrix + */ private native void cairoSetMatrix(double[] m); - private native void cairoSetMatrixUnlocked(double[] m); + + /** + * Set the compositing operator + */ private native void cairoSetOperator(int cairoOperator); + + /** + * Sets the current color in RGBA as a 0.0-1.0 double + */ private native void cairoSetRGBAColor(double red, double green, double blue, double alpha); - private native void cairoSetRGBAColorUnlocked(double red, double green, - double blue, double alpha); - private native void cairoSetFillRule(int cairoFillRule); - private native void cairoSetLineWidth(double width); - private native void cairoSetLineWidthUnlocked(double width); - private native void cairoSetLineCap(int cairoLineCap); - private native void cairoSetLineCapUnlocked(int cairoLineCap); - private native void cairoSetLineJoin(int cairoLineJoin); - private native void cairoSetLineJoinUnlocked(int cairoLineJoin); - private native void cairoSetDash(double[] dashes, int ndash, double offset); - private native void cairoSetDashUnlocked(double[] dashes, int ndash, double offset); - private native void cairoSetMiterLimit(double limit); - private native void cairoSetMiterLimitUnlocked(double limit); - private native void cairoNewPath(); - private native void cairoMoveTo(double x, double y); - private native void cairoLineTo(double x, double y); - private native void cairoCurveTo(double x1, double y1, double x2, double y2, - double x3, double y3); - private native void cairoRelMoveTo(double dx, double dy); - private native void cairoRelLineTo(double dx, double dy); - private native void cairoRelCurveTo(double dx1, double dy1, double dx2, - double dy2, double dx3, double dy3); - private native void cairoRectangle(double x, double y, double width, - double height); - private native void cairoClosePath(); - private native void cairoStroke(); - private native void cairoFill(); - private native void cairoClip(); - - ///////////////////////////////////////////// - ////// General Drawing Support Methods ////// - ///////////////////////////////////////////// - - private class DrawState - { - private Paint paint; - private Stroke stroke; - private Color fg; - private Color bg; - private Shape clip; - private AffineTransform transform; - private Font font; - private Composite comp; - - DrawState(GdkGraphics2D g) - { - this.paint = g.paint; - this.stroke = g.stroke; - this.fg = g.fg; - this.bg = g.bg; - this.clip = g.clip; - if (g.transform != null) - this.transform = (AffineTransform) g.transform.clone(); - this.font = g.font; - this.comp = g.comp; - } - - public void restore(GdkGraphics2D g) - { - g.paint = this.paint; - g.stroke = this.stroke; - g.fg = this.fg; - g.bg = this.bg; - g.clip = this.clip; - g.transform = this.transform; - g.font = this.font; - g.comp = this.comp; - } - } - - private void stateSave() - { - stateStack.push(new DrawState(this)); - cairoSave(); - } - - private void stateRestore() - { - ((DrawState) (stateStack.pop())).restore(this); - cairoRestore(); - } - - // Some operations (drawing rather than filling) require that their - // coords be shifted to land on 0.5-pixel boundaries, in order to land on - // "middle of pixel" coordinates and light up complete pixels. - private boolean shiftDrawCalls = false; - - private double shifted(double coord, boolean doShift) - { - if (doShift) - return Math.floor(coord) + 0.5; - else - return coord; - } - - private void walkPath(PathIterator p, boolean doShift) - { - double x = 0; - double y = 0; - double[] coords = new double[6]; - - cairoSetFillRule(p.getWindingRule()); - for (; ! p.isDone(); p.next()) - { - int seg = p.currentSegment(coords); - switch (seg) - { - case PathIterator.SEG_MOVETO: - x = shifted(coords[0], doShift); - y = shifted(coords[1], doShift); - cairoMoveTo(x, y); - break; - case PathIterator.SEG_LINETO: - x = shifted(coords[0], doShift); - y = shifted(coords[1], doShift); - cairoLineTo(x, y); - break; - case PathIterator.SEG_QUADTO: - // splitting a quadratic bezier into a cubic: - // see: http://pfaedit.sourceforge.net/bezier.html - double x1 = x + (2.0 / 3.0) * (shifted(coords[0], doShift) - x); - double y1 = y + (2.0 / 3.0) * (shifted(coords[1], doShift) - y); - - double x2 = x1 + (1.0 / 3.0) * (shifted(coords[2], doShift) - x); - double y2 = y1 + (1.0 / 3.0) * (shifted(coords[3], doShift) - y); - - x = shifted(coords[2], doShift); - y = shifted(coords[3], doShift); - cairoCurveTo(x1, y1, x2, y2, x, y); - break; - case PathIterator.SEG_CUBICTO: - x = shifted(coords[4], doShift); - y = shifted(coords[5], doShift); - cairoCurveTo(shifted(coords[0], doShift), - shifted(coords[1], doShift), - shifted(coords[2], doShift), - shifted(coords[3], doShift), x, y); - break; - case PathIterator.SEG_CLOSE: - cairoClosePath(); - break; - } - } - } + /** + * Sets the current winding rule in Cairo + */ + private native void cairoSetFillRule(int cairoFillRule); - private Map getDefaultHints() - { - HashMap defaultHints = new HashMap(); + /** + * Set the line style, cap, join and miter limit. + * Cap and join parameters are in the BasicStroke enumerations. + */ + private native void cairoSetLine(double width, int cap, int join, double miterLimit); - defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + /** + * Set the dash style + */ + private native void cairoSetDash(double[] dashes, int ndash, double offset); - defaultHints.put(RenderingHints.KEY_STROKE_CONTROL, - RenderingHints.VALUE_STROKE_DEFAULT); + /* + * Draws a Glyph Vector + */ + native void cairoDrawGlyphVector(GdkFontPeer font, + float x, float y, int n, + int[] codes, float[] positions); - defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS, - RenderingHints.VALUE_FRACTIONALMETRICS_OFF); - defaultHints.put(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_OFF); + private native void cairoRelCurveTo(double dx1, double dy1, double dx2, + double dy2, double dx3, double dy3); - defaultHints.put(RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_DEFAULT); + /** + * Appends a rectangle to the current path + */ + private native void cairoRectangle(double x, double y, double width, + double height); - return defaultHints; - } + /** + * New current path + */ + private native void cairoNewPath(); - public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster) - { - if (cm == null || raster == null) - return null; + /** + * Close current path + */ + private native void cairoClosePath(); - if (! cm.getColorSpace().isCS_sRGB()) - return null; + /** moveTo */ + private native void cairoMoveTo(double x, double y); - if (! (cm instanceof DirectColorModel)) - return null; + /** relative moveTo */ + private native void cairoRelMoveTo(double dx, double dy); - DirectColorModel dcm = (DirectColorModel) cm; + /** lineTo */ + private native void cairoLineTo(double x, double y); - if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00 - || dcm.getBlueMask() != 0x000000FF) - return null; + /** relative lineTo */ + private native void cairoRelLineTo(double dx, double dy); - if (! (raster instanceof WritableRaster)) - return null; + /** Cubic curve-to */ + private native void cairoCurveTo(double x1, double y1, double x2, double y2, + double x3, double y3); - if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT) - return null; + /** + * Stroke current path + */ + private native void cairoStroke(); - if (! (raster.getDataBuffer() instanceof DataBufferInt)) - return null; + /** + * Fill current path + */ + private native void cairoFill(); - DataBufferInt db = (DataBufferInt) raster.getDataBuffer(); + /** + * Clip current path + */ + private native void cairoClip(); - if (db.getNumBanks() != 1) - return null; + /** + * Save clip + */ + private native void cairoPreserveClip(); - // Finally, we have determined that this is a single bank, [A]RGB-int - // buffer in sRGB space. It's worth checking all this, because it means - // that cairo can paint directly into the data buffer, which is very - // fast compared to all the normal copying and converting. + /** + * Save clip + */ + private native void cairoResetClip(); - return db.getData(); - } + /** + * Set interpolation types + */ + private native void cairoSurfaceSetFilter(int filter); - private void updateBufferedImage() + ///////////////////////// TRANSFORMS /////////////////////////////////// + /** + * Set the current transform + */ + public void setTransform(AffineTransform tx) { - if (bimage != null && pixelConversionRequired) + transform = tx; + if (transform != null) { - int height = bimage.getHeight(); - int width = bimage.getWidth(); - int index = 0; - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) - bimage.setRGB(x, y, pixelBuffer[index++]); + double[] m = new double[6]; + transform.getMatrix(m); + cairoSetMatrix(m); } } - - private boolean drawImage(Image img, AffineTransform xform, - Color bgcolor, ImageObserver obs) + + public void transform(AffineTransform tx) { - if (img == null) - return false; - - // FIXME: I'll fix this, /Sven -// if (img instanceof GtkOffScreenImage -// && img.getGraphics() instanceof GdkGraphics2D -// && (xform == null || xform.getType() == AffineTransform.TYPE_IDENTITY -// || xform.getType() == AffineTransform.TYPE_TRANSLATION)) -// { -// // we are being asked to flush a double buffer from Gdk -// GdkGraphics2D g2 = (GdkGraphics2D) img.getGraphics(); -// gdkDrawDrawable(g2, (int) xform.getTranslateX(), -// (int) xform.getTranslateY()); - -// updateBufferedImage(); - -// return true; -// } -// else + if (transform == null) + transform = new AffineTransform(tx); + else + transform.concatenate(tx); + setTransform(transform); + if (clip != null) { - // In this case, xform is an AffineTransform that transforms bounding - // box of the specified image from image space to user space. However - // when we pass this transform to cairo, cairo will use this transform - // to map "user coordinates" to "pixel" coordinates, which is the - // other way around. Therefore to get the "user -> pixel" transform - // that cairo wants from "image -> user" transform that we currently - // have, we will need to invert the transformation matrix. - AffineTransform invertedXform = new AffineTransform(); - + // FIXME: this should actuall try to transform the shape + // rather than degrade to bounds. + Rectangle2D r = clip.getBounds2D(); + double[] coords = new double[] + { + r.getX(), r.getY(), r.getX() + r.getWidth(), + r.getY() + r.getHeight() + }; try { - invertedXform = xform.createInverse(); - if (img instanceof BufferedImage) - { - // draw an image which has actually been loaded - // into memory fully - BufferedImage b = (BufferedImage) img; - return drawRaster(b.getColorModel(), b.getTile(0, 0), - invertedXform, bgcolor); - } - else - return this.drawImage(GdkPixbufDecoder.createBufferedImage(img - .getSource()), - xform, bgcolor, obs); + tx.createInverse().transform(coords, 0, coords, 0, 2); + r.setRect(coords[0], coords[1], coords[2] - coords[0], + coords[3] - coords[1]); + clip = r; } - catch (NoninvertibleTransformException e) + catch (java.awt.geom.NoninvertibleTransformException e) { - throw new ImagingOpException("Unable to invert transform " - + xform.toString()); } } } - ////////////////////////////////////////////////// - ////// Implementation of Graphics2D Methods ////// - ////////////////////////////////////////////////// - - public void draw(Shape s) + public void rotate(double theta) { - if (stroke != null && ! (stroke instanceof BasicStroke)) - { - fill(stroke.createStrokedShape(s)); - return; - } - - cairoNewPath(); + transform(AffineTransform.getRotateInstance(theta)); + } - if (s instanceof Rectangle2D) - { - Rectangle2D r = (Rectangle2D) s; - cairoRectangle(shifted(r.getX(), shiftDrawCalls), - shifted(r.getY(), shiftDrawCalls), r.getWidth(), - r.getHeight()); - } - else - walkPath(s.getPathIterator(null), shiftDrawCalls); - cairoStroke(); + public void rotate(double theta, double x, double y) + { + transform(AffineTransform.getRotateInstance(theta, x, y)); + } - updateBufferedImage(); + public void scale(double sx, double sy) + { + transform(AffineTransform.getScaleInstance(sx, sy)); } - public void fill(Shape s) + /** + * Translate the system of the co-ordinates. As translation is a frequent + * operation, it is done in an optimised way, unlike scaling and rotating. + */ + public void translate(double tx, double ty) { - cairoNewPath(); - if (s instanceof Rectangle2D) + if (transform != null) + transform.translate(tx, ty); + else + transform = AffineTransform.getTranslateInstance(tx, ty); + + if (clip != null) { - Rectangle2D r = (Rectangle2D) s; - cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + // FIXME: this should actuall try to transform the shape + // rather than degrade to bounds. + Rectangle2D r; + + if (clip instanceof Rectangle2D) + r = (Rectangle2D) clip; + else + r = clip.getBounds2D(); + + r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(), r.getHeight()); + clip = r; } - else - walkPath(s.getPathIterator(null), false); - cairoFill(); + setTransform(transform); + } + + public void translate(int x, int y) + { + translate((double) x, (double) y); + } - updateBufferedImage(); + public void shear(double shearX, double shearY) + { + transform(AffineTransform.getShearInstance(shearX, shearY)); } + ///////////////////////// DRAWING STATE /////////////////////////////////// + public void clip(Shape s) { - // update it - if (clip == null || s == null) - clip = s; - else if (s instanceof Rectangle2D && clip instanceof Rectangle2D) - { - Rectangle2D r = (Rectangle2D) s; - Rectangle2D curr = (Rectangle2D) clip; - clip = curr.createIntersection(r); - } - else - throw new UnsupportedOperationException(); + // Do not touch clip when s == null. + if (s == null) + return; - // draw it - if (clip != null) + // If the current clip is still null, initialize it. + if (clip == null) + clip = originalClip; + + // This is so common, let's optimize this. + else if (clip instanceof Rectangle2D && s instanceof Rectangle2D) { - cairoNewPath(); - if (clip instanceof Rectangle2D) - { - Rectangle2D r = (Rectangle2D) clip; - cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); - } - else - walkPath(clip.getPathIterator(null), false); - - // cairoClosePath (); - cairoClip(); + Rectangle2D clipRect = (Rectangle2D) clip; + Rectangle2D r = (Rectangle2D) s; + Rectangle2D.intersect(clipRect, r, clipRect); + // Call setClip so that subclasses get notified. + setClip(clipRect); } + else + { + Area current; + if (clip instanceof Area) + current = (Area) clip; + else + current = new Area(clip); + + Area intersect; + if (s instanceof Area) + intersect = (Area) s; + else + intersect = new Area(s); + + current.intersect(intersect); + clip = current; + // Call setClip so that the native side gets notified. + setClip(clip); + } } public Paint getPaint() @@ -720,8 +596,8 @@ public class GdkGraphics2D extends Graphics2D int width = (int) tp.getAnchorRect().getWidth(); int height = (int) tp.getAnchorRect().getHeight(); - double scaleX = width / (double) img.getWidth(); - double scaleY = width / (double) img.getHeight(); + double scaleX = (width+1) / (double) img.getWidth(); + double scaleY = (height+1) / (double) img.getHeight(); AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); @@ -744,131 +620,6 @@ public class GdkGraphics2D extends Graphics2D throw new java.lang.UnsupportedOperationException(); } - public void setPaintUnlocked(Paint p) - { - if (paint == null) - return; - - paint = p; - if (paint instanceof Color) - { - setColorUnlocked((Color) paint); - } - else if (paint instanceof TexturePaint) - { - TexturePaint tp = (TexturePaint) paint; - BufferedImage img = tp.getImage(); - - // map the image to the anchor rectangle - int width = (int) tp.getAnchorRect().getWidth(); - int height = (int) tp.getAnchorRect().getHeight(); - - double scaleX = width / (double) img.getWidth(); - double scaleY = width / (double) img.getHeight(); - - AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); - AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); - BufferedImage texture = op.filter(img, null); - int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); - setTexturePixelsUnlocked(pixels, width, height, width); - } - else if (paint instanceof GradientPaint) - { - GradientPaint gp = (GradientPaint) paint; - Point2D p1 = gp.getPoint1(); - Point2D p2 = gp.getPoint2(); - Color c1 = gp.getColor1(); - Color c2 = gp.getColor2(); - setGradientUnlocked(p1.getX(), p1.getY(), p2.getX(), p2.getY(), c1.getRed(), - c1.getGreen(), c1.getBlue(), c1.getAlpha(), c2.getRed(), - c2.getGreen(), c2.getBlue(), c2.getAlpha(), gp.isCyclic()); - } - else - throw new java.lang.UnsupportedOperationException(); - } - - public void setTransform(AffineTransform tx) - { - transform = tx; - if (transform != null) - { - double[] m = new double[6]; - transform.getMatrix(m); - cairoSetMatrix(m); - } - } - - public void setTransformUnlocked(AffineTransform tx) - { - transform = tx; - if (transform != null) - { - double[] m = new double[6]; - transform.getMatrix(m); - cairoSetMatrixUnlocked(m); - } - } - - public void transform(AffineTransform tx) - { - if (transform == null) - transform = new AffineTransform(tx); - else - transform.concatenate(tx); - setTransform(transform); - if (clip != null) - { - // FIXME: this should actuall try to transform the shape - // rather than degrade to bounds. - Rectangle2D r = clip.getBounds2D(); - double[] coords = new double[] - { - r.getX(), r.getY(), r.getX() + r.getWidth(), - r.getY() + r.getHeight() - }; - try - { - tx.createInverse().transform(coords, 0, coords, 0, 2); - r.setRect(coords[0], coords[1], coords[2] - coords[0], - coords[3] - coords[1]); - clip = r; - } - catch (java.awt.geom.NoninvertibleTransformException e) - { - } - } - } - - public void rotate(double theta) - { - transform(AffineTransform.getRotateInstance(theta)); - } - - public void rotate(double theta, double x, double y) - { - transform(AffineTransform.getRotateInstance(theta, x, y)); - } - - public void scale(double sx, double sy) - { - transform(AffineTransform.getScaleInstance(sx, sy)); - } - - public void translate(double tx, double ty) - { - transform(AffineTransform.getTranslateInstance(tx, ty)); - } - - public void translate(int x, int y) - { - translate((double) x, (double) y); - } - - public void shear(double shearX, double shearY) - { - transform(AffineTransform.getShearInstance(shearX, shearY)); - } - public Stroke getStroke() { return stroke; @@ -880,10 +631,9 @@ public class GdkGraphics2D extends Graphics2D if (stroke instanceof BasicStroke) { BasicStroke bs = (BasicStroke) stroke; - cairoSetLineCap(bs.getEndCap()); - cairoSetLineWidth(bs.getLineWidth()); - cairoSetLineJoin(bs.getLineJoin()); - cairoSetMiterLimit(bs.getMiterLimit()); + cairoSetLine(bs.getLineWidth(), bs.getEndCap(), + bs.getLineJoin(), bs.getMiterLimit()); + float[] dashes = bs.getDashArray(); if (dashes != null) { @@ -898,42 +648,14 @@ public class GdkGraphics2D extends Graphics2D } } - public void setStrokeUnlocked(Stroke st) - { - stroke = st; - if (stroke instanceof BasicStroke) - { - BasicStroke bs = (BasicStroke) stroke; - cairoSetLineCapUnlocked(bs.getEndCap()); - cairoSetLineWidthUnlocked(bs.getLineWidth()); - cairoSetLineJoinUnlocked(bs.getLineJoin()); - cairoSetMiterLimitUnlocked(bs.getMiterLimit()); - float[] dashes = bs.getDashArray(); - if (dashes != null) - { - double[] double_dashes = new double[dashes.length]; - for (int i = 0; i < dashes.length; i++) - double_dashes[i] = dashes[i]; - cairoSetDashUnlocked(double_dashes, double_dashes.length, - (double) bs.getDashPhase()); - } - else - cairoSetDashUnlocked(new double[0], 0, 0.0); - } - } - - //////////////////////////////////////////////// - ////// Implementation of Graphics Methods ////// - //////////////////////////////////////////////// - public void setPaintMode() { - setComposite(java.awt.AlphaComposite.SrcOver); + setComposite(AlphaComposite.SrcOver); } public void setXORMode(Color c) { - setComposite(new gnu.java.awt.BitwiseXORComposite(c)); + // FIXME: implement } public void setColor(Color c) @@ -943,18 +665,17 @@ public class GdkGraphics2D extends Graphics2D fg = c; paint = c; - cairoSetRGBAColor(fg.getRed() / 255.0, fg.getGreen() / 255.0, - fg.getBlue() / 255.0, fg.getAlpha() / 255.0); + updateColor(); } - - public void setColorUnlocked(Color c) + + /** + * Set the current fg value as the cairo color. + */ + void updateColor() { - if (c == null) - c = Color.BLACK; - - fg = c; - paint = c; - cairoSetRGBAColorUnlocked(fg.getRed() / 255.0, fg.getGreen() / 255.0, + if (fg == null) + fg = Color.BLACK; + cairoSetRGBAColor(fg.getRed() / 255.0, fg.getGreen() / 255.0, fg.getBlue() / 255.0, fg.getAlpha() / 255.0); } @@ -963,11 +684,6 @@ public class GdkGraphics2D extends Graphics2D return fg; } - public Color getColorUnlocked() - { - return getColor(); - } - public void clipRect(int x, int y, int width, int height) { clip(new Rectangle(x, y, width, height)); @@ -1011,81 +727,41 @@ public class GdkGraphics2D extends Graphics2D public void setClip(int x, int y, int width, int height) { - setClip(new Rectangle2D.Double((double) x, (double) y, (double) width, - (double) height)); + if( width < 0 || height < 0 ) + return; + + setClip(new Rectangle2D.Double(x, y, width, height)); } public void setClip(Shape s) - { - clip = s; - if (clip == null) - { - // Reset clipping. - if (component != null) - { - Dimension d = component.awtComponent.getSize(); - setClip(0, 0, d.width, d.height); - } - } - else + { + // The first time the clip is set, save it as the original clip + // to reset to on s == null. We can rely on this being non-null + // because the constructor in subclasses is expected to set the + // initial clip properly. + if( firstClip ) { - cairoNewPath(); - if (s instanceof Rectangle2D) - { - Rectangle2D r = (Rectangle2D) s; - cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); - } - else - walkPath(s.getPathIterator(null), false); - - // cairoClosePath (); - cairoClip(); + originalClip = s; + firstClip = false; } - } - - private static BasicStroke draw3DRectStroke = new BasicStroke(); - - public void draw3DRect(int x, int y, int width, int height, boolean raised) - { - Stroke tmp = stroke; - setStroke(draw3DRectStroke); - super.draw3DRect(x, y, width, height, raised); - setStroke(tmp); - updateBufferedImage(); - } - - public void fill3DRect(int x, int y, int width, int height, boolean raised) - { - Stroke tmp = stroke; - setStroke(draw3DRectStroke); - super.fill3DRect(x, y, width, height, raised); - setStroke(tmp); - updateBufferedImage(); - } - public void drawRect(int x, int y, int width, int height) - { - draw(new Rectangle(x, y, width, height)); - } + if (s == null) + clip = originalClip; + else + clip = s; - public void fillRect(int x, int y, int width, int height) - { - cairoNewPath(); - cairoRectangle(x, y, width, height); - cairoFill(); - } + cairoResetClip(); - public void clearRect(int x, int y, int width, int height) - { - if (bg != null) - cairoSetRGBAColor(bg.getRed() / 255.0, bg.getGreen() / 255.0, - bg.getBlue() / 255.0, 1.0); cairoNewPath(); - cairoRectangle(x, y, width, height); - cairoFill(); - setColor(fg); - - updateBufferedImage(); + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) clip; + cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + else + walkPath(clip.getPathIterator(null), false); + + cairoClip(); } public void setBackground(Color c) @@ -1095,203 +771,232 @@ public class GdkGraphics2D extends Graphics2D bg = c; } - public void setBackgroundUnlocked(Color c) - { - setBackground(c); - } - public Color getBackground() { return bg; } - private void doPolygon(int[] xPoints, int[] yPoints, int nPoints, - boolean close, boolean fill) + /** + * Return the current composite. + */ + public Composite getComposite() { - if (nPoints < 1) - return; - GeneralPath gp = new GeneralPath(PathIterator.WIND_EVEN_ODD); - gp.moveTo((float) xPoints[0], (float) yPoints[0]); - for (int i = 1; i < nPoints; i++) - gp.lineTo((float) xPoints[i], (float) yPoints[i]); + if (comp == null) + return AlphaComposite.SrcOver; + else + return comp; + } - if (close) - gp.closePath(); + /** + * Sets the current composite context. + */ + public void setComposite(Composite comp) + { + this.comp = comp; - Shape sh = gp; - if (fill == false && stroke != null && ! (stroke instanceof BasicStroke)) + if (comp instanceof AlphaComposite) { - sh = stroke.createStrokedShape(gp); - fill = true; + AlphaComposite a = (AlphaComposite) comp; + cairoSetOperator(a.getRule()); + Color c = getColor(); + setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), + (int) (a.getAlpha() * ((float) c.getAlpha())))); } - - if (fill) - fill(sh); else - draw(sh); + { + // FIXME: implement general Composite support + throw new java.lang.UnsupportedOperationException(); + } } - public void drawLine(int x1, int y1, int x2, int y2) + ///////////////////////// DRAWING PRIMITIVES /////////////////////////////////// + + public void draw(Shape s) { - int[] xp = new int[2]; - int[] yp = new int[2]; + if (stroke != null && ! (stroke instanceof BasicStroke)) + { + fill(stroke.createStrokedShape(s)); + return; + } - xp[0] = x1; - xp[1] = x2; - yp[0] = y1; - yp[1] = y2; + cairoNewPath(); - doPolygon(xp, yp, 2, false, false); + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) s; + cairoRectangle(shifted(r.getX(), shiftDrawCalls), + shifted(r.getY(), shiftDrawCalls), r.getWidth(), + r.getHeight()); + } + else + walkPath(s.getPathIterator(null), shiftDrawCalls); + cairoStroke(); } - public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + public void fill(Shape s) { - doPolygon(xPoints, yPoints, nPoints, true, true); + cairoNewPath(); + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) s; + cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + else + walkPath(s.getPathIterator(null), false); + + cairoFill(); } - public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + /** + * Note that the rest of the drawing methods go via fill() or draw() for the drawing, + * although subclasses may with to overload these methods where context-specific + * optimizations are possible (e.g. bitmaps and fillRect(int, int, int, int) + */ + + public void clearRect(int x, int y, int width, int height) { - doPolygon(xPoints, yPoints, nPoints, true, false); + if (bg != null) + cairoSetRGBAColor(bg.getRed() / 255.0, bg.getGreen() / 255.0, + bg.getBlue() / 255.0, 1.0); + fillRect(x, y, width, height); + updateColor(); } - public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + public void draw3DRect(int x, int y, int width, int height, boolean raised) { - doPolygon(xPoints, yPoints, nPoints, false, false); + Stroke tmp = stroke; + setStroke(draw3DRectStroke); + super.draw3DRect(x, y, width, height, raised); + setStroke(tmp); } - private boolean drawRaster(ColorModel cm, Raster r, - AffineTransform imageToUser, Color bgcolor) + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) { - if (r == null) - return false; - - SampleModel sm = r.getSampleModel(); - DataBuffer db = r.getDataBuffer(); - - if (db == null || sm == null) - return false; - - if (cm == null) - cm = ColorModel.getRGBdefault(); - - double[] i2u = new double[6]; - if (imageToUser != null) - imageToUser.getMatrix(i2u); - else - { - i2u[0] = 1; - i2u[1] = 0; - i2u[2] = 0; - i2u[3] = 1; - i2u[4] = 0; - i2u[5] = 0; - } - - int[] pixels = findSimpleIntegerArray(cm, r); - - if (pixels == null) - { - // FIXME: I don't think this code will work correctly with a non-RGB - // MultiPixelPackedSampleModel. Although this entire method should - // probably be rewritten to better utilize Cairo's different supported - // data formats. - if (sm instanceof MultiPixelPackedSampleModel) - { - pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels); - for (int i = 0; i < pixels.length; i++) - pixels[i] = cm.getRGB(pixels[i]); - } - else - { - pixels = new int[r.getWidth() * r.getHeight()]; - for (int i = 0; i < pixels.length; i++) - pixels[i] = cm.getRGB(db.getElem(i)); - } - } - - // Change all transparent pixels in the image to the specified bgcolor, - // or (if there's no alpha) fill in an alpha channel so that it paints - // correctly. - if (cm.hasAlpha()) - { - if (bgcolor != null && cm.hasAlpha()) - for (int i = 0; i < pixels.length; i++) - { - if (cm.getAlpha(pixels[i]) == 0) - pixels[i] = bgcolor.getRGB(); - } - } - else - for (int i = 0; i < pixels.length; i++) - pixels[i] |= 0xFF000000; + draw(new Arc2D.Double((double) x, (double) y, (double) width, + (double) height, (double) startAngle, + (double) arcAngle, Arc2D.OPEN)); + } - drawPixels(pixels, r.getWidth(), r.getHeight(), r.getWidth(), i2u); + public void drawLine(int x1, int y1, int x2, int y2) + { + draw(new Line2D.Double(x1, y1, x2, y2)); + } - updateBufferedImage(); - - // Cairo seems loosing the current color. - setColor(fg); - - return true; + public void drawRect(int x, int y, int width, int height) + { + draw(new Rectangle(x, y, width, height)); } - public void drawRenderedImage(RenderedImage image, AffineTransform xform) + public void fillArc(int x, int y, int width, int height, int startAngle, + int arcAngle) { - drawRaster(image.getColorModel(), image.getData(), xform, bg); + fill(new Arc2D.Double((double) x, (double) y, (double) width, + (double) height, (double) startAngle, + (double) arcAngle, Arc2D.OPEN)); } - public void drawRenderableImage(RenderableImage image, AffineTransform xform) + public void fillRect(int x, int y, int width, int height) { - drawRenderedImage(image.createRendering(new RenderContext(xform)), xform); + fill(new Rectangle(x, y, width, height)); } - public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { - return drawImage(img, xform, bg, obs); + fill(new Polygon(xPoints, yPoints, nPoints)); } - public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { - Image filtered = op.filter(image, null); - drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), bg, null); + draw(new Polygon(xPoints, yPoints, nPoints)); } - public boolean drawImage(Image img, int x, int y, ImageObserver observer) + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { - return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), bg, - observer); + draw(new Polygon(xPoints, yPoints, nPoints)); } - /////////////////////////////////////////////// - ////// Unimplemented Stubs and Overloads ////// - /////////////////////////////////////////////// + public void drawOval(int x, int y, int width, int height) + { + drawArc(x, y, width, height, 0, 360); + } - public boolean hit(Rectangle rect, Shape text, boolean onStroke) + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) { - throw new java.lang.UnsupportedOperationException(); + draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); } - public GraphicsConfiguration getDeviceConfiguration() + public void fillOval(int x, int y, int width, int height) { - throw new java.lang.UnsupportedOperationException(); + fillArc(x, y, width, height, 0, 360); } - public void setComposite(Composite comp) + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) { - this.comp = comp; + fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + /** + * CopyArea - performs clipping to the native surface as a convenience + * (requires getRealBounds). Then calls copyAreaImpl. + */ + public void copyArea(int ox, int oy, int owidth, int oheight, + int odx, int ody) + { + Point2D pos = transform.transform(new Point2D.Double(ox, oy), + (Point2D) null); + Point2D dim = transform.transform(new Point2D.Double(ox + owidth, + oy + oheight), + (Point2D) null); + Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody), + (Point2D) null); + int x = (int)pos.getX(); + int y = (int)pos.getY(); + int width = (int)(dim.getX() - pos.getX()); + int height = (int)(dim.getY() - pos.getY()); + int dx = (int)(p2.getX() - pos.getX()); + int dy = (int)(p2.getY() - pos.getY()); + + Rectangle2D r = getRealBounds(); + + if( width < 0 || height < 0 ) + return; + // Return if outside the surface + if( x + dx > r.getWidth() || y + dy > r.getHeight() ) + return; - if (comp instanceof AlphaComposite) + if( x + dx + width < r.getX() || y + dy + height < r.getY() ) + return; + + // Clip edges if necessary + if( x + dx < r.getX() ) // left { - AlphaComposite a = (AlphaComposite) comp; - cairoSetOperator(a.getRule()); - Color c = getColor(); - setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), - (int) (a.getAlpha() * ((float) c.getAlpha())))); + width = x + dx + width; + x = (int)r.getX() - dx; } - else - throw new java.lang.UnsupportedOperationException(); + + if( y + dy < r.getY() ) // top + { + height = y + dy + height; + y = (int)r.getY() - dy; + } + + if( x + dx + width >= r.getWidth() ) // right + width = (int)r.getWidth() - dx - x; + + if( y + dy + height >= r.getHeight() ) // bottom + height = (int)r.getHeight() - dy - y; + + copyAreaImpl(x, y, width, height, dx, dy); } + ///////////////////////// RENDERING HINTS /////////////////////////////////// + + /** + * FIXME- support better + */ public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { hints.put(hintKey, hintValue); @@ -1316,7 +1021,7 @@ public class GdkGraphics2D extends Graphics2D } shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) - || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); } public Object getRenderingHint(RenderingHints.Key hintKey) @@ -1351,74 +1056,137 @@ public class GdkGraphics2D extends Graphics2D } shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) - || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); } - public void setRenderingHintsUnlocked(Map hints) + public void addRenderingHints(Map hints) { - this.hints = new RenderingHints(getDefaultHints()); this.hints.add(new RenderingHints(hints)); + } - if (hints.containsKey(RenderingHints.KEY_INTERPOLATION)) - { - if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) - cairoSurfaceSetFilterUnlocked(0); + public RenderingHints getRenderingHints() + { + return hints; + } - else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) - cairoSurfaceSetFilterUnlocked(1); + ///////////////////////// IMAGE. METHODS /////////////////////////////////// + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (img == null) + return false; + + // In this case, xform is an AffineTransform that transforms bounding + // box of the specified image from image space to user space. However + // when we pass this transform to cairo, cairo will use this transform + // to map "user coordinates" to "pixel" coordinates, which is the + // other way around. Therefore to get the "user -> pixel" transform + // that cairo wants from "image -> user" transform that we currently + // have, we will need to invert the transformation matrix. + AffineTransform invertedXform = new AffineTransform(); + + try + { + invertedXform = xform.createInverse(); + } + catch (NoninvertibleTransformException e) + { + throw new ImagingOpException("Unable to invert transform " + + xform.toString()); } - if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION)) + // Unrecognized image - convert to a BufferedImage and come back. + if( !(img instanceof BufferedImage) ) + return this.drawImage(Toolkit.getDefaultToolkit(). + createImage(img.getSource()), + xform, bgcolor, obs); + + BufferedImage b = (BufferedImage) img; + DataBuffer db; + double[] i2u = new double[6]; + int width = b.getWidth(); + int height = b.getHeight(); + + // If this BufferedImage has a BufferedImageGraphics object, + // use the cached CairoSurface that BIG is drawing onto + if( BufferedImageGraphics.bufferedImages.get( b ) != null ) + db = (DataBuffer)BufferedImageGraphics.bufferedImages.get( b ); + else + db = b.getRaster().getDataBuffer(); + + invertedXform.getMatrix(i2u); + + if(db instanceof CairoSurface) { - if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) - cairoSurfaceSetFilterUnlocked(2); + ((CairoSurface)db).drawSurface(this, i2u); + return true; + } + + if( bgcolor != null ) + { + // Fill a rectangle with the background color + // to composite the image onto. + Paint oldPaint = paint; + AffineTransform oldTransform = transform; + setPaint( bgcolor ); + setTransform( invertedXform ); + fillRect(0, 0, width, height); + setTransform( oldTransform ); + setPaint( oldPaint ); + } - else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) - cairoSurfaceSetFilterUnlocked(3); + int[] pixels; - else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) - cairoSurfaceSetFilterUnlocked(4); + // Shortcut for easy color models. + if( b.getColorModel().equals(rgb32) ) + { + pixels = ((DataBufferInt)db).getData(); + for(int i = 0; i < pixels.length; i++) + pixels[i] |= 0xFF000000; + } + else if( b.getColorModel().equals(argb32) ) + { + pixels = ((DataBufferInt)db).getData(); + } + else + { + pixels = b.getRGB(0, 0, width, height, + null, 0, width); } - shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) - || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); - } + drawPixels(pixels, width, height, width, i2u); - public void addRenderingHints(Map hints) - { - this.hints.add(new RenderingHints(hints)); + // Cairo seems to lose the current color which must be restored. + updateColor(); + return true; } - public RenderingHints getRenderingHints() + public void drawRenderedImage(RenderedImage image, AffineTransform xform) { - return hints; + drawRaster(image.getColorModel(), image.getData(), xform, null); } - public Composite getComposite() + public void drawRenderableImage(RenderableImage image, AffineTransform xform) { - if (comp == null) - return AlphaComposite.SrcOver; - else - return comp; + drawRenderedImage(image.createRendering(new RenderContext(xform)), xform); } - public FontRenderContext getFontRenderContext() + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { - return new FontRenderContext(transform, true, true); + return drawImage(img, xform, null, obs); } - public void copyArea(int x, int y, int width, int height, int dx, int dy) + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) { - GdkGraphics2D g = (GdkGraphics2D) create(x, y, width, height); - gdkDrawDrawable(g, x + dx, y + dy); + Image filtered = op.filter(image, null); + drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, null); } - public void drawArc(int x, int y, int width, int height, int startAngle, - int arcAngle) + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - draw(new Arc2D.Double((double) x, (double) y, (double) width, - (double) height, (double) startAngle, - (double) arcAngle, Arc2D.OPEN)); + return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, + observer); } public boolean drawImage(Image img, int x, int y, Color bgcolor, @@ -1433,6 +1201,8 @@ public class GdkGraphics2D extends Graphics2D { double scaleX = width / (double) img.getWidth(observer); double scaleY = height / (double) img.getHeight(observer); + if( scaleX == 0 || scaleY == 0 ) + return true; return drawImage(img, new AffineTransform(scaleX, 0f, 0f, scaleY, x, y), bgcolor, observer); @@ -1441,7 +1211,7 @@ public class GdkGraphics2D extends Graphics2D public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { - return drawImage(img, x, y, width, height, bg, observer); + return drawImage(img, x, y, width, height, null, observer); } public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, @@ -1451,101 +1221,51 @@ public class GdkGraphics2D extends Graphics2D if (img == null) return false; - Image subImage; - int sourceWidth = sx2 - sx1; int sourceHeight = sy2 - sy1; int destWidth = dx2 - dx1; int destHeight = dy2 - dy1; + if(destWidth == 0 || destHeight == 0 || sourceWidth == 0 || + sourceHeight == 0) + return true; + double scaleX = destWidth / (double) sourceWidth; double scaleY = destHeight / (double) sourceHeight; - // Get the subimage of the source enclosed in the - // rectangle specified by sx1, sy1, sx2, sy2 - - if (img instanceof BufferedImage) - { - BufferedImage b = (BufferedImage) img; - subImage = b.getSubimage(sx1, sy1, sx2, sy2); - } + // FIXME: Avoid using an AT if possible here - it's at least twice as slow. + + Shape oldClip = getClip(); + int cx, cy, cw, ch; + if( dx1 < dx2 ) + { cx = dx1; cw = dx2 - dx1; } else - { - // FIXME: This code currently doesn't work. Null Pointer - // exception is thrown in this case. This happens - // because img.getSource() always returns null, since source gets - // never initialized when it is created with the help of - // createImage(int width, int height). - CropImageFilter filter = new CropImageFilter(sx1, sx2, sx2, sy2); - FilteredImageSource src = new FilteredImageSource(img.getSource(), - filter); - - subImage = Toolkit.getDefaultToolkit().createImage(src); - } + { cx = dx2; cw = dx1 - dx2; } + if( dy1 < dy2 ) + { cy = dy1; ch = dy2 - dy1; } + else + { cy = dy2; ch = dy1 - dy2; } + + setClip( cx, cy, cw, ch ); - return drawImage(subImage, - new AffineTransform(scaleX, 0, 0, scaleY, dx1, dy1), - bgcolor, observer); + AffineTransform tx = new AffineTransform(); + tx.translate( dx1 - sx1*scaleX, dy1 - sy1*scaleY ); + tx.scale( scaleX, scaleY ); + + boolean retval = drawImage(img, tx, bgcolor, observer); + setClip( oldClip ); + return retval; } public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { - return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bg, observer); + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); } - public void drawOval(int x, int y, int width, int height) - { - drawArc(x, y, width, height, 0, 360); - } - - public void drawRoundRect(int x, int y, int width, int height, int arcWidth, - int arcHeight) - { - if (arcWidth > width) - arcWidth = width; - if (arcHeight > height) - arcHeight = height; - - int xx = x + width - arcWidth; - int yy = y + height - arcHeight; - - drawArc(x, y, arcWidth, arcHeight, 90, 90); - drawArc(xx, y, arcWidth, arcHeight, 0, 90); - drawArc(xx, yy, arcWidth, arcHeight, 270, 90); - drawArc(x, yy, arcWidth, arcHeight, 180, 90); - - int y1 = y + arcHeight / 2; - int y2 = y + height - arcHeight / 2; - drawLine(x, y1, x, y2); - drawLine(x + width, y1, x + width, y2); - - int x1 = x + arcWidth / 2; - int x2 = x + width - arcWidth / 2; - drawLine(x1, y, x2, y); - drawLine(x1, y + height, x2, y + height); - } - - // these are the most accelerated painting paths - native void cairoDrawGlyphVector(GdkFontPeer font, - float x, float y, int n, - int[] codes, float[] positions); - - native void cairoDrawGdkTextLayout(GdkTextLayout gl, - float x, float y); - - GdkFontPeer getFontPeer() - { - return (GdkFontPeer) getFont().getPeer(); - } - - public void drawGdkTextLayout(GdkTextLayout gl, float x, float y) - { - cairoDrawGdkTextLayout (gl, x, y); - updateBufferedImage (); - } + ///////////////////////// TEXT METHODS //////////////////////////////////// public void drawString(String str, float x, float y) { @@ -1553,7 +1273,6 @@ public class GdkGraphics2D extends Graphics2D return; drawGlyphVector(getFont().createGlyphVector(null, str), x, y); - updateBufferedImage (); } public void drawString(String str, int x, int y) @@ -1573,8 +1292,7 @@ public class GdkGraphics2D extends Graphics2D float[] positions = gv.getGlyphPositions (0, n, null); setFont (gv.getFont ()); - cairoDrawGlyphVector (getFontPeer(), x, y, n, codes, positions); - updateBufferedImage (); + cairoDrawGlyphVector( (GdkFontPeer)getFont().getPeer(), x, y, n, codes, positions); } public void drawString(AttributedCharacterIterator ci, float x, float y) @@ -1583,52 +1301,19 @@ public class GdkGraphics2D extends Graphics2D drawGlyphVector(gv, x, y); } - public void fillArc(int x, int y, int width, int height, int startAngle, - int arcAngle) - { - fill(new Arc2D.Double((double) x, (double) y, (double) width, - (double) height, (double) startAngle, - (double) arcAngle, Arc2D.OPEN)); - } - - public void fillOval(int x, int y, int width, int height) - { - fillArc(x, y, width, height, 0, 360); - } - - public void fillRoundRect(int x, int y, int width, int height, int arcWidth, - int arcHeight) - { - if (arcWidth > width) - arcWidth = width; - if (arcHeight > height) - arcHeight = height; - - int xx = x + width - arcWidth; - int yy = y + height - arcHeight; - - fillArc(x, y, arcWidth, arcHeight, 90, 90); - fillArc(xx, y, arcWidth, arcHeight, 0, 90); - fillArc(xx, yy, arcWidth, arcHeight, 270, 90); - fillArc(x, yy, arcWidth, arcHeight, 180, 90); - - fillRect(x, y + arcHeight / 2, width, height - arcHeight + 1); - fillRect(x + arcWidth / 2, y, width - arcWidth + 1, height); - } - - public Font getFont() + /** + * Should perhaps be contexct dependent, but this is left for now as an + * overloadable default implementation. + */ + public FontRenderContext getFontRenderContext() { - if (font == null) - return new Font("SansSerif", Font.PLAIN, 12); - return font; + return new FontRenderContext(transform, true, true); } // Until such time as pango is happy to talk directly to cairo, we // actually need to redirect some calls from the GtkFontPeer and // GtkFontMetrics into the drawing kit and ask cairo ourselves. - static native void releasePeerGraphicsResource(GdkFontPeer f); - public FontMetrics getFontMetrics() { return getFontMetrics(getFont()); @@ -1656,9 +1341,25 @@ public class GdkGraphics2D extends Graphics2D .getFont(f.getName(), f.getAttributes()); } - public void setFontUnlocked(Font f) + public Font getFont() + { + if (font == null) + return new Font("SansSerif", Font.PLAIN, 12); + return font; + } + + /////////////////////// MISC. PUBLIC METHODS ///////////////////////////////// + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { - setFont (f); + if( onStroke ) + { + Shape stroked = stroke.createStrokedShape( s ); + return stroked.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + return s.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); } public String toString() @@ -1668,4 +1369,218 @@ public class GdkGraphics2D extends Graphics2D + ",color=" + fg.toString() + "]"); } + + ///////////////////////// PRIVATE METHODS /////////////////////////////////// + + /** + * All the drawImage() methods eventually get delegated here if the image + * is not a Cairo surface. + * + * @param bgcolor - if non-null draws the background color before + * drawing the image. + */ + private boolean drawRaster(ColorModel cm, Raster r, + AffineTransform imageToUser, Color bgcolor) + { + if (r == null) + return false; + + SampleModel sm = r.getSampleModel(); + DataBuffer db = r.getDataBuffer(); + + if (db == null || sm == null) + return false; + + if (cm == null) + cm = ColorModel.getRGBdefault(); + + double[] i2u = new double[6]; + if (imageToUser != null) + imageToUser.getMatrix(i2u); + else + { + i2u[0] = 1; + i2u[1] = 0; + i2u[2] = 0; + i2u[3] = 1; + i2u[4] = 0; + i2u[5] = 0; + } + + int[] pixels = findSimpleIntegerArray(cm, r); + + if (pixels == null) + { + // FIXME: I don't think this code will work correctly with a non-RGB + // MultiPixelPackedSampleModel. Although this entire method should + // probably be rewritten to better utilize Cairo's different supported + // data formats. + if (sm instanceof MultiPixelPackedSampleModel) + { + pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels); + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(pixels[i]); + } + else + { + pixels = new int[r.getWidth() * r.getHeight()]; + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(db.getElem(i)); + } + } + + // Change all transparent pixels in the image to the specified bgcolor, + // or (if there's no alpha) fill in an alpha channel so that it paints + // correctly. + if (cm.hasAlpha()) + { + if (bgcolor != null && cm.hasAlpha()) + for (int i = 0; i < pixels.length; i++) + { + if (cm.getAlpha(pixels[i]) == 0) + pixels[i] = bgcolor.getRGB(); + } + } + else + for (int i = 0; i < pixels.length; i++) + pixels[i] |= 0xFF000000; + + drawPixels(pixels, r.getWidth(), r.getHeight(), r.getWidth(), i2u); + + // Cairo seems to lose the current color which must be restored. + updateColor(); + + return true; + } + + /** + * Shifts coordinates by 0.5. + */ + private double shifted(double coord, boolean doShift) + { + if (doShift) + return Math.floor(coord) + 0.5; + else + return coord; + } + + /** + * Adds a pathIterator to the current Cairo path, also sets the cairo winding rule. + */ + private void walkPath(PathIterator p, boolean doShift) + { + double x = 0; + double y = 0; + double[] coords = new double[6]; + + cairoSetFillRule(p.getWindingRule()); + for (; ! p.isDone(); p.next()) + { + int seg = p.currentSegment(coords); + switch (seg) + { + case PathIterator.SEG_MOVETO: + x = shifted(coords[0], doShift); + y = shifted(coords[1], doShift); + cairoMoveTo(x, y); + break; + case PathIterator.SEG_LINETO: + x = shifted(coords[0], doShift); + y = shifted(coords[1], doShift); + cairoLineTo(x, y); + break; + case PathIterator.SEG_QUADTO: + // splitting a quadratic bezier into a cubic: + // see: http://pfaedit.sourceforge.net/bezier.html + double x1 = x + (2.0 / 3.0) * (shifted(coords[0], doShift) - x); + double y1 = y + (2.0 / 3.0) * (shifted(coords[1], doShift) - y); + + double x2 = x1 + (1.0 / 3.0) * (shifted(coords[2], doShift) - x); + double y2 = y1 + (1.0 / 3.0) * (shifted(coords[3], doShift) - y); + + x = shifted(coords[2], doShift); + y = shifted(coords[3], doShift); + cairoCurveTo(x1, y1, x2, y2, x, y); + break; + case PathIterator.SEG_CUBICTO: + x = shifted(coords[4], doShift); + y = shifted(coords[5], doShift); + cairoCurveTo(shifted(coords[0], doShift), + shifted(coords[1], doShift), + shifted(coords[2], doShift), + shifted(coords[3], doShift), x, y); + break; + case PathIterator.SEG_CLOSE: + cairoClosePath(); + break; + } + } + } + + /** + * Used by setRenderingHints() + */ + private Map getDefaultHints() + { + HashMap defaultHints = new HashMap(); + + defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + + defaultHints.put(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_DEFAULT); + + defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + + defaultHints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + + defaultHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_DEFAULT); + + return defaultHints; + } + + /** + * Used by drawRaster and GdkPixbufDecoder + */ + public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster) + { + if (cm == null || raster == null) + return null; + + if (! cm.getColorSpace().isCS_sRGB()) + return null; + + if (! (cm instanceof DirectColorModel)) + return null; + + DirectColorModel dcm = (DirectColorModel) cm; + + if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00 + || dcm.getBlueMask() != 0x000000FF) + return null; + + if (! (raster instanceof WritableRaster)) + return null; + + if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT) + return null; + + if (! (raster.getDataBuffer() instanceof DataBufferInt)) + return null; + + DataBufferInt db = (DataBufferInt) raster.getDataBuffer(); + + if (db.getNumBanks() != 1) + return null; + + // Finally, we have determined that this is a single bank, [A]RGB-int + // buffer in sRGB space. It's worth checking all this, because it means + // that cairo can paint directly into the data buffer, which is very + // fast compared to all the normal copying and converting. + + return db.getData(); + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java new file mode 100644 index 0000000..e19c9b9 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java @@ -0,0 +1,288 @@ +/* CairoSurface.java + 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.gtk; + +import java.awt.Graphics; +import java.awt.Color; +import java.awt.Image; +import java.awt.Point; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.io.File; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.net.URL; +import gnu.classpath.Pointer; + +/** + * CairoSurface - wraps a Cairo surface. + * + * @author Sven de Marothy + */ +public class CairoSurface extends DataBuffer +{ + int width = -1, height = -1; + + /** + * The native pointer to the Cairo surface. + */ + long surfacePointer; + + /** + * The native pointer to the image's data buffer + */ + long bufferPointer; + + + static ColorModel nativeModel = new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + + /** + * Allocates and clears the buffer and creates the cairo surface. + * @param width, height - the image size + * @param stride - the buffer row stride. + */ + private native void create(int width, int height, int stride); + + /** + * Destroys the cairo surface and frees the buffer. + */ + private native void destroy(); + + /** + * Gets buffer elements + */ + private native int nativeGetElem(int i); + + /** + * Sets buffer elements. + */ + private native void nativeSetElem(int i, int val); + + /** + * Draws this image to a given CairoGraphics context, + * with an affine transform given by i2u. + */ + public native void drawSurface(CairoGraphics2D context, double[] i2u); + + /** + * getPixels -return the pixels as a java array. + */ + native int[] getPixels(int size); + + /** + * getPixels -return the pixels as a java array. + */ + native void setPixels(int[] pixels); + + native long getFlippedBuffer(int size); + + /** + * Create a cairo_surface_t with specified width and height. + * The format will be ARGB32 with premultiplied alpha and native bit + * and word ordering. + */ + CairoSurface(int width, int height) + { + super(DataBuffer.TYPE_INT, width * height); + + if(width <= 0 || height <= 0) + throw new IllegalArgumentException("Image must be at least 1x1 pixels."); + + this.width = width; + this.height = height; + + create(width, height, width * 4); + + if(surfacePointer == 0 || bufferPointer == 0) + throw new Error("Could not allocate bitmap."); + } + + /** + * Create a cairo_surface_t from a GtkImage instance. + * (data is copied, not shared) + */ + CairoSurface(GtkImage image) + { + super(DataBuffer.TYPE_INT, image.width * image.height); + + if(image.width <= 0 || image.height <= 0) + throw new IllegalArgumentException("Image must be at least 1x1 pixels."); + + width = image.width; + height = image.height; + + create(width, height, width * 4); + + if(surfacePointer == 0 || bufferPointer == 0) + throw new Error("Could not allocate bitmap."); + + // Copy the pixel data from the GtkImage. + int[] data = image.getPixels(); + + // Swap ordering from GdkPixbuf to Cairo + for(int i = 0; i < data.length; i++ ) + { + int alpha = (data[i] & 0xFF000000) >> 24; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + int r = (((data[i] & 0x00FF0000) >> 16) ); + int g = (((data[i] & 0x0000FF00) >> 8) ); + int b = ((data[i] & 0x000000FF) ); + data[i] = (( alpha << 24 ) & 0xFF000000) + | (( b << 16 ) & 0x00FF0000) + | (( g << 8 ) & 0x0000FF00) + | ( r & 0x000000FF); + } + } + + setPixels( data ); + } + + /** + * Dispose of the native data. + */ + public void dispose() + { + if(surfacePointer != 0) + destroy(); + } + + /** + * Call dispose() to clean up any native resources allocated. + */ + protected void finalize() + { + dispose(); + } + + /** + * Return a GtkImage from this Cairo surface. + */ + public GtkImage getGtkImage() + { + return new GtkImage( width, height, getFlippedBuffer( width * height )); + } + + /** + * Returns a BufferedImage backed by a Cairo surface. + */ + public static BufferedImage getBufferedImage(int width, int height) + { + return getBufferedImage(new CairoSurface(width, height)); + } + + /** + * Returns a BufferedImage backed by a Cairo surface, + * created from a GtkImage. + */ + public static BufferedImage getBufferedImage(GtkImage image) + { + return getBufferedImage(new CairoSurface(image)); + } + + /** + * Returns a BufferedImage backed by a Cairo surface. + */ + public static BufferedImage getBufferedImage(CairoSurface surface) + { + WritableRaster raster = Raster.createPackedRaster + (surface, surface.width, surface.height, surface.width, + new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }, + new Point(0,0)); + + return new BufferedImage(nativeModel, raster, true, new Hashtable()); + } + + /** + * DataBank.getElem implementation + */ + public int getElem(int bank, int i) + { + if(bank != 0 || i < 0 || i >= width*height) + throw new IndexOutOfBoundsException(i+" size: "+width*height); + return nativeGetElem(i); + } + + /** + * DataBank.setElem implementation + */ + public void setElem(int bank, int i, int val) + { + if(bank != 0 || i < 0 || i >= width*height) + throw new IndexOutOfBoundsException(i+" size: "+width*height); + nativeSetElem(i, val); + } + + /** + * Return a Graphics2D drawing to the CairoSurface. + */ + public Graphics2D getGraphics() + { + return new CairoSurfaceGraphics(this); + } + + ///// Methods used by CairoSurfaceGraphics ///// + /** + * Creates a cairo_t drawing context, returns the pointer as a long. + * Used by CairoSurfaceGraphics. + */ + native long newCairoContext(); + + /** + * Copy an area of the surface. Expects parameters must be within bounds. + * Count on a segfault otherwise. + */ + native void copyAreaNative(int x, int y, int width, int height, + int dx, int dy, int stride); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java new file mode 100644 index 0000000..38c549d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java @@ -0,0 +1,100 @@ +/* CairoSurfaceGraphics.java + 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.gtk; + +import java.awt.Graphics; +import java.awt.Color; +import java.awt.Image; +import java.awt.Point; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.geom.Rectangle2D; +import java.awt.image.*; + +/** + * Implementation of Graphics2D on a Cairo surface. + */ +public class CairoSurfaceGraphics extends CairoGraphics2D +{ + protected CairoSurface surface; + private long cairo_t; + + /** + * Create a graphics context from a cairo surface + */ + public CairoSurfaceGraphics(CairoSurface surface) + { + this.surface = surface; + cairo_t = surface.newCairoContext(); + setup( cairo_t ); + setClip(0, 0, surface.width, surface.height); + } + + /** + * Creates another context from a surface. + * Used by create(). + */ + private CairoSurfaceGraphics(CairoSurfaceGraphics copyFrom) + { + surface = copyFrom.surface; + cairo_t = surface.newCairoContext(); + copy( copyFrom, cairo_t ); + setClip(0, 0, surface.width, surface.height); + } + + public Graphics create() + { + return new CairoSurfaceGraphics(this); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + throw new UnsupportedOperationException(); + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0.0, 0.0, surface.width, surface.height); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java new file mode 100644 index 0000000..c6cf494 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -0,0 +1,243 @@ +/* ComponentGraphics.java -- + 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.gtk; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Point; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.awt.image.ImagingOpException; +import java.awt.image.RenderedImage; + +/** + * ComponentGraphics - context for drawing directly to a component, + * as this is an X drawable, it requires that we use GTK locks. + * + * This context draws directly to the drawable and requires xrender. + */ +public class ComponentGraphics extends CairoGraphics2D +{ + private GtkComponentPeer component; + protected long cairo_t; + + ComponentGraphics() + { + } + + private ComponentGraphics(GtkComponentPeer component) + { + this.component = component; + cairo_t = initState(component); + setup( cairo_t ); + Rectangle bounds = component.awtComponent.getBounds(); + setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); + setBackground(component.awtComponent.getBackground()); + setColor(component.awtComponent.getForeground()); + } + + private ComponentGraphics(ComponentGraphics cg) + { + component = cg.component; + cairo_t = initState(component); + copy( cg, cairo_t ); + Rectangle bounds = component.awtComponent.getBounds(); + setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); + setBackground(component.awtComponent.getBackground()); + setColor(component.awtComponent.getForeground()); + } + + /** + * Creates a cairo_t for the component surface and return it. + */ + private native long initState(GtkComponentPeer component); + + /** + * Destroys the component surface and calls dispose on the cairo + * graphics2d to destroy any super class resources. + */ + public void dispose() + { + disposeSurface(nativePointer); + super.dispose(); + } + + /** + * Destroys the component surface. + */ + private native void disposeSurface(long nativePointer); + + /** + * Creates a cairo_t for a volatile image + */ + protected native long initFromVolatile( long pixmapPtr, int width, int height); + + /** + * Grab lock + */ + private native void start_gdk_drawing(); + + /** + * Release lock + */ + private native void end_gdk_drawing(); + + /** + * Query if the system has the XRender extension. + */ + public static native boolean hasXRender(); + + + private native void copyAreaNative(GtkComponentPeer component, int x, int y, + int width, int height, int dx, int dy); + + private native void drawVolatile(GtkComponentPeer component, + Image vimg, int x, int y, + int width, int height); + + /** + * Returns a Graphics2D object for a component, either an instance of this + * class (if xrender is supported), or a context which copies. + */ + public static Graphics2D getComponentGraphics(GtkComponentPeer component) + { + if( hasXRender() ) + return new ComponentGraphics(component); + + Rectangle r = component.awtComponent.getBounds(); + return new ComponentGraphicsCopy(r.width, r.height, component); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return component.getGraphicsConfiguration(); + } + + public Graphics create() + { + return new ComponentGraphics(this); + } + + protected Rectangle2D getRealBounds() + { + return component.awtComponent.getBounds(); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + copyAreaNative(component, x, y, width, height, dx, dy); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + start_gdk_drawing(); + super.draw(s); + end_gdk_drawing(); + } + + public void fill(Shape s) + { + start_gdk_drawing(); + super.fill(s); + end_gdk_drawing(); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + start_gdk_drawing(); + super.drawRenderedImage(image, xform); + end_gdk_drawing(); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + start_gdk_drawing(); + boolean rv = super.drawImage(img, xform, bgcolor, obs); + end_gdk_drawing(); + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + start_gdk_drawing(); + super.drawGlyphVector(gv, x, y); + end_gdk_drawing(); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + if( img instanceof GtkVolatileImage ) + { + drawVolatile( component, img, x, y - 20, + ((GtkVolatileImage)img).width, + ((GtkVolatileImage)img).height ); + return true; + } + return super.drawImage( img, x, y, observer ); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + if( img instanceof GtkVolatileImage ) + { + drawVolatile( component, img, x, y - 20, + width, height ); + return true; + } + return super.drawImage( img, x, y, width, height, observer ); + } + +} + diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java new file mode 100644 index 0000000..286fbea --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java @@ -0,0 +1,129 @@ +/* ComponentGraphicsCopy.java + 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.gtk; + +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.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; + +/** + * Implementation of Graphics2D for Components for servers which + * do not have xrender. + * + * A mirrored GtkImage of the component is stored in memory + * and copied back. Yay. + */ +public class ComponentGraphicsCopy extends CairoSurfaceGraphics +{ + private GtkComponentPeer component; + + /** + * GtkImage sharing its data buffer with this Cairo surface. + */ + private GtkImage gtkimage; + + private int width, height; + + native void getPixbuf( GtkComponentPeer component, GtkImage image ); + + native void copyPixbuf( GtkComponentPeer component, GtkImage image, + int x, int y, int w, int h ); + + public ComponentGraphicsCopy(int width, int height, + GtkComponentPeer component) + { + super( new CairoSurface( width, height ) ); + this.component = component; + this.width = width; + this.height = height; + gtkimage = surface.getGtkImage(); + getPixbuf( component, gtkimage ); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + super.draw(s); + Rectangle r = s.getBounds(); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } + + public void fill(Shape s) + { + super.fill(s); + Rectangle r = s.getBounds(); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + super.drawRenderedImage(image, xform); + copyPixbuf(component, gtkimage, 0, 0, width, height); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + boolean rv = super.drawImage(img, xform, bgcolor, obs); + copyPixbuf(component, gtkimage, 0, 0, width, height); + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + super.drawGlyphVector(gv, x, y); + Rectangle r = gv.getPixelBounds(getFontRenderContext(), x , y); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } +} + diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java new file mode 100644 index 0000000..0f8ce6d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java @@ -0,0 +1,392 @@ +/* FreetypeGlyphVector.java + 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.gtk; + +import java.awt.Font; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; + +public class FreetypeGlyphVector extends GlyphVector +{ + /** + * The associated font and its peer. + */ + private Font font; + private GdkFontPeer peer; // ATTN: Accessed from native code. + + /** + * The string represented by this GlyphVector. + */ + private String s; + + /** + * The font render context + */ + private FontRenderContext frc; + + /** + * The total # of glyphs. + */ + private int nGlyphs; + + /** + * The glyph codes + */ + private int[] glyphCodes; + + /** + * Glyph transforms. (de facto only the translation is used) + */ + private AffineTransform[] glyphTransforms; + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, String s, FontRenderContext frc) + { + this.s = s; + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + getGlyphs(); + performDefaultLayout(); + } + + /** + * Create a glyphvector from a given set of glyph codes. + */ + public FreetypeGlyphVector(Font f, int[] codes, FontRenderContext frc) + { + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + glyphCodes = new int[ codes.length ]; + System.arraycopy(codes, 0, glyphCodes, 0, codes.length); + nGlyphs = glyphCodes.length; + performDefaultLayout(); + } + + /** + * Create the array of glyph codes. + */ + private void getGlyphs() + { + nGlyphs = s.codePointCount( 0, s.length() ); + glyphCodes = new int[ nGlyphs ]; + int stringIndex = 0; + for(int i = 0; i < nGlyphs; i++) + { + glyphCodes[i] = getGlyph( s.codePointAt(stringIndex) ); + // UTF32 surrogate handling + if( s.codePointAt( stringIndex ) != (int)s.charAt( stringIndex ) ) + stringIndex ++; + stringIndex ++; + } + } + + /** + * Returns the glyph code within the font for a given character + */ + public native int getGlyph(int codepoint); + + /** + * Returns the kerning of a glyph pair + */ + private native Point2D getKerning(int leftGlyph, int rightGlyph); + + private native double[] getMetricsNative( int glyphCode ); + + private native GeneralPath getGlyphOutlineNative(int glyphIndex); + + /** + * Duh, compares two instances. + */ + public boolean equals(GlyphVector gv) + { + if( ! (gv instanceof FreetypeGlyphVector) ) + return false; + + return (((FreetypeGlyphVector)gv).font.equals(font) && + ((FreetypeGlyphVector)gv).frc.equals(frc) + && ((FreetypeGlyphVector)gv).s.equals(s)); + } + + /** + * Returns the associated Font + */ + public Font getFont() + { + return font; + } + + /** + * Returns the associated FontRenderContext + */ + public FontRenderContext getFontRenderContext() + { + return frc; + } + + /** + * Layout the glyphs. + */ + public void performDefaultLayout() + { + glyphTransforms = new AffineTransform[ nGlyphs ]; + double x = 0; + for(int i = 0; i < nGlyphs; i++) + { + GlyphMetrics gm = getGlyphMetrics( i ); + Rectangle2D r = gm.getBounds2D(); + glyphTransforms[ i ] = AffineTransform.getTranslateInstance(x, 0); + x += gm.getAdvanceX(); + if( i > 0 ) + { + Point2D p = getKerning( glyphCodes[ i - 1 ], glyphCodes[ i ] ); + x += p.getX(); + } + } + } + + /** + * Returns the code of the glyph at glyphIndex; + */ + public int getGlyphCode(int glyphIndex) + { + return glyphCodes[ glyphIndex ]; + } + + /** + * Returns multiple glyphcodes. + */ + public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, + int[] codeReturn) + { + int[] rval; + + if( codeReturn == null ) + rval = new int[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(glyphCodes, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + + /** + * FIXME: Implement me. + */ + public Shape getGlyphLogicalBounds(int glyphIndex) + { + GlyphMetrics gm = getGlyphMetrics( glyphIndex ); + if( gm == null ) + return null; + Rectangle2D r = gm.getBounds2D(); + return new Rectangle2D.Double( r.getX() - gm.getLSB(), r.getY(), + gm.getAdvanceX(), r.getHeight() ); + } + + /** + * Returns the metrics of a single glyph. + */ + public GlyphMetrics getGlyphMetrics(int glyphIndex) + { + double[] val = getMetricsNative( glyphCodes[ glyphIndex ] ); + if( val == null ) + return null; + + return new GlyphMetrics( true, (float)val[1], (float)val[2], + new Rectangle2D.Double( val[3], val[4], + val[5], val[6] ), + GlyphMetrics.STANDARD ); + } + + /** + * Returns the outline of a single glyph. + */ + public Shape getGlyphOutline(int glyphIndex) + { + GeneralPath gp = getGlyphOutlineNative( glyphCodes[ glyphIndex ] ); + gp.transform( glyphTransforms[ glyphIndex ] ); + return gp; + } + + /** + * Returns the position of a single glyph. + */ + public Point2D getGlyphPosition(int glyphIndex) + { + return glyphTransforms[ glyphIndex ].transform( new Point2D.Double(0, 0), + null ); + } + + /** + * Returns the positions of multiple glyphs. + */ + public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn) + { + float[] rval; + + if( positionReturn == null ) + rval = new float[2 * numEntries]; + else + rval = positionReturn; + + for( int i = beginGlyphIndex; i < numEntries; i++ ) + { + Point2D p = getGlyphPosition( i ); + rval[i * 2] = (float)p.getX(); + rval[i * 2 + 1] = (float)p.getY(); + } + + return rval; + } + + /** + * Returns the transform of a glyph. + */ + public AffineTransform getGlyphTransform(int glyphIndex) + { + return new AffineTransform( glyphTransforms[ glyphIndex ] ); + } + + /** + * Returns the visual bounds of a glyph + * May be off by a pixel or two due to hinting/rasterization. + */ + public Shape getGlyphVisualBounds(int glyphIndex) + { + return getGlyphOutline( glyphIndex ).getBounds2D(); + } + + /** + * Return the logical bounds of the whole thing. + */ + public Rectangle2D getLogicalBounds() + { + if( nGlyphs == 0 ) + return new Rectangle2D.Double(0, 0, 0, 0); + + Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 ); + for( int i = 1; i < nGlyphs; i++ ) + rect = rect.createUnion( (Rectangle2D)getGlyphLogicalBounds( i ) ); + + return rect; + } + + /** + * Returns the number of glyphs. + */ + public int getNumGlyphs() + { + return glyphCodes.length; + } + + /** + * Returns the outline of the entire GlyphVector. + */ + public Shape getOutline() + { + GeneralPath path = new GeneralPath(); + for( int i = 0; i < getNumGlyphs(); i++ ) + path.append( getGlyphOutline( i ), false ); + return path; + } + + /** + * TODO: + * FreeType does not currently have an API for the JSTF table. We should + * probably get the table ourselves from FT and pass it to some parser + * which the native font peers will need. + */ + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) + { + return null; + } + + /** + * Returns the outline of the entire vector, drawn at (x,y). + */ + public Shape getOutline(float x, float y) + { + AffineTransform tx = AffineTransform.getTranslateInstance( x, y ); + return tx.createTransformedShape( getOutline() ); + } + + /** + * Returns the visual bounds of the entire GlyphVector. + * May be off by a pixel or two due to hinting/rasterization. + */ + public Rectangle2D getVisualBounds() + { + return getOutline().getBounds2D(); + } + + /** + * Sets the position of a glyph. + */ + public void setGlyphPosition(int glyphIndex, Point2D newPos) + { + // FIXME: Scaling, etc.? + glyphTransforms[ glyphIndex ].setToTranslation( newPos.getX(), + newPos.getY() ); + } + + /** + * Sets the transform of a single glyph. + */ + public void setGlyphTransform(int glyphIndex, AffineTransform newTX) + { + glyphTransforms[ glyphIndex ].setTransform( newTX ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java index 36986d5..7aa5e7a 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java @@ -40,19 +40,23 @@ package gnu.java.awt.peer.gtk; import gnu.classpath.Configuration; import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.font.opentype.NameDecoder; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; +import java.awt.font.GlyphMetrics; import java.awt.font.LineMetrics; import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; +import java.nio.ByteBuffer; public class GdkFontPeer extends ClasspathFontPeer { @@ -76,17 +80,21 @@ public class GdkFontPeer extends ClasspathFontPeer } } + private ByteBuffer nameTable = null; + private native void initState (); private native void dispose (); - private native void setFont (String family, int style, int size, boolean useGraphics2D); + private native void setFont (String family, int style, int size); native void getFontMetrics(double [] metrics); native void getTextMetrics(String str, double [] metrics); + native void releasePeerGraphicsResource(); + + protected void finalize () { - if (GtkToolkit.useGraphics2D ()) - GdkGraphics2D.releasePeerGraphicsResource(this); + releasePeerGraphicsResource(); dispose (); } @@ -136,26 +144,84 @@ public class GdkFontPeer extends ClasspathFontPeer { super(name, style, size); initState (); - setFont (this.familyName, this.style, (int)this.size, - GtkToolkit.useGraphics2D()); + setFont (this.familyName, this.style, (int)this.size); } public GdkFontPeer (String name, Map attributes) { super(name, attributes); initState (); - setFont (this.familyName, this.style, (int)this.size, - GtkToolkit.useGraphics2D()); + setFont (this.familyName, this.style, (int)this.size); } - + + /** + * Unneeded, but implemented anyway. + */ public String getSubFamilyName(Font font, Locale locale) { - return null; + String name; + + if (locale == null) + locale = Locale.getDefault(); + + name = getName(NameDecoder.NAME_SUBFAMILY, locale); + if (name == null) + { + name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH); + if ("Regular".equals(name)) + name = null; + } + + return name; } + /** + * Returns the bytes belonging to a TrueType/OpenType table, + * Parameters n,a,m,e identify the 4-byte ASCII tag of the table. + * + * Returns null if the font is not TT, the table is nonexistant, + * or if some other unexpected error occured. + * + */ + private native byte[] getTrueTypeTable(byte n, byte a, byte m, byte e); + + /** + * Returns the PostScript name of the font, defaults to the familyName if + * a PS name could not be retrieved. + */ public String getPostScriptName(Font font) { - return this.familyName; + String name = getName(NameDecoder.NAME_POSTSCRIPT, + /* any language */ null); + if( name == null ) + return this.familyName; + + return name; + } + + /** + * Extracts a String from the font’s name table. + * + * @param name the numeric TrueType or OpenType name ID. + * + * @param locale the locale for which names shall be localized, or + * <code>null</code> if the locale does mot matter because the name + * is known to be language-independent (for example, because it is + * the PostScript name). + */ + private String getName(int name, Locale locale) + { + if (nameTable == null) + { + byte[] data = getTrueTypeTable((byte)'n', (byte) 'a', + (byte) 'm', (byte) 'e'); + if( data == null ) + return null; + + nameTable = ByteBuffer.wrap( data ); + } + + return NameDecoder.getName(nameTable, name, locale); } public boolean canDisplay (Font font, char c) @@ -170,23 +236,18 @@ public class GdkFontPeer extends ClasspathFontPeer return -1; } - private native GdkGlyphVector getGlyphVector(String txt, - Font f, - FontRenderContext ctx); - public GlyphVector createGlyphVector (Font font, FontRenderContext ctx, CharacterIterator i) { - return getGlyphVector(buildString (i), font, ctx); + return new FreetypeGlyphVector(font, buildString (i), ctx); } public GlyphVector createGlyphVector (Font font, FontRenderContext ctx, int[] glyphCodes) { - return null; - // return new GdkGlyphVector (font, this, ctx, glyphCodes); + return new FreetypeGlyphVector(font, glyphCodes, ctx); } public byte getBaselineFor (Font font, char c) @@ -262,13 +323,21 @@ public class GdkFontPeer extends ClasspathFontPeer public int getNumGlyphs (Font font) { - throw new UnsupportedOperationException (); + byte[] data = getTrueTypeTable((byte)'m', (byte) 'a', + (byte)'x', (byte) 'p'); + if( data == null ) + return -1; + + ByteBuffer buf = ByteBuffer.wrap( data ); + return buf.getShort(4); } public Rectangle2D getStringBounds (Font font, CharacterIterator ci, int begin, int limit, FontRenderContext frc) { - GdkGlyphVector gv = getGlyphVector(buildString (ci, begin, limit), font, frc); + GlyphVector gv = new FreetypeGlyphVector( font, + buildString(ci, begin, limit), + frc); return gv.getVisualBounds(); } @@ -303,5 +372,4 @@ public class GdkFontPeer extends ClasspathFontPeer // the metrics cache. return Toolkit.getDefaultToolkit().getFontMetrics (font); } - } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java deleted file mode 100644 index f0ddea4..0000000 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java +++ /dev/null @@ -1,359 +0,0 @@ -/* GdkGlyphVector.java -- Glyph vector object - Copyright (C) 2003, 2004, 2005 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.gtk; - -import java.awt.Font; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphJustificationInfo; -import java.awt.font.GlyphMetrics; -import java.awt.font.GlyphVector; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -public class GdkGlyphVector extends GlyphVector -{ - - /* We use a simple representation for glyph vectors here. Glyph i - * consumes 8 doubles: - * - * logical x: extents[ 10*i ] - * logical y: extents[ 10*i + 1 ] - * logical width: extents[ 10*i + 2 ] - * logical height: extents[ 10*i + 3 ] - * - * visual x: extents[ 10*i + 4 ] - * visual y: extents[ 10*i + 5 ] - * visual width: extents[ 10*i + 6 ] - * visual height: extents[ 10*i + 7 ] - * - * origin pos x: extents[ 10*i + 8 ] - * origin pos y: extents[ 10*i + 9 ] - * - * as well as one int, code[i], representing the glyph code in the font. - */ - - double [] extents; - int [] codes; - - Font font; - FontRenderContext fontRenderContext; - - Rectangle2D allLogical; - Rectangle2D allVisual; - - public GdkGlyphVector(double[] extents, int[] codes, Font font, FontRenderContext frc) - { - this.extents = extents; - this.codes = codes; - this.font = font; - this.fontRenderContext = frc; - - allLogical = new Rectangle2D.Double(); - allVisual = new Rectangle2D.Double(); - - for (int i = 0; i < codes.length; ++i) - { - allLogical.add (new Rectangle2D.Double(extents[10*i ] + extents[10*i + 8], - extents[10*i + 1] + extents[10*i + 9], - extents[10*i + 2], - extents[10*i + 3])); - - allVisual.add (new Rectangle2D.Double(extents[10*i + 4] + extents[10*i + 8], - extents[10*i + 5] + extents[10*i + 9], - extents[10*i + 6], - extents[10*i + 7])); - } - } - - /* - geometric notes: - - the FRC contains a mapping from points -> pixels. - - typographics points are typically 1/72 of an inch. - - pixel displays are often around 72 dpi. - - so the FRC can get away with using an identity transform on a screen, - often. behavior is documented by sun to fall back to an identity - transform if the internal transformation is null. - - coordinates coming up from pango are expressed as floats -- in device - space, so basically pixels-with-fractional-bits -- derived from their - storage format in pango (1024ths of pixels). - - it is not clear from the javadocs whether the results of methods like - getGlyphPositions ought to return coordinates in device space, or - "point" space, or what. for now I'm returning them in device space. - - */ - - public double[] getExtents() - { - return extents; - } - - public int[] getCodes() - { - return codes; - } - - public Font getFont () - { - return font; - } - - public FontRenderContext getFontRenderContext () - { - return fontRenderContext; - } - - public int getGlyphCharIndex (int glyphIndex) - { - // FIXME: currently pango does not provide glyph-by-glyph - // reverse mapping information, so we assume a broken 1:1 - // glyph model here. This is plainly wrong. - return glyphIndex; - } - - public int[] getGlyphCharIndices (int beginGlyphIndex, - int numEntries, - int[] codeReturn) - { - int ix[] = codeReturn; - if (ix == null) - ix = new int[numEntries]; - - for (int i = 0; i < numEntries; i++) - ix[i] = getGlyphCharIndex (beginGlyphIndex + i); - return ix; - } - - public int getGlyphCode (int glyphIndex) - { - return codes[glyphIndex]; - } - - public int[] getGlyphCodes (int beginGlyphIndex, int numEntries, - int[] codeReturn) - { - if (codeReturn == null) - codeReturn = new int[numEntries]; - - System.arraycopy(codes, beginGlyphIndex, codeReturn, 0, numEntries); - return codeReturn; - } - - public Shape getGlyphLogicalBounds (int i) - { - return new Rectangle2D.Double (extents[8*i], extents[8*i + 1], - extents[8*i + 2], extents[8*i + 3]); - } - - public GlyphMetrics getGlyphMetrics (int i) - { - // FIXME: pango does not yield vertical layout information at the - // moment. - - boolean is_horizontal = true; - double advanceX = extents[8*i + 2]; // "logical width" == advanceX - double advanceY = 0; - - return new GlyphMetrics (is_horizontal, - (float) advanceX, (float) advanceY, - (Rectangle2D) getGlyphVisualBounds(i), - GlyphMetrics.STANDARD); - } - - public Shape getGlyphOutline (int glyphIndex) - { - throw new UnsupportedOperationException (); - } - - public Shape getGlyphOutline (int glyphIndex, float x, float y) - { - throw new UnsupportedOperationException (); - } - - public Rectangle getGlyphPixelBounds (int i, - FontRenderContext renderFRC, - float x, float y) - { - return new Rectangle((int) x, (int) y, - (int) extents[8*i + 6], (int) extents[8*i + 7]); - } - - public Point2D getGlyphPosition (int i) - { - return new Point2D.Double (extents[10*i + 8], - extents[10*i + 9]); - } - - public float[] getGlyphPositions (int beginGlyphIndex, - int numEntries, - float[] positionReturn) - { - float fx[] = positionReturn; - if (fx == null) - fx = new float[numEntries * 2]; - - for (int i = 0; i < numEntries; ++i) - { - fx[2*i ] = (float) extents[10*i + 8]; - fx[2*i + 1] = (float) extents[10*i + 9]; - } - return fx; - } - - public AffineTransform getGlyphTransform (int glyphIndex) - { - // Glyphs don't have independent transforms in these simple glyph - // vectors; docs specify null is an ok return here. - return null; - } - - public Shape getGlyphVisualBounds (int i) - { - return new Rectangle2D.Double(extents[8*i + 4], extents[8*i + 5], - extents[8*i + 6], extents[8*i + 7]); - } - - public int getLayoutFlags () - { - return 0; - } - - public Rectangle2D getLogicalBounds () - { - return allLogical; - } - - public int getNumGlyphs () - { - return codes.length; - } - - public Shape getOutline () - { - throw new UnsupportedOperationException (); - } - - public Rectangle getPixelBounds (FontRenderContext renderFRC, - float x, float y) - { - return new Rectangle((int)x, - (int)y, - (int) allVisual.getWidth(), - (int) allVisual.getHeight()); - } - - public Rectangle2D getVisualBounds () - { - return allVisual; - } - - public void performDefaultLayout () - { - } - - public void setGlyphPosition (int i, Point2D newPos) - { - extents[8*i ] = newPos.getX(); - extents[8*i + 1] = newPos.getY(); - - extents[8*i + 4] = newPos.getX(); - extents[8*i + 5] = newPos.getY(); - } - - public void setGlyphTransform (int glyphIndex, - AffineTransform newTX) - { - // not yet.. maybe not ever? - throw new UnsupportedOperationException (); - } - - public boolean equals(GlyphVector gv) - { - if (gv == null) - return false; - - if (! (gv instanceof GdkGlyphVector)) - return false; - - GdkGlyphVector ggv = (GdkGlyphVector) gv; - - if ((ggv.codes.length != this.codes.length) - || (ggv.extents.length != this.extents.length)) - return false; - - if ((ggv.font == null && this.font != null) - || (ggv.font != null && this.font == null) - || (!ggv.font.equals(this.font))) - return false; - - if ((ggv.fontRenderContext == null && this.fontRenderContext != null) - || (ggv.fontRenderContext != null && this.fontRenderContext == null) - || (!ggv.fontRenderContext.equals(this.fontRenderContext))) - return false; - - for (int i = 0; i < ggv.codes.length; ++i) - if (ggv.codes[i] != this.codes[i]) - return false; - - for (int i = 0; i < ggv.extents.length; ++i) - if (ggv.extents[i] != this.extents[i]) - return false; - - return true; - } - - public GlyphJustificationInfo getGlyphJustificationInfo(int idx) - { - throw new UnsupportedOperationException (); - } - - public Shape getOutline(float x, float y) - { - throw new UnsupportedOperationException (); - } - -} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java deleted file mode 100644 index 50066ff..0000000 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java +++ /dev/null @@ -1,494 +0,0 @@ -/* GdkGraphics.java - Copyright (C) 1998, 1999, 2002, 2005 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.gtk; - -import gnu.classpath.Configuration; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Toolkit; -import java.awt.image.ImageObserver; -import java.text.AttributedCharacterIterator; - -public class GdkGraphics extends Graphics -{ - static - { - System.loadLibrary("gtkpeer"); - - initStaticState (); - } - - static native void initStaticState(); - private final int native_state = GtkGenericPeer.getUniqueInteger (); - - Color color, xorColor; - GtkComponentPeer component; - Font font = new Font ("Dialog", Font.PLAIN, 12); - Rectangle clip; - GtkImage image; - - int xOffset = 0; - int yOffset = 0; - - static final int GDK_COPY = 0, GDK_XOR = 2; - - native void initState (GtkComponentPeer component); - native void initStateUnlocked (GtkComponentPeer component); - native void initState (int width, int height); - native void initFromImage (GtkImage image); - native void nativeCopyState (GdkGraphics g); - - /** - * A cached instance that is used by {@link #create} in order to avoid - * massive allocation of graphics contexts. - */ - GdkGraphics cached = null; - - /** - * A link to the parent context. This is used in {@link #dispose} to put - * this graphics context into the cache. - */ - GdkGraphics parent = null; - - GdkGraphics (GdkGraphics g) - { - parent = g; - copyState (g); - } - - GdkGraphics (int width, int height) - { - initState (width, height); - color = Color.black; - clip = new Rectangle (0, 0, width, height); - font = new Font ("Dialog", Font.PLAIN, 12); - } - - GdkGraphics (GtkImage image) - { - this.image = image; - initFromImage (image); - color = Color.black; - clip = new Rectangle (0, 0, - image.getWidth(null), image.getHeight(null)); - font = new Font ("Dialog", Font.PLAIN, 12); - } - - GdkGraphics (GtkComponentPeer component) - { - this.component = component; - color = Color.black; - - if (component.isRealized ()) - initComponentGraphics (); - else - connectSignals (component); - } - - void initComponentGraphics () - { - initState (component); - color = component.awtComponent.getForeground (); - if (color == null) - color = Color.BLACK; - Dimension d = component.awtComponent.getSize (); - clip = new Rectangle (0, 0, d.width, d.height); - } - - // called back by native side: realize_cb - void initComponentGraphicsUnlocked () - { - initStateUnlocked (component); - color = component.awtComponent.getForeground (); - if (color == null) - color = Color.BLACK; - Dimension d = component.awtComponent.getSize (); - clip = new Rectangle (0, 0, d.width, d.height); - } - - native void connectSignals (GtkComponentPeer component); - - public native void clearRect(int x, int y, int width, int height); - - public void clipRect (int x, int y, int width, int height) - { - if (component != null && ! component.isRealized ()) - return; - - clip = clip.intersection (new Rectangle (x, y, width, height)); - setClipRectangle (clip.x, clip.y, clip.width, clip.height); - } - - public native void copyArea(int x, int y, int width, int height, - int dx, int dy); - - /** - * Creates a copy of this GdkGraphics instance. This implementation can - * reuse a cached instance to avoid massive instantiation of Graphics objects - * during painting. - * - * @return a copy of this graphics context - */ - public Graphics create() - { - GdkGraphics copy = cached; - if (copy == null) - copy = new GdkGraphics(this); - else - { - copy.copyState(this); - cached = null; - } - return copy; - } - - public native void nativeDispose(); - - /** - * Disposes this graphics object. This puts this graphics context into the - * cache of its parent graphics if there is one. - */ - public void dispose() - { - if (parent != null) - { - parent.cached = this; - parent = null; - } - else - nativeDispose(); - } - - /** - * This is called when this object gets finalized by the garbage collector. - * In addition to {@link Graphics#finalize()} this calls nativeDispose() to - * make sure the native resources are freed before the graphics context is - * thrown away. - */ - public void finalize() - { - super.finalize(); - nativeDispose(); - } - - public boolean drawImage (Image img, int x, int y, - Color bgcolor, ImageObserver observer) - { - if (img != null) - return drawImage(img, x, y, img.getWidth(null), img.getHeight(null), - bgcolor, observer); - return false; - } - - public boolean drawImage (Image img, int x, int y, ImageObserver observer) - { - return drawImage (img, x, y, null, observer); - } - - public boolean drawImage(Image img, int x, int y, int width, int height, - Color bgcolor, ImageObserver observer) - { - if (img != null) - { - if (img instanceof GtkImage) - return ((GtkImage) img).drawImage(this, x, y, width, height, bgcolor, - observer); - return (new GtkImage(img.getSource())).drawImage(this, x, y, width, - height, bgcolor, - observer); - } - return false; - } - - public boolean drawImage (Image img, int x, int y, int width, int height, - ImageObserver observer) - { - return drawImage (img, x, y, width, height, null, observer); - } - - public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, - int sx1, int sy1, int sx2, int sy2, - Color bgcolor, ImageObserver observer) - { - if (img != null) - { - if (img instanceof GtkImage) - return ((GtkImage) img).drawImage(this, dx1, dy1, dx2, dy2, sx1, sy1, - sx2, sy2, bgcolor, observer); - return (new GtkImage(img.getSource())).drawImage(this, dx1, dy1, dx2, - dy2, sx1, sy1, sx2, - sy2, bgcolor, observer); - } - return false; - } - - public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, - int sx1, int sy1, int sx2, int sy2, - ImageObserver observer) - { - return drawImage (img, dx1, dy1, dx2, dy2, - sx1, sy1, sx2, sy2, - null, observer); - } - - public native void drawLine(int x1, int y1, int x2, int y2); - - public native void drawArc(int x, int y, int width, int height, - int startAngle, int arcAngle); - public native void fillArc(int x, int y, int width, int height, - int startAngle, int arcAngle); - public native void drawOval(int x, int y, int width, int height); - public native void fillOval(int x, int y, int width, int height); - - public native void drawPolygon(int[] xPoints, int[] yPoints, int nPoints); - public native void fillPolygon(int[] xPoints, int[] yPoints, int nPoints); - - public native void drawPolyline(int[] xPoints, int[] yPoints, int nPoints); - - public native void drawRect(int x, int y, int width, int height); - public native void fillRect(int x, int y, int width, int height); - - GdkFontPeer getFontPeer() - { - return (GdkFontPeer) getFont().getPeer(); - } - - native void drawString (GdkFontPeer f, String str, int x, int y); - public void drawString (String str, int x, int y) - { - drawString(getFontPeer(), str, x, y); - } - - public void drawString (AttributedCharacterIterator ci, int x, int y) - { - throw new Error ("not implemented"); - } - - public void drawRoundRect(int x, int y, int width, int height, - int arcWidth, int arcHeight) - { - if (arcWidth > width) - arcWidth = width; - if (arcHeight > height) - arcHeight = height; - - int xx = x + width - arcWidth; - int yy = y + height - arcHeight; - - drawArc (x, y, arcWidth, arcHeight, 90, 90); - drawArc (xx, y, arcWidth, arcHeight, 0, 90); - drawArc (xx, yy, arcWidth, arcHeight, 270, 90); - drawArc (x, yy, arcWidth, arcHeight, 180, 90); - - int y1 = y + arcHeight / 2; - int y2 = y + height - arcHeight / 2; - drawLine (x, y1, x, y2); - drawLine (x + width, y1, x + width, y2); - - int x1 = x + arcWidth / 2; - int x2 = x + width - arcWidth / 2; - drawLine (x1, y, x2, y); - drawLine (x1, y + height, x2, y + height); - } - - public void fillRoundRect (int x, int y, int width, int height, - int arcWidth, int arcHeight) - { - if (arcWidth > width) - arcWidth = width; - if (arcHeight > height) - arcHeight = height; - - int xx = x + width - arcWidth; - int yy = y + height - arcHeight; - - fillArc (x, y, arcWidth, arcHeight, 90, 90); - fillArc (xx, y, arcWidth, arcHeight, 0, 90); - fillArc (xx, yy, arcWidth, arcHeight, 270, 90); - fillArc (x, yy, arcWidth, arcHeight, 180, 90); - - fillRect (x, y + arcHeight / 2, width, height - arcHeight + 1); - fillRect (x + arcWidth / 2, y, width - arcWidth + 1, height); - } - - public Shape getClip () - { - return getClipBounds (); - } - - public Rectangle getClipBounds () - { - if (clip == null) - return null; - else - return clip.getBounds(); - } - - public Color getColor () - { - return color; - } - - public Font getFont () - { - return font; - } - - public FontMetrics getFontMetrics (Font font) - { - // Get the font metrics through GtkToolkit to take advantage of - // the metrics cache. - return Toolkit.getDefaultToolkit().getFontMetrics (font); - } - - native void setClipRectangle (int x, int y, int width, int height); - - public void setClip (int x, int y, int width, int height) - { - if ((component != null && ! component.isRealized ()) - || clip == null) - return; - - clip.x = x; - clip.y = y; - clip.width = width; - clip.height = height; - - setClipRectangle (x, y, width, height); - } - - public void setClip (Rectangle clip) - { - setClip (clip.x, clip.y, clip.width, clip.height); - } - - public void setClip (Shape clip) - { - if (clip == null) - { - // Reset clipping. - Dimension d = component.awtComponent.getSize(); - setClip(new Rectangle (0, 0, d.width, d.height)); - } - else - setClip(clip.getBounds()); - } - - private native void setFGColor(int red, int green, int blue); - - public void setColor (Color c) - { - if (c == null) - color = Color.BLACK; - else - color = c; - - if (xorColor == null) /* paint mode */ - setFGColor (color.getRed (), color.getGreen (), color.getBlue ()); - else /* xor mode */ - setFGColor (color.getRed () ^ xorColor.getRed (), - color.getGreen () ^ xorColor.getGreen (), - color.getBlue () ^ xorColor.getBlue ()); - } - - public void setFont (Font font) - { - if (font != null) - this.font = font; - } - - native void setFunction (int gdk_func); - - public void setPaintMode () - { - xorColor = null; - - setFunction (GDK_COPY); - setFGColor (color.getRed (), color.getGreen (), color.getBlue ()); - } - - public void setXORMode (Color c) - { - xorColor = c; - - setFunction (GDK_XOR); - setFGColor (color.getRed () ^ xorColor.getRed (), - color.getGreen () ^ xorColor.getGreen (), - color.getBlue () ^ xorColor.getBlue ()); - } - - public native void translateNative(int x, int y); - - public void translate (int x, int y) - { - if (component != null && ! component.isRealized ()) - return; - - clip.x -= x; - clip.y -= y; - - translateNative (x, y); - } - - /** - * Copies over the state of another GdkGraphics to this instance. This is - * used by the {@link #GdkGraphics(GdkGraphics)} constructor and the - * {@link #create()} method. - * - * @param g the GdkGraphics object to copy the state from - */ - private void copyState(GdkGraphics g) - { - color = g.color; - xorColor = g.xorColor; - font = g.font; - if (font == null) - font = new Font ("Dialog", Font.PLAIN, 12); - clip = new Rectangle (g.clip); - component = g.component; - nativeCopyState(g); - } -} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java index 6cf7310..147f8f3 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java @@ -1,5 +1,5 @@ /* GdkGraphicsConfiguration.java -- describes characteristics of graphics - Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -42,26 +42,33 @@ import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.ImageCapabilities; import java.awt.Rectangle; -import java.awt.Toolkit; +import java.awt.Transparency; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; import java.awt.image.VolatileImage; public class GdkGraphicsConfiguration extends GraphicsConfiguration { GdkScreenGraphicsDevice gdkScreenGraphicsDevice; - ColorModel cm; - Rectangle bounds; + + ColorModel opaqueColorModel; + ColorModel bitmaskColorModel; + + ColorModel translucentColorModel; + public GdkGraphicsConfiguration(GdkScreenGraphicsDevice dev) { - this.gdkScreenGraphicsDevice = dev; - cm = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getColorModel(); - bounds = ((GtkToolkit) Toolkit.getDefaultToolkit()).getBounds(); + gdkScreenGraphicsDevice = dev; + + opaqueColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0); + bitmaskColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0x1000000); + translucentColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000); } public GraphicsDevice getDevice() @@ -94,12 +101,21 @@ public class GdkGraphicsConfiguration public ColorModel getColorModel() { - return cm; + return opaqueColorModel; } public ColorModel getColorModel(int transparency) { - return getColorModel(); + switch (transparency) + { + case Transparency.OPAQUE: + return opaqueColorModel; + case Transparency.BITMASK: + return bitmaskColorModel; + default: + case Transparency.TRANSLUCENT: + return translucentColorModel; + } } public AffineTransform getDefaultTransform() @@ -116,7 +132,7 @@ public class GdkGraphicsConfiguration public Rectangle getBounds() { - return bounds; + return gdkScreenGraphicsDevice.getBounds(); } public BufferCapabilities getBufferCapabilities() @@ -133,8 +149,8 @@ public class GdkGraphicsConfiguration public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) { - // FIXME: implement - return null; + // FIXME: support the transparency argument + return new GtkVolatileImage(width, height); } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java index 4b0b5d3..e1c076c 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -1,5 +1,5 @@ /* GdkGraphicsEnvironment.java -- information about the graphics environment - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,33 +43,80 @@ import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; -import java.awt.Toolkit; import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; import java.util.Locale; public class GdkGraphicsEnvironment extends GraphicsEnvironment { + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private GdkScreenGraphicsDevice defaultDevice; + + private GdkScreenGraphicsDevice[] devices; + + static + { + System.loadLibrary("gtkpeer"); + + initStaticState (); + } + + static native void initStaticState(); + public GdkGraphicsEnvironment () { + nativeInitState(); } + + native void nativeInitState(); public GraphicsDevice[] getScreenDevices () { - // FIXME: Support multiple screens, since GDK can. - return new GraphicsDevice[] { new GdkScreenGraphicsDevice (this) }; + if (devices == null) + { + devices = nativeGetScreenDevices(); + } + + return (GraphicsDevice[]) devices.clone(); } + + private native GdkScreenGraphicsDevice[] nativeGetScreenDevices(); public GraphicsDevice getDefaultScreenDevice () { if (GraphicsEnvironment.isHeadless ()) throw new HeadlessException (); - - return new GdkScreenGraphicsDevice (this); + + // GCJ LOCAL: workaround a GCJ problem accessing + // GdkGraphicsEnvironment.class + try + { + synchronized (Class.forName ("gnu.java.awt.peer.gtk.GdkGraphicsEnvironment")) + { + if (defaultDevice == null) + { + defaultDevice = nativeGetDefaultScreenDevice(); + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + return defaultDevice; } + + private native GdkScreenGraphicsDevice nativeGetDefaultScreenDevice(); public Graphics2D createGraphics (BufferedImage image) { - return new GdkGraphics2D (image); + DataBuffer db = image.getRaster().getDataBuffer(); + if(db instanceof CairoSurface) + return ((CairoSurface)db).getGraphics(); + + return new BufferedImageGraphics( image ); } private native int nativeGetNumFontFamilies(); @@ -80,20 +127,21 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment throw new java.lang.UnsupportedOperationException (); } - public String[] getAvailableFontFamilyNames () - { - String[] family_names; - int array_size; + public String[] getAvailableFontFamilyNames () + { + String[] family_names; + int array_size; - array_size = nativeGetNumFontFamilies(); - family_names = new String[array_size]; + array_size = nativeGetNumFontFamilies(); + family_names = new String[array_size]; - nativeGetFontFamilies(family_names); - return family_names; - } + nativeGetFontFamilies(family_names); + return family_names; + } public String[] getAvailableFontFamilyNames (Locale l) { throw new java.lang.UnsupportedOperationException (); } + } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java index 2e3eee4..58b2dec 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -247,12 +247,23 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder public static ImageFormatSpec registerFormat(String name, boolean writable) { ImageFormatSpec ifs = new ImageFormatSpec(name, writable); - synchronized(GdkPixbufDecoder.class) + + // GCJ LOCAL: workaround a GCJ problem accessing + // GdkPixbufDecoder.class + try + { + synchronized(Class.forName ("gnu.java.awt.peer.gtk.GdkPixbufDecoder")) { if (imageFormatSpecs == null) imageFormatSpecs = new ArrayList(); imageFormatSpecs.add(ifs); } + } + catch (Exception e) + { + e.printStackTrace(); + } + return ifs; } @@ -502,19 +513,19 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder int width = ras.getWidth(); int height = ras.getHeight(); ColorModel model = image.getColorModel(); - int[] pixels = GdkGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras); + int[] pixels = CairoGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras); if (pixels == null) { - BufferedImage img = new BufferedImage(width, height, - (model != null && model.hasAlpha() ? - BufferedImage.TYPE_INT_ARGB - : BufferedImage.TYPE_INT_RGB)); + BufferedImage img; + if(model != null && model.hasAlpha()) + img = CairoSurface.getBufferedImage(width, height); + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); int[] pix = new int[4]; for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix))); - pixels = GdkGraphics2D.findSimpleIntegerArray (img.getColorModel(), + pixels = CairoGraphics2D.findSimpleIntegerArray (img.getColorModel(), img.getRaster()); model = img.getColorModel(); } @@ -584,9 +595,10 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder if (bufferedImage == null) { - bufferedImage = new BufferedImage (width, height, (model != null && model.hasAlpha() ? - BufferedImage.TYPE_INT_ARGB - : BufferedImage.TYPE_INT_RGB)); + if(model != null && model.hasAlpha()) + bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); + else + bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); } int pixels2[]; @@ -680,43 +692,4 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder return getBufferedImage (); } } - - // remaining helper class and static method is a convenience for the Gtk - // peers, for loading a BufferedImage in off a disk file without going - // through the whole imageio system. - - public static BufferedImage createBufferedImage (String filename) - { - GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), - "png", // reader auto-detects, doesn't matter - new GdkPixbufDecoder (filename)); - return r.getBufferedImage (); - } - - public static BufferedImage createBufferedImage (URL u) - { - GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), - "png", // reader auto-detects, doesn't matter - new GdkPixbufDecoder (u)); - return r.getBufferedImage (); - } - - public static BufferedImage createBufferedImage (byte[] imagedata, int imageoffset, - int imagelength) - { - GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), - "png", // reader auto-detects, doesn't matter - new GdkPixbufDecoder (imagedata, - imageoffset, - imagelength)); - return r.getBufferedImage (); - } - - public static BufferedImage createBufferedImage (ImageProducer producer) - { - GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), "png" /* ignored */, null); - producer.startProduction(r); - return r.getBufferedImage (); - } - } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java index b5d1237..62116a3 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java @@ -1,5 +1,5 @@ /* GdkScreenGraphicsDevice.java -- information about a screen device - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,44 +38,110 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; -import java.awt.Dimension; import java.awt.DisplayMode; +import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import java.awt.Toolkit; +import java.awt.Rectangle; +import java.awt.Window; +import java.util.ArrayList; -public class GdkScreenGraphicsDevice extends GraphicsDevice +class GdkScreenGraphicsDevice extends GraphicsDevice { + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private Window fullscreenWindow; + + private boolean oldWindowDecorationState; + + private Rectangle oldWindowBounds; + + private Rectangle bounds; + + private GdkGraphicsConfiguration[] configurations; + + /** The <code>GdkGraphicsEnvironment</code> instance that created this + * <code>GdkScreenGraphicsDevice</code>. This is only needed for native + * methods which need to access the 'native_state' field storing a pointer + * to a GdkDisplay object. + */ GdkGraphicsEnvironment env; + + /** An identifier that is created by Gdk + */ + String idString; + + /** The display modes supported by this <code>GdkScreenGraphicsDevice</code>. + * If the array is <code>null</code> <code>nativeGetDisplayModes</code> has + * to be called. + */ + X11DisplayMode[] displayModes; - public GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) - { - super (); + /** The non-changeable display mode of this <code>GdkScreenGraphicsDevice + * </code>. This field gets initialized by the {@link #init()} method. If it + * is still <code>null</code> afterwards, the XRandR extension is available + * and display mode changes are possible. If it is non-null XRandR is not + * available, no display mode changes are possible and no other native + * method must be called. + */ + DisplayMode fixedDisplayMode; + + static + { + System.loadLibrary("gtkpeer"); + + initStaticState (); + } + + static native void initStaticState(); + + GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) + { + super(); env = e; + + configurations = new GdkGraphicsConfiguration[1]; + configurations[0] = new GdkGraphicsConfiguration(this); } + /** This method is called from the native side immediately after + * the constructor is run. + */ + void init() + { + fixedDisplayMode = nativeGetFixedDisplayMode(env); + } + + /** Depending on the availability of the XRandR extension the method returns + * the screens' non-changeable display mode or null, meaning that XRandR can + * handle display mode changes. + */ + native DisplayMode nativeGetFixedDisplayMode(GdkGraphicsEnvironment env); + public int getType () { + // Gdk manages only raster screens. return GraphicsDevice.TYPE_RASTER_SCREEN; } public String getIDstring () { - // FIXME: query X for this string - return "default GDK device ID string"; + if (idString == null) + idString = nativeGetIDString(); + + return idString; } + + private native String nativeGetIDString(); public GraphicsConfiguration[] getConfigurations () { - // FIXME: query X for the list of possible configurations - return new GraphicsConfiguration [] { new GdkGraphicsConfiguration(this) }; + return (GraphicsConfiguration[]) configurations.clone(); } - + public GraphicsConfiguration getDefaultConfiguration () { - - // FIXME: query X for default configuration - return new GdkGraphicsConfiguration(this); + return configurations[0]; } @@ -89,23 +155,193 @@ public class GdkScreenGraphicsDevice extends GraphicsDevice */ public DisplayMode getDisplayMode() { - // determine display mode - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - DisplayMode mode = new DisplayMode(dim.width, dim.height, 0, - DisplayMode.REFRESH_RATE_UNKNOWN); - return mode; + if (fixedDisplayMode != null) + return fixedDisplayMode; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + int index = nativeGetDisplayModeIndex(env); + int rate = nativeGetDisplayModeRate(env); + + return new DisplayMode(displayModes[index].width, + displayModes[index].height, + DisplayMode.BIT_DEPTH_MULTI, + rate); + } + + native int nativeGetDisplayModeIndex(GdkGraphicsEnvironment env); + + native int nativeGetDisplayModeRate(GdkGraphicsEnvironment env); + + public DisplayMode[] getDisplayModes() + { + if (fixedDisplayMode != null) + return new DisplayMode[] { fixedDisplayMode }; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + ArrayList list = new ArrayList(); + for(int i=0;i<displayModes.length;i++) + for(int j=0;j<displayModes[i].rates.length;j++) + list.add(new DisplayMode(displayModes[i].width, + displayModes[i].height, + DisplayMode.BIT_DEPTH_MULTI, + displayModes[i].rates[j])); + + return (DisplayMode[]) list.toArray(new DisplayMode[list.size()]); } + + native X11DisplayMode[] nativeGetDisplayModes(GdkGraphicsEnvironment env); /** - * This device does not yet support fullscreen exclusive mode, so this - * returns <code>false</code>. + * Real fullscreen exclusive mode is not supported. * * @return <code>false</code> * @since 1.4 */ public boolean isFullScreenSupported() { - return false; + return true; + } + + public boolean isDisplayChangeSupported() + { + return fixedDisplayMode == null; + } + + public void setDisplayMode(DisplayMode dm) + { + if (fixedDisplayMode != null) + throw new UnsupportedOperationException("Cannnot change display mode."); + + if (dm == null) + throw new IllegalArgumentException("DisplayMode must not be null."); + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + for (int i=0; i<displayModes.length; i++) + if (displayModes[i].width == dm.getWidth() + && displayModes[i].height == dm.getHeight()) + { + synchronized (this) + { + nativeSetDisplayMode(env, + i, + (short) dm.getRefreshRate()); + + bounds = null; + } + + return; + } + + throw new IllegalArgumentException("Mode not supported by this device."); + } + + native void nativeSetDisplayMode(GdkGraphicsEnvironment env, + int index, short rate); + + /** A class that simply encapsulates the X11 display mode data. + */ + static class X11DisplayMode + { + short[] rates; + int width; + int height; + + X11DisplayMode(int width, int height, short[] rates) + { + this.width = width; + this.height = height; + this.rates = rates; + } + + } + + public void setFullScreenWindow(Window w) + { + // Bring old fullscreen window back into its original state. + if (fullscreenWindow != null && w != fullscreenWindow) + { + if (fullscreenWindow instanceof Frame) + { + // Decoration state can only be switched when the peer is + // non-existent. That means we have to dispose the + // Frame. + Frame f = (Frame) fullscreenWindow; + if (oldWindowDecorationState != f.isUndecorated()) + { + f.dispose(); + f.setUndecorated(oldWindowDecorationState); + } + } + + fullscreenWindow.setBounds(oldWindowBounds); + + if (!fullscreenWindow.isVisible()) + fullscreenWindow.setVisible(true); + } + + // If applicable remove decoration, then maximize the window and + // bring it to the foreground. + if (w != null) + { + if (w instanceof Frame) + { + Frame f = (Frame) w; + oldWindowDecorationState = f.isUndecorated(); + if (!oldWindowDecorationState) + { + f.dispose(); + f.setUndecorated(true); + } + } + + oldWindowBounds = w.getBounds(); + + DisplayMode dm = getDisplayMode(); + + w.setBounds(0, 0, dm.getWidth(), dm.getHeight()); + + if (!w.isVisible()) + w.setVisible(true); + + w.requestFocus(); + w.toFront(); + + } + + fullscreenWindow = w; + } + + public Window getFullScreenWindow() + { + return fullscreenWindow; + } + + Rectangle getBounds() + { + synchronized(this) + { + if (bounds == null) + bounds = nativeGetBounds(); + } + + return bounds; } + + native Rectangle nativeGetBounds(); } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java index c5e751f..d6b3de8 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java @@ -75,13 +75,21 @@ public class GdkTextLayout initStaticState (); } private native void setText(String str); + private native void setFont(GdkFontPeer font); private native void getExtents(double[] inkExtents, double[] logExtents); private native void indexToPos(int idx, double[] pos); + private native void initState (); + private native void dispose (); + + private native void cairoDrawGdkTextLayout(CairoGraphics2D g, float x, float y); + static native void initStaticState(); + private final int native_state = GtkGenericPeer.getUniqueInteger (); + protected void finalize () { dispose (); @@ -97,6 +105,15 @@ public class GdkTextLayout initState(); attributedString = str; fontRenderContext = frc; + AttributedCharacterIterator aci = str.getIterator(); + char[] chars = new char[aci.getEndIndex() - aci.getBeginIndex()]; + for(int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) + chars[i] = aci.setIndex(i); + setText(new String(chars)); + + Object fnt = aci.getAttribute(TextAttribute.FONT); + if (fnt != null && fnt instanceof Font) + setFont( (GdkFontPeer) ((Font)fnt).getPeer() ); } protected class CharacterIteratorProxy @@ -199,60 +216,7 @@ public class GdkTextLayout public void draw (Graphics2D g2, float x, float y) { - if (g2 instanceof GdkGraphics2D) - { - // we share pango structures directly with GdkGraphics2D - // when legal - GdkGraphics2D gg2 = (GdkGraphics2D) g2; - gg2.drawGdkTextLayout(this, x, y); - } - else - { - // falling back to a rather tedious layout algorithm when - // not legal - AttributedCharacterIterator ci = attributedString.getIterator (); - CharacterIteratorProxy proxy = new CharacterIteratorProxy (ci); - Font defFont = g2.getFont (); - - /* Note: this implementation currently only interprets FONT text - * attributes. There is a reasonable argument to be made for some - * attributes being interpreted out here, where we have control of the - * Graphics2D and can construct or derive new fonts, and some - * attributes being interpreted by the GlyphVector itself. So far, for - * all attributes except FONT we do neither. - */ - - for (char c = ci.first (); - c != CharacterIterator.DONE; - c = ci.next ()) - { - proxy.begin = ci.getIndex (); - proxy.limit = ci.getRunLimit(TextAttribute.FONT); - if (proxy.limit <= proxy.begin) - continue; - - proxy.index = proxy.begin; - - Object fnt = ci.getAttribute(TextAttribute.FONT); - GlyphVector gv; - if (fnt instanceof Font) - gv = ((Font)fnt).createGlyphVector (fontRenderContext, proxy); - else - gv = defFont.createGlyphVector (fontRenderContext, proxy); - - g2.drawGlyphVector (gv, x, y); - - int n = gv.getNumGlyphs (); - for (int i = 0; i < n; ++i) - { - GlyphMetrics gm = gv.getGlyphMetrics (i); - if (gm.getAdvanceX() == gm.getAdvance ()) - x += gm.getAdvanceX (); - else - y += gm.getAdvanceY (); - } - } - } + cairoDrawGdkTextLayout((CairoGraphics2D)g2, x, y); } public TextHitInfo getStrongCaret (TextHitInfo hit1, diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java index 797d653..edfc9ce 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java @@ -45,7 +45,6 @@ import java.awt.peer.CanvasPeer; public class GtkCanvasPeer extends GtkComponentPeer implements CanvasPeer { native void create (); - native void realize (); public GtkCanvasPeer (Canvas c) { diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java index 1a85de5..625855f 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -109,14 +109,7 @@ public class GtkComponentPeer extends GtkGenericPeer native void gtkWidgetRequestFocus (); native void gtkWidgetDispatchKeyEvent (int id, long when, int mods, int keyCode, int keyLocation); - - native boolean isRealized (); - - void realize () - { - // Default implementation does nothing - } - + native void realize(); native void setNativeEventMask (); void create () @@ -149,6 +142,9 @@ public class GtkComponentPeer extends GtkGenericPeer setNativeEventMask (); + // This peer is guaranteed to have an X window upon construction. + // That is, native methods such as those in GdkGraphics can rely + // on this component's widget->window field being non-null. realize (); if (awtComponent.isCursorSet()) @@ -211,16 +207,7 @@ public class GtkComponentPeer extends GtkGenericPeer public Image createImage (int width, int height) { - Image image; - if (GtkToolkit.useGraphics2D ()) - image = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); - else - image = new GtkImage (width, height); - - Graphics g = image.getGraphics(); - g.setColor(getBackground()); - g.fillRect(0, 0, width, height); - return image; + return CairoSurface.getBufferedImage(width, height); } public void disable () @@ -247,10 +234,7 @@ public class GtkComponentPeer extends GtkGenericPeer // never return null. public Graphics getGraphics () { - if (GtkToolkit.useGraphics2D ()) - return new GdkGraphics2D (this); - else - return new GdkGraphics (this); + return ComponentGraphics.getComponentGraphics(this); } public Point getLocationOnScreen () @@ -713,7 +697,7 @@ public class GtkComponentPeer extends GtkGenericPeer // on which this component is displayed. public VolatileImage createVolatileImage (int width, int height) { - return new GtkVolatileImage (width, height); + return new GtkVolatileImage (this, width, height, null); } // Creates buffers used in a buffering strategy. @@ -723,7 +707,7 @@ public class GtkComponentPeer extends GtkGenericPeer // numBuffers == 2 implies double-buffering, meaning one back // buffer and one front buffer. if (numBuffers == 2) - backBuffer = new GtkVolatileImage(awtComponent.getWidth(), + backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(), awtComponent.getHeight(), caps.getBackBufferCapabilities()); else diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java index 5e5f1de..ef96518 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java @@ -57,14 +57,7 @@ import java.net.URL; import gnu.classpath.Pointer; /** - * GtkImage - wraps a GdkPixbuf or GdkPixmap. - * - * The constructor GtkImage(int, int) creates an 'off-screen' GdkPixmap, - * this can be drawn to (it's a GdkDrawable), and correspondingly, you can - * create a GdkGraphics object for it. - * - * This corresponds to the Image implementation returned by - * Component.createImage(int, int). + * GtkImage - wraps a GdkPixbuf. * * A GdkPixbuf is 'on-screen' and the gdk cannot draw to it, * this is used for the other constructors (and other createImage methods), and @@ -88,9 +81,10 @@ public class GtkImage extends Image boolean isLoaded; /** - * Pointer to the GdkPixbuf + * Pointer to the GdkPixbuf - + * don't change the name without changing the native code. */ - Pointer pixmap; + Pointer pixbuf; /** * Observer queue. @@ -98,11 +92,6 @@ public class GtkImage extends Image Vector observers; /** - * If offScreen is set, a GdkBitmap is wrapped and not a Pixbuf. - */ - boolean offScreen; - - /** * Error flag for loading. */ boolean errorLoading; @@ -122,71 +111,64 @@ public class GtkImage extends Image 0xFF000000); /** + * The singleton GtkImage that is returned on errors by GtkToolkit. + */ + private static GtkImage errorImage; + + /** + * Lock that should be held for all gdkpixbuf operations. We don't use + * the global gdk_threads_enter/leave functions in most places since + * most gdkpixbuf operations can be done in parallel to drawing and + * manipulating gtk widgets. + */ + static Object pixbufLock = new Object(); + + /** + * Allocate a PixBuf from a given ARGB32 buffer pointer. + */ + private native void initFromBuffer( long bufferPointer ); + + /** * Returns a copy of the pixel data as a java array. - * Should be called with the GdkPixbufDecoder.pixbufLock held. + * Should be called with the pixbufLock held. */ - private native int[] getPixels(); + native int[] getPixels(); /** * Sets the pixel data from a java array. - * Should be called with the GdkPixbufDecoder.pixbufLock held. + * Should be called with the pixbufLock held. */ private native void setPixels(int[] pixels); /** * Loads an image using gdk-pixbuf from a file. - * Should be called with the GdkPixbufDecoder.pixbufLock held. + * Should be called with the pixbufLock held. */ private native boolean loadPixbuf(String name); /** * Loads an image using gdk-pixbuf from data. - * Should be called with the GdkPixbufDecoder.pixbufLock held. + * Should be called with the pixbufLock held. */ private native boolean loadImageFromData(byte[] data); /** - * Allocates a Gtk Pixbuf or pixmap - * Should be called with the GdkPixbufDecoder.pixbufLock held. + * Allocates a Gtk Pixbuf + * Should be called with the pixbufLock held. */ - private native void createPixmap(); + private native void createPixbuf(); /** * Frees the above. - * Should be called with the GdkPixbufDecoder.pixbufLock held. - */ - private native void freePixmap(); - - /** - * Sets the pixmap to scaled copy of src image. hints are rendering hints. - * Should be called with the GdkPixbufDecoder.pixbufLock held. - */ - private native void createScaledPixmap(GtkImage src, int hints); - - /** - * Draws the image, optionally scaled and composited. - * Should be called with the GdkPixbufDecoder.pixbufLock held. - * Also acquires global gdk lock for drawing. + * Should be called with the pixbufLock held. */ - private native void drawPixelsScaled (GdkGraphics gc, - int bg_red, int bg_green, int bg_blue, - int x, int y, int width, int height, - boolean composite); + private native void freePixbuf(); /** - * Draws the image, optionally scaled flipped and composited. - * Should be called with the GdkPixbufDecoder.pixbufLock held. - * Also acquires global gdk lock for drawing. + * Sets the pixbuf to scaled copy of src image. hints are rendering hints. + * Should be called with the pixbufLock held. */ - private native void drawPixelsScaledFlipped (GdkGraphics gc, - int bg_red, int bg_green, - int bg_blue, - boolean flipX, boolean flipY, - int srcX, int srcY, - int srcWidth, int srcHeight, - int dstX, int dstY, - int dstWidth, int dstHeight, - boolean composite); + private native void createScaledPixbuf(GtkImage src, int hints); /** * Constructs a GtkImage from an ImageProducer. Asynchronity is handled in @@ -202,7 +184,6 @@ public class GtkImage extends Image source = producer; errorLoading = false; source.startProduction(new GtkImageConsumer(this, source)); - offScreen = false; } /** @@ -215,7 +196,6 @@ public class GtkImage extends Image { isLoaded = true; observers = null; - offScreen = false; props = new Hashtable(); errorLoading = false; } @@ -231,7 +211,7 @@ public class GtkImage extends Image try { String path = f.getCanonicalPath(); - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { if (loadPixbuf(f.getCanonicalPath()) != true) throw new IllegalArgumentException("Couldn't load image: " @@ -249,7 +229,6 @@ public class GtkImage extends Image isLoaded = true; observers = null; - offScreen = false; props = new Hashtable(); } @@ -261,7 +240,7 @@ public class GtkImage extends Image */ public GtkImage (byte[] data) { - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { if (loadImageFromData (data) != true) throw new IllegalArgumentException ("Couldn't load image."); @@ -269,7 +248,6 @@ public class GtkImage extends Image isLoaded = true; observers = null; - offScreen = false; props = new Hashtable(); errorLoading = false; } @@ -301,7 +279,7 @@ public class GtkImage extends Image throw new IllegalArgumentException ("Couldn't load image."); } byte[] array = baos.toByteArray(); - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { if (loadImageFromData(array) != true) throw new IllegalArgumentException ("Couldn't load image."); @@ -313,23 +291,6 @@ public class GtkImage extends Image } /** - * Constructs an empty GtkImage. - */ - public GtkImage (int width, int height) - { - this.width = width; - this.height = height; - props = new Hashtable(); - isLoaded = true; - observers = null; - offScreen = true; - synchronized(GdkPixbufDecoder.pixbufLock) - { - createPixmap(); - } - } - - /** * Constructs a scaled version of the src bitmap, using the GDK. */ private GtkImage (GtkImage src, int width, int height, int hints) @@ -339,12 +300,11 @@ public class GtkImage extends Image props = new Hashtable(); isLoaded = true; observers = null; - offScreen = false; // Use the GDK scaling method. - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { - createScaledPixmap(src, hints); + createScaledPixbuf(src, hints); } } @@ -354,19 +314,30 @@ public class GtkImage extends Image */ GtkImage (Pointer pixbuf) { - pixmap = pixbuf; - synchronized(GdkPixbufDecoder.pixbufLock) + this.pixbuf = pixbuf; + synchronized(pixbufLock) { createFromPixbuf(); } isLoaded = true; observers = null; - offScreen = false; props = new Hashtable(); } - // The singleton GtkImage that is returned on errors by GtkToolkit. - private static GtkImage errorImage; + /** + * Wraps a buffer with a GtkImage. + * + * @param bufferPointer a pointer to an ARGB32 buffer + */ + GtkImage(int width, int height, long bufferPointer) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + observers = null; + initFromBuffer( bufferPointer ); + } /** * Returns an empty GtkImage with the errorLoading flag set. @@ -385,7 +356,7 @@ public class GtkImage extends Image /** * Native helper function for constructor that takes a pixbuf Pointer. - * Should be called with the GdkPixbufDecoder.pixbufLock held. + * Should be called with the pixbufLock held. */ private native void createFromPixbuf(); @@ -407,9 +378,9 @@ public class GtkImage extends Image isLoaded = true; deliver(); - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { - createPixmap(); + createPixbuf(); setPixels(pixels); } } @@ -450,30 +421,28 @@ public class GtkImage extends Image return null; int[] pixels; - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized (pixbufLock) { - pixels = getPixels(); + if (!errorLoading) + pixels = getPixels(); + else + return null; } return new MemoryImageSource(width, height, nativeModel, pixels, 0, width); } /** - * Creates a GdkGraphics context for this pixmap. + * Does nothing. Should not be called. */ public Graphics getGraphics () { - if (!isLoaded) - return null; - if (offScreen) - return new GdkGraphics(this); - else - throw new IllegalAccessError("This method only works for off-screen" - +" Images."); + throw new IllegalAccessError("This method only works for off-screen" + +" Images."); } /** - * Returns a scaled instance of this pixmap. + * Returns a scaled instance of this pixbuf. */ public Image getScaledInstance(int width, int height, @@ -500,9 +469,9 @@ public class GtkImage extends Image { observers = new Vector(); isLoaded = false; - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { - freePixmap(); + freePixbuf(); } source.startProduction(new GtkImageConsumer(this, source)); } @@ -512,9 +481,9 @@ public class GtkImage extends Image { if (isLoaded) { - synchronized(GdkPixbufDecoder.pixbufLock) + synchronized(pixbufLock) { - freePixmap(); + freePixbuf(); } } } @@ -535,104 +504,6 @@ public class GtkImage extends Image return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; } - // Drawing methods //////////////////////////////////////////////// - - /** - * Draws an image with eventual scaling/transforming. - */ - public boolean drawImage (GdkGraphics g, int dx1, int dy1, int dx2, int dy2, - int sx1, int sy1, int sx2, int sy2, - Color bgcolor, ImageObserver observer) - { - if (addObserver(observer)) - return false; - - boolean flipX = (dx1 > dx2)^(sx1 > sx2); - boolean flipY = (dy1 > dy2)^(sy1 > sy2); - int dstWidth = Math.abs (dx2 - dx1); - int dstHeight = Math.abs (dy2 - dy1); - int srcWidth = Math.abs (sx2 - sx1); - int srcHeight = Math.abs (sy2 - sy1); - int srcX = (sx1 < sx2) ? sx1 : sx2; - int srcY = (sy1 < sy2) ? sy1 : sy2; - int dstX = (dx1 < dx2) ? dx1 : dx2; - int dstY = (dy1 < dy2) ? dy1 : dy2; - - // Clipping. This requires the dst to be scaled as well, - if (srcWidth > width) - { - dstWidth = (int)((double)dstWidth*((double)width/(double)srcWidth)); - srcWidth = width - srcX; - } - - if (srcHeight > height) - { - dstHeight = (int)((double)dstHeight*((double)height/(double)srcHeight)); - srcHeight = height - srcY; - } - - if (srcWidth + srcX > width) - { - dstWidth = (int)((double)dstWidth * (double)(width - srcX)/(double)srcWidth); - srcWidth = width - srcX; - } - - if (srcHeight + srcY > height) - { - dstHeight = (int)((double)dstHeight * (double)(width - srcY)/(double)srcHeight); - srcHeight = height - srcY; - } - - if ( this.width <= 0 || this.height <= 0 ) - return true; - - if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) - return true; - - synchronized(GdkPixbufDecoder.pixbufLock) - { - if(bgcolor != null) - drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (), - bgcolor.getBlue (), - flipX, flipY, - srcX, srcY, - srcWidth, srcHeight, - dstX, dstY, - dstWidth, dstHeight, - true); - else - drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY, - srcX, srcY, srcWidth, srcHeight, - dstX, dstY, dstWidth, dstHeight, - false); - } - return true; - } - - /** - * Draws an image to the GdkGraphics context, at (x,y) scaled to - * width and height, with optional compositing with a background color. - */ - public boolean drawImage (GdkGraphics g, int x, int y, int width, int height, - Color bgcolor, ImageObserver observer) - { - if (addObserver(observer)) - return false; - - if ( this.width <= 0 || this.height <= 0 ) - return true; - - synchronized(GdkPixbufDecoder.pixbufLock) - { - if(bgcolor != null) - drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (), - bgcolor.getBlue (), x, y, width, height, true); - else - drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false); - } - - return true; - } // Private methods //////////////////////////////////////////////// diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java index 4c41f97..688af00 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -78,31 +78,12 @@ import javax.imageio.spi.IIORegistry; this class. If getPeer() ever goes away, we can implement a hash table that will keep up with every window's peer, but for now this is faster. */ -/** - * This class accesses a system property called - * <tt>gnu.java.awt.peer.gtk.Graphics</tt>. If the property is defined and - * equal to "Graphics2D", the cairo-based GdkGraphics2D will be used in - * drawing contexts. Any other value will cause the older GdkGraphics - * object to be used. - */ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit { Hashtable containers = new Hashtable(); static EventQueue q; - static boolean useGraphics2dSet; - static boolean useGraphics2d; static Thread mainThread; - public static boolean useGraphics2D() - { - if (useGraphics2dSet) - return useGraphics2d; - useGraphics2d = System.getProperty("gnu.java.awt.peer.gtk.Graphics", - "Graphics").equals("Graphics2D"); - useGraphics2dSet = true; - return useGraphics2d; - } - static native void gtkInit(int portableNativeSync); static @@ -178,10 +159,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit Image image; try { - if (useGraphics2D()) - image = GdkPixbufDecoder.createBufferedImage(filename); - else - image = new GtkImage(filename); + image = CairoSurface.getBufferedImage( new GtkImage( filename ) ); } catch (IllegalArgumentException iae) { @@ -195,10 +173,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit Image image; try { - if (useGraphics2D()) - image = GdkPixbufDecoder.createBufferedImage(url); - else - image = new GtkImage(url); + image = CairoSurface.getBufferedImage( new GtkImage( url ) ); } catch (IllegalArgumentException iae) { @@ -209,13 +184,13 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public Image createImage (ImageProducer producer) { + if (producer == null) + return null; + Image image; try { - if (useGraphics2D()) - image = GdkPixbufDecoder.createBufferedImage(producer); - else - image = new GtkImage(producer); + image = CairoSurface.getBufferedImage( new GtkImage( producer ) ); } catch (IllegalArgumentException iae) { @@ -230,16 +205,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit Image image; try { - if (useGraphics2D()) - image = GdkPixbufDecoder.createBufferedImage(imagedata, - imageoffset, - imagelength); - else - { - byte[] datacopy = new byte[imagelength]; - System.arraycopy(imagedata, imageoffset, datacopy, 0, imagelength); - return new GtkImage(datacopy); - } + byte[] data = new byte[ imagelength ]; + System.arraycopy(imagedata, imageoffset, data, 0, imagelength); + image = CairoSurface.getBufferedImage( new GtkImage( data ) ); } catch (IllegalArgumentException iae) { @@ -256,7 +224,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit */ public ImageProducer createImageProducer(URL url) { - return new GdkPixbufDecoder(url); + return createImage( url ).getSource(); } /** @@ -568,13 +536,23 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit protected EventQueue getSystemEventQueueImpl() { - synchronized (GtkToolkit.class) + // GCJ LOCAL: workaround a GCJ problem accessing + // GtkToolkit.class + try + { + synchronized (Class.forName ("gnu.java.awt.peer.gtk.GtkToolkit")) { if (q == null) { q = new EventQueue(); } } + } + catch (Exception e) + { + e.printStackTrace(); + } + return q; } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java index 496090a..53bcd73 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java @@ -1,4 +1,4 @@ -/* GtkVolatileImage.java -- a hardware-accelerated image buffer +/* GtkVolatileImage.java -- wraps an X pixmap Copyright (C) 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.ImageCapabilities; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.image.BufferedImage; @@ -46,44 +47,68 @@ import java.awt.image.VolatileImage; public class GtkVolatileImage extends VolatileImage { - private int width; - private int height; + int width, height; private ImageCapabilities caps; - public GtkVolatileImage(int width, int height) - { - this(width, height, null); - } + /** + * Don't touch, accessed from native code. + */ + long nativePointer; - public GtkVolatileImage(int width, int height, ImageCapabilities caps) + native long init(GtkComponentPeer component, int width, int height); + + native void destroy(); + + native int[] getPixels(); + + native void copyArea( int x, int y, int w, int h, int dx, int dy ); + + native void drawVolatile( long ptr, int x, int y, int w, int h ); + + public GtkVolatileImage(GtkComponentPeer component, + int width, int height, ImageCapabilities caps) { this.width = width; this.height = height; this.caps = caps; + nativePointer = init( component, width, height ); } - // FIXME: should return a buffered image snapshot of the accelerated - // visual - public BufferedImage getSnapshot() + public GtkVolatileImage(int width, int height, ImageCapabilities caps) { - return null; + this(null, width, height, caps); } - public int getWidth() + public GtkVolatileImage(int width, int height) { - return width; + this(null, width, height, null); } - public int getHeight() + public void finalize() { - return height; + dispose(); + } + + public void dispose() + { + destroy(); + } + + public BufferedImage getSnapshot() + { + CairoSurface cs = new CairoSurface( width, height ); + cs.setPixels( getPixels() ); + return CairoSurface.getBufferedImage( cs ); + } + + public Graphics getGraphics() + { + return createGraphics(); } - // FIXME: should return a graphics wrapper around this image's - // visual public Graphics2D createGraphics() { - return null; + return new VolatileImageGraphics( this ); } public int validate(GraphicsConfiguration gc) @@ -101,18 +126,28 @@ public class GtkVolatileImage extends VolatileImage return caps; } - public synchronized Object getProperty (String name, ImageObserver observer) + public int getWidth() { - return null; + return width; + } + + public int getHeight() + { + return height; } - public synchronized int getWidth (ImageObserver observer) + public int getWidth(java.awt.image.ImageObserver observer) { return width; } - public synchronized int getHeight (ImageObserver observer) + public int getHeight(java.awt.image.ImageObserver observer) { return height; } + + public Object getProperty(String name, ImageObserver observer) + { + return null; + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java new file mode 100644 index 0000000..d5adfcf --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java @@ -0,0 +1,122 @@ +/* VolatileImageGraphics.java + 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.gtk; + +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.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; +import java.util.WeakHashMap; + +public class VolatileImageGraphics extends ComponentGraphics +{ + private GtkVolatileImage owner; + + public VolatileImageGraphics(GtkVolatileImage img) + { + this.owner = img; + cairo_t = initFromVolatile( owner.nativePointer, img.width, img.height ); + setup( cairo_t ); + setClip( new Rectangle( 0, 0, img.width, img.height) ); + } + + private VolatileImageGraphics(VolatileImageGraphics copy) + { + this.owner = copy.owner; + initFromVolatile( owner.nativePointer, owner.width, owner.height ); + setClip( new Rectangle( 0, 0, owner.width, owner.height) ); + copy( copy, cairo_t ); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + owner.copyArea(x, y, width, height, dx, dy); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return null; + } + + public Graphics create() + { + return new VolatileImageGraphics( this ); + } + + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + if( img instanceof GtkVolatileImage ) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, + ((GtkVolatileImage)img).width, + ((GtkVolatileImage)img).height ); + return true; + } + return super.drawImage( img, x, y, observer ); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + if( img instanceof GtkVolatileImage ) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, width, height ); + return true; + } + return super.drawImage( img, x, y, width, height, observer ); + } +} + diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java index 04ca729..a51b758 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java @@ -62,7 +62,7 @@ public interface SwingComponent /** * Handles a mouse event. This is usually forwarded to - * {@link Component#processMouseMotionEvent(MouseEvent)} of the swing + * {@link java.awt.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 Component#processMouseEvent(MouseEvent)} of the swing + * {@link java.awt.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 Component#processKeyEvent(KeyEvent)} of the swing + * {@link java.awt.Component#processKeyEvent(KeyEvent)} of the swing * component. * * @param ev the key event diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java index 5d484e0..f60c8e9 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -48,6 +48,8 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; @@ -98,8 +100,9 @@ public class SwingComponentPeer /** * Creates a SwingComponentPeer instance. Subclasses are expected to call - * this constructor and thereafter call {@link #init(Component, JComponent)} - * 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() { @@ -164,9 +167,12 @@ public class SwingComponentPeer */ public Image createImage(int width, int height) { - Component parent = awtComponent.getParent(); - ComponentPeer parentPeer = parent.getPeer(); - return parentPeer.createImage(width, height); + GraphicsEnvironment graphicsEnv = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = graphicsEnv.getDefaultScreenDevice(); + GraphicsConfiguration conf = dev.getDefaultConfiguration(); + Image image = conf.createCompatibleImage(width, height); + return image; } /** @@ -442,20 +448,6 @@ public class SwingComponentPeer return retVal; } - /** - * Prepares an image for rendering on this component. This is called by - * {@link Component#prepareImage(Image, int, int, ImageObserver)}. - * - * @param img the image to prepare - * @param width the desired width of the rendered image - * @param height the desired height of the rendered image - * @param ob the image observer to be notified of updates in the preparation - * process - * - * @return <code>true</code> if the image has been fully prepared, - * <code>false</code> otherwise (in which case the image observer - * receives updates) - */ public void paint(Graphics graphics) { // FIXME: I don't know what this method is supposed to do. @@ -478,8 +470,17 @@ public class SwingComponentPeer public boolean prepareImage(Image img, int width, int height, ImageObserver ob) { Component parent = awtComponent.getParent(); - ComponentPeer parentPeer = parent.getPeer(); - return parentPeer.prepareImage(img, width, height, ob); + boolean res; + if(parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + res = parentPeer.prepareImage(img, width, height, ob); + } + else + { + res = Toolkit.getDefaultToolkit().prepareImage(img, width, height, ob); + } + return res; } public void print(Graphics graphics) diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java index 0b2fb99..f433e1b 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java @@ -92,7 +92,12 @@ public class SwingContainerPeer */ public Insets getInsets() { - return insets(); + Insets retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getInsets(); + else + retVal = new Insets(0, 0, 0, 0); + return retVal; } /** @@ -209,6 +214,8 @@ public class SwingContainerPeer protected void handleMouseEvent(MouseEvent ev) { Component comp = awtComponent.getComponentAt(ev.getPoint()); + if(comp == null) + comp = awtComponent; if (comp != null) { ComponentPeer peer = comp.getPeer(); diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java index fea1b50..0d5a02d 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java @@ -53,9 +53,9 @@ import java.awt.peer.FramePeer; * As a minimum, a subclass must implement all the remaining abstract methods * as well as the following methods: * <ul> - * <li>{@link ComponentPeer#getLocationOnScreen()}</li> - * <li>{@link ComponentPeer#getGraphics()}</li> - * <li>{@link ComponentPeer#createImage(int, int)}</li> + * <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li> + * <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li> + * <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li> * </ul> * * @author Roman Kennke (kennke@aicas.com) diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java index bd9dcd7..0033efb 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java @@ -174,7 +174,7 @@ public class SwingMenuBarPeer /** * Adds a help menu to the menu bar. * - * @param m the menu to add + * @param menu the menu to add */ public void addHelpMenu(Menu menu) { diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java index a4c6d82..0c3b4e7 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java @@ -283,7 +283,7 @@ public class SwingTextFieldPeer * @param startPos the start index of the selection * @param endPos the start index of the selection */ - public void select(int start_pos, int endPos) + public void select(int startPos, int endPos) { // TODO: Must be implemented. } diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java index 2f89795..43a509b 100644 --- a/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java @@ -48,9 +48,9 @@ import java.awt.peer.WindowPeer; * As a minimum, a subclass must implement all the remaining abstract methods * as well as the following methods: * <ul> - * <li>{@link ComponentPeer#getLocationOnScreen()}</li> - * <li>{@link ComponentPeer#getGraphics()}</li> - * <li>{@link ComponentPeer#createImage(int, int)}</li> + * <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li> + * <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li> + * <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li> * </ul> * * @author Roman Kennke (kennke@aicas.com) |