summaryrefslogtreecommitdiffstats
path: root/awt
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch)
tree35051494d2af230dce54d6b31c6af8fc24091316 /awt
downloadframeworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2
Initial Contribution
Diffstat (limited to 'awt')
-rw-r--r--awt/Android.mk31
-rw-r--r--awt/com/android/internal/awt/AndroidGraphics2D.java1354
-rw-r--r--awt/com/android/internal/awt/AndroidGraphicsConfiguration.java96
-rw-r--r--awt/com/android/internal/awt/AndroidGraphicsFactory.java87
-rw-r--r--awt/com/android/internal/awt/AndroidImageDecoder.java274
-rw-r--r--awt/com/android/internal/awt/AndroidJavaBlitter.java536
-rw-r--r--awt/com/android/internal/awt/AndroidNativeEventQueue.java75
-rw-r--r--awt/com/android/internal/awt/AndroidWTK.java88
-rw-r--r--awt/com/android/internal/awt/AwtFactory.java52
-rw-r--r--awt/com/android/internal/awt/ImageOutputStreamWrapper.java66
-rw-r--r--awt/java/awt/AWTEvent.java618
-rw-r--r--awt/java/awt/AWTException.java43
-rw-r--r--awt/java/awt/AWTKeyStroke.java678
-rw-r--r--awt/java/awt/AWTListenerList.java47
-rw-r--r--awt/java/awt/AWTPermission.java54
-rw-r--r--awt/java/awt/ActiveEvent.java36
-rw-r--r--awt/java/awt/Adjustable.java156
-rw-r--r--awt/java/awt/AlphaComposite.java315
-rw-r--r--awt/java/awt/BasicStroke.java2204
-rw-r--r--awt/java/awt/BufferCapabilities.java185
-rw-r--r--awt/java/awt/Color.java881
-rw-r--r--awt/java/awt/Component.java6408
-rw-r--r--awt/java/awt/ComponentBehavior.java56
-rw-r--r--awt/java/awt/ComponentOrientation.java140
-rw-r--r--awt/java/awt/Composite.java47
-rw-r--r--awt/java/awt/CompositeContext.java49
-rw-r--r--awt/java/awt/Cursor.java372
-rw-r--r--awt/java/awt/Dimension.java185
-rw-r--r--awt/java/awt/Dispatcher.java723
-rw-r--r--awt/java/awt/DisplayMode.java147
-rw-r--r--awt/java/awt/Event.java479
-rw-r--r--awt/java/awt/EventDispatchThread.java118
-rw-r--r--awt/java/awt/EventQueue.java310
-rw-r--r--awt/java/awt/EventQueueCore.java253
-rw-r--r--awt/java/awt/Font.java1500
-rw-r--r--awt/java/awt/FontFormatException.java41
-rw-r--r--awt/java/awt/FontMetrics.java456
-rw-r--r--awt/java/awt/GradientPaint.java219
-rw-r--r--awt/java/awt/GradientPaintContext.java204
-rw-r--r--awt/java/awt/Graphics.java737
-rw-r--r--awt/java/awt/Graphics2D.java456
-rw-r--r--awt/java/awt/GraphicsConfiguration.java217
-rw-r--r--awt/java/awt/GraphicsDevice.java199
-rw-r--r--awt/java/awt/GraphicsEnvironment.java209
-rw-r--r--awt/java/awt/HeadlessException.java48
-rw-r--r--awt/java/awt/HeadlessGraphicsEnvironment.java69
-rw-r--r--awt/java/awt/HeadlessToolkit.java301
-rw-r--r--awt/java/awt/IllegalComponentStateException.java51
-rw-r--r--awt/java/awt/Image.java203
-rw-r--r--awt/java/awt/ImageCapabilities.java74
-rw-r--r--awt/java/awt/Insets.java165
-rw-r--r--awt/java/awt/ItemSelectable.java53
-rw-r--r--awt/java/awt/MenuComponent.java1041
-rw-r--r--awt/java/awt/MenuContainer.java56
-rw-r--r--awt/java/awt/ModalContext.java64
-rw-r--r--awt/java/awt/MouseDispatcher.java418
-rw-r--r--awt/java/awt/Paint.java52
-rw-r--r--awt/java/awt/PaintContext.java64
-rw-r--r--awt/java/awt/Point.java195
-rw-r--r--awt/java/awt/Polygon.java494
-rw-r--r--awt/java/awt/Rectangle.java686
-rw-r--r--awt/java/awt/RenderingHints.java601
-rw-r--r--awt/java/awt/Shape.java162
-rw-r--r--awt/java/awt/Stroke.java47
-rw-r--r--awt/java/awt/Toolkit.java1338
-rw-r--r--awt/java/awt/ToolkitImpl.java255
-rw-r--r--awt/java/awt/Transparency.java51
-rw-r--r--awt/java/awt/color/CMMException.java40
-rw-r--r--awt/java/awt/color/ColorSpace.java340
-rw-r--r--awt/java/awt/color/ICC_ColorSpace.java379
-rw-r--r--awt/java/awt/color/ICC_Profile.java1231
-rw-r--r--awt/java/awt/color/ICC_ProfileGray.java68
-rw-r--r--awt/java/awt/color/ICC_ProfileRGB.java122
-rw-r--r--awt/java/awt/color/ICC_ProfileStub.java173
-rw-r--r--awt/java/awt/color/ProfileDataException.java42
-rw-r--r--awt/java/awt/event/AWTEventListener.java30
-rw-r--r--awt/java/awt/event/AWTEventListenerProxy.java52
-rw-r--r--awt/java/awt/event/ActionEvent.java108
-rw-r--r--awt/java/awt/event/ActionListener.java29
-rw-r--r--awt/java/awt/event/AdjustmentEvent.java117
-rw-r--r--awt/java/awt/event/AdjustmentListener.java29
-rw-r--r--awt/java/awt/event/ComponentAdapter.java40
-rw-r--r--awt/java/awt/event/ComponentEvent.java82
-rw-r--r--awt/java/awt/event/ComponentListener.java35
-rw-r--r--awt/java/awt/event/ContainerAdapter.java34
-rw-r--r--awt/java/awt/event/ContainerEvent.java83
-rw-r--r--awt/java/awt/event/ContainerListener.java31
-rw-r--r--awt/java/awt/event/FocusAdapter.java34
-rw-r--r--awt/java/awt/event/FocusEvent.java90
-rw-r--r--awt/java/awt/event/FocusListener.java31
-rw-r--r--awt/java/awt/event/HierarchyBoundsAdapter.java34
-rw-r--r--awt/java/awt/event/HierarchyBoundsListener.java31
-rw-r--r--awt/java/awt/event/HierarchyEvent.java148
-rw-r--r--awt/java/awt/event/HierarchyListener.java29
-rw-r--r--awt/java/awt/event/InputEvent.java184
-rw-r--r--awt/java/awt/event/InputMethodEvent.java150
-rw-r--r--awt/java/awt/event/InputMethodListener.java31
-rw-r--r--awt/java/awt/event/InvocationEvent.java132
-rw-r--r--awt/java/awt/event/ItemEvent.java90
-rw-r--r--awt/java/awt/event/ItemListener.java29
-rw-r--r--awt/java/awt/event/KeyAdapter.java37
-rw-r--r--awt/java/awt/event/KeyEvent.java681
-rw-r--r--awt/java/awt/event/KeyListener.java33
-rw-r--r--awt/java/awt/event/MouseAdapter.java43
-rw-r--r--awt/java/awt/event/MouseEvent.java226
-rw-r--r--awt/java/awt/event/MouseListener.java37
-rw-r--r--awt/java/awt/event/MouseMotionAdapter.java34
-rw-r--r--awt/java/awt/event/MouseMotionListener.java31
-rw-r--r--awt/java/awt/event/MouseWheelEvent.java97
-rw-r--r--awt/java/awt/event/MouseWheelListener.java29
-rw-r--r--awt/java/awt/event/PaintEvent.java80
-rw-r--r--awt/java/awt/event/TextEvent.java53
-rw-r--r--awt/java/awt/event/TextListener.java30
-rw-r--r--awt/java/awt/event/WindowAdapter.java58
-rw-r--r--awt/java/awt/event/WindowEvent.java162
-rw-r--r--awt/java/awt/event/WindowFocusListener.java31
-rw-r--r--awt/java/awt/event/WindowListener.java41
-rw-r--r--awt/java/awt/event/WindowStateListener.java30
-rw-r--r--awt/java/awt/font/FontRenderContext.java168
-rw-r--r--awt/java/awt/font/GlyphJustificationInfo.java185
-rw-r--r--awt/java/awt/font/GlyphMetrics.java248
-rw-r--r--awt/java/awt/font/GlyphVector.java394
-rw-r--r--awt/java/awt/font/GraphicAttribute.java196
-rw-r--r--awt/java/awt/font/ImageGraphicAttribute.java179
-rw-r--r--awt/java/awt/font/LineBreakMeasurer.java231
-rw-r--r--awt/java/awt/font/LineMetrics.java115
-rw-r--r--awt/java/awt/font/MultipleMaster.java86
-rw-r--r--awt/java/awt/font/OpenType.java410
-rw-r--r--awt/java/awt/font/ShapeGraphicAttribute.java195
-rw-r--r--awt/java/awt/font/TextHitInfo.java216
-rw-r--r--awt/java/awt/font/TextLayout.java916
-rw-r--r--awt/java/awt/font/TextMeasurer.java167
-rw-r--r--awt/java/awt/font/TransformAttribute.java80
-rw-r--r--awt/java/awt/geom/AffineTransform.java1158
-rw-r--r--awt/java/awt/geom/Arc2D.java1028
-rw-r--r--awt/java/awt/geom/Area.java317
-rw-r--r--awt/java/awt/geom/CubicCurve2D.java945
-rw-r--r--awt/java/awt/geom/Dimension2D.java78
-rw-r--r--awt/java/awt/geom/Ellipse2D.java403
-rw-r--r--awt/java/awt/geom/FlatteningPathIterator.java326
-rw-r--r--awt/java/awt/geom/GeneralPath.java566
-rw-r--r--awt/java/awt/geom/IllegalPathStateException.java50
-rw-r--r--awt/java/awt/geom/Line2D.java871
-rw-r--r--awt/java/awt/geom/NoninvertibleTransformException.java43
-rw-r--r--awt/java/awt/geom/PathIterator.java132
-rw-r--r--awt/java/awt/geom/Point2D.java288
-rw-r--r--awt/java/awt/geom/QuadCurve2D.java824
-rw-r--r--awt/java/awt/geom/Rectangle2D.java761
-rw-r--r--awt/java/awt/geom/RectangularShape.java276
-rw-r--r--awt/java/awt/geom/RoundRectangle2D.java552
-rw-r--r--awt/java/awt/im/InputContext.java77
-rw-r--r--awt/java/awt/im/InputMethodHighlight.java89
-rw-r--r--awt/java/awt/im/InputMethodRequests.java43
-rw-r--r--awt/java/awt/im/InputSubset.java53
-rw-r--r--awt/java/awt/im/spi/InputMethod.java61
-rw-r--r--awt/java/awt/im/spi/InputMethodContext.java40
-rw-r--r--awt/java/awt/im/spi/InputMethodDescriptor.java40
-rw-r--r--awt/java/awt/image/AffineTransformOp.java617
-rw-r--r--awt/java/awt/image/AreaAveragingScaleFilter.java253
-rw-r--r--awt/java/awt/image/AwtImageBackdoorAccessorImpl.java153
-rw-r--r--awt/java/awt/image/BandCombineOp.java610
-rw-r--r--awt/java/awt/image/BandedSampleModel.java426
-rw-r--r--awt/java/awt/image/BufferStrategy.java72
-rw-r--r--awt/java/awt/image/BufferedImage.java931
-rw-r--r--awt/java/awt/image/BufferedImageFilter.java375
-rw-r--r--awt/java/awt/image/BufferedImageOp.java86
-rw-r--r--awt/java/awt/image/ByteLookupTable.java134
-rw-r--r--awt/java/awt/image/ColorConvertOp.java711
-rw-r--r--awt/java/awt/image/ColorModel.java911
-rw-r--r--awt/java/awt/image/ComponentColorModel.java1471
-rw-r--r--awt/java/awt/image/ComponentSampleModel.java690
-rw-r--r--awt/java/awt/image/ConvolveOp.java545
-rw-r--r--awt/java/awt/image/CropImageFilter.java193
-rw-r--r--awt/java/awt/image/DataBuffer.java442
-rw-r--r--awt/java/awt/image/DataBufferByte.java171
-rw-r--r--awt/java/awt/image/DataBufferDouble.java214
-rw-r--r--awt/java/awt/image/DataBufferFloat.java214
-rw-r--r--awt/java/awt/image/DataBufferInt.java170
-rw-r--r--awt/java/awt/image/DataBufferShort.java172
-rw-r--r--awt/java/awt/image/DataBufferUShort.java182
-rw-r--r--awt/java/awt/image/DirectColorModel.java862
-rw-r--r--awt/java/awt/image/FilteredImageSource.java88
-rw-r--r--awt/java/awt/image/ImageConsumer.java165
-rw-r--r--awt/java/awt/image/ImageFilter.java129
-rw-r--r--awt/java/awt/image/ImageObserver.java99
-rw-r--r--awt/java/awt/image/ImageProducer.java74
-rw-r--r--awt/java/awt/image/ImagingOpException.java44
-rw-r--r--awt/java/awt/image/IndexColorModel.java1020
-rw-r--r--awt/java/awt/image/Kernel.java138
-rw-r--r--awt/java/awt/image/LookupOp.java647
-rw-r--r--awt/java/awt/image/LookupTable.java93
-rw-r--r--awt/java/awt/image/MemoryImageSource.java512
-rw-r--r--awt/java/awt/image/MultiPixelPackedSampleModel.java454
-rw-r--r--awt/java/awt/image/PackedColorModel.java383
-rw-r--r--awt/java/awt/image/PixelGrabber.java408
-rw-r--r--awt/java/awt/image/PixelInterleavedSampleModel.java124
-rw-r--r--awt/java/awt/image/RGBImageFilter.java190
-rw-r--r--awt/java/awt/image/Raster.java1412
-rw-r--r--awt/java/awt/image/RasterFormatException.java45
-rw-r--r--awt/java/awt/image/RasterOp.java83
-rw-r--r--awt/java/awt/image/RenderedImage.java198
-rw-r--r--awt/java/awt/image/ReplicateScaleFilter.java213
-rw-r--r--awt/java/awt/image/RescaleOp.java659
-rw-r--r--awt/java/awt/image/SampleModel.java1053
-rw-r--r--awt/java/awt/image/ShortLookupTable.java132
-rw-r--r--awt/java/awt/image/SinglePixelPackedSampleModel.java508
-rw-r--r--awt/java/awt/image/TileObserver.java44
-rw-r--r--awt/java/awt/image/VolatileImage.java144
-rw-r--r--awt/java/awt/image/WritableRaster.java516
-rw-r--r--awt/java/awt/image/WritableRenderedImage.java101
-rw-r--r--awt/java/awt/image/renderable/ContextualRenderedImageFactory.java89
-rw-r--r--awt/java/awt/image/renderable/ParameterBlock.java548
-rw-r--r--awt/java/awt/image/renderable/RenderContext.java196
-rw-r--r--awt/java/awt/image/renderable/RenderableImage.java132
-rw-r--r--awt/java/awt/image/renderable/RenderableImageOp.java182
-rw-r--r--awt/java/awt/image/renderable/RenderableImageProducer.java141
-rw-r--r--awt/java/awt/image/renderable/RenderedImageFactory.java43
-rw-r--r--awt/java/awt/peer/ButtonPeer.java25
-rw-r--r--awt/java/awt/peer/CanvasPeer.java25
-rw-r--r--awt/java/awt/peer/CheckboxMenuItemPeer.java25
-rw-r--r--awt/java/awt/peer/CheckboxPeer.java25
-rw-r--r--awt/java/awt/peer/ChoicePeer.java25
-rw-r--r--awt/java/awt/peer/ComponentPeer.java25
-rw-r--r--awt/java/awt/peer/DialogPeer.java25
-rw-r--r--awt/java/awt/peer/FileDialogPeer.java25
-rw-r--r--awt/java/awt/peer/FontPeer.java25
-rw-r--r--awt/java/awt/peer/FramePeer.java25
-rw-r--r--awt/java/awt/peer/LabelPeer.java25
-rw-r--r--awt/java/awt/peer/LightweightPeer.java25
-rw-r--r--awt/java/awt/peer/ListPeer.java25
-rw-r--r--awt/java/awt/peer/MenuBarPeer.java25
-rw-r--r--awt/java/awt/peer/MenuComponentPeer.java25
-rw-r--r--awt/java/awt/peer/MenuItemPeer.java25
-rw-r--r--awt/java/awt/peer/MenuPeer.java25
-rw-r--r--awt/java/awt/peer/MouseInfoPeer.java25
-rw-r--r--awt/java/awt/peer/PanelPeer.java25
-rw-r--r--awt/java/awt/peer/PopupMenuPeer.java25
-rw-r--r--awt/java/awt/peer/ScrollPanePeer.java25
-rw-r--r--awt/java/awt/peer/ScrollbarPeer.java25
-rw-r--r--awt/java/awt/peer/TextAreaPeer.java25
-rw-r--r--awt/java/awt/peer/TextFieldPeer.java25
-rw-r--r--awt/java/awt/peer/WindowPeer.java25
-rw-r--r--awt/java/beans/FeatureDescriptor.java234
-rw-r--r--awt/java/beans/IndexedPropertyChangeEvent.java66
-rw-r--r--awt/java/beans/IndexedPropertyDescriptor.java227
-rw-r--r--awt/java/beans/IntrospectionException.java27
-rw-r--r--awt/java/beans/PropertyChangeEvent.java62
-rw-r--r--awt/java/beans/PropertyChangeListener.java25
-rw-r--r--awt/java/beans/PropertyChangeListenerProxy.java41
-rw-r--r--awt/java/beans/PropertyChangeSupport.java351
-rw-r--r--awt/java/beans/PropertyDescriptor.java300
-rw-r--r--awt/java/beans/PropertyEditor.java49
-rw-r--r--awt/java/beans/PropertyEditorManager.java114
-rw-r--r--awt/java/beans/PropertyEditorSupport.java129
-rw-r--r--awt/java/beans/PropertyVetoException.java54
-rw-r--r--awt/javax/imageio/IIOException.java52
-rw-r--r--awt/javax/imageio/IIOImage.java203
-rw-r--r--awt/javax/imageio/IIOParam.java316
-rw-r--r--awt/javax/imageio/IIOParamController.java43
-rw-r--r--awt/javax/imageio/ImageIO.java777
-rw-r--r--awt/javax/imageio/ImageReadParam.java193
-rw-r--r--awt/javax/imageio/ImageReader.java1100
-rw-r--r--awt/javax/imageio/ImageTranscoder.java60
-rw-r--r--awt/javax/imageio/ImageTypeSpecifier.java339
-rw-r--r--awt/javax/imageio/ImageWriteParam.java633
-rw-r--r--awt/javax/imageio/ImageWriter.java951
-rw-r--r--awt/javax/imageio/event/IIOReadProgressListener.java103
-rw-r--r--awt/javax/imageio/event/IIOReadUpdateListener.java138
-rw-r--r--awt/javax/imageio/event/IIOReadWarningListener.java46
-rw-r--r--awt/javax/imageio/event/IIOWriteProgressListener.java86
-rw-r--r--awt/javax/imageio/event/IIOWriteWarningListener.java40
-rw-r--r--awt/javax/imageio/metadata/IIOInvalidTreeException.java67
-rw-r--r--awt/javax/imageio/metadata/IIOMetadata.java371
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataController.java45
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataFormat.java347
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataFormatImpl.java939
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataNode.java675
-rw-r--r--awt/javax/imageio/metadata/IIOStandardMetadataFormat.java316
-rw-r--r--awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties133
-rw-r--r--awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java75
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java213
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java116
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java193
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGQTable.java162
-rw-r--r--awt/javax/imageio/spi/IIORegistry.java110
-rw-r--r--awt/javax/imageio/spi/IIOServiceProvider.java97
-rw-r--r--awt/javax/imageio/spi/ImageInputStreamSpi.java126
-rw-r--r--awt/javax/imageio/spi/ImageOutputStreamSpi.java126
-rw-r--r--awt/javax/imageio/spi/ImageReaderSpi.java186
-rw-r--r--awt/javax/imageio/spi/ImageReaderWriterSpi.java315
-rw-r--r--awt/javax/imageio/spi/ImageTranscoderSpi.java74
-rw-r--r--awt/javax/imageio/spi/ImageWriterSpi.java209
-rw-r--r--awt/javax/imageio/spi/RegisterableService.java50
-rw-r--r--awt/javax/imageio/spi/ServiceRegistry.java516
-rw-r--r--awt/javax/imageio/stream/FileCacheImageInputStream.java131
-rw-r--r--awt/javax/imageio/stream/FileCacheImageOutputStream.java184
-rw-r--r--awt/javax/imageio/stream/FileImageInputStream.java115
-rw-r--r--awt/javax/imageio/stream/FileImageOutputStream.java123
-rw-r--r--awt/javax/imageio/stream/IIOByteBuffer.java111
-rw-r--r--awt/javax/imageio/stream/ImageInputStream.java485
-rw-r--r--awt/javax/imageio/stream/ImageInputStreamImpl.java394
-rw-r--r--awt/javax/imageio/stream/ImageOutputStream.java270
-rw-r--r--awt/javax/imageio/stream/ImageOutputStreamImpl.java169
-rw-r--r--awt/javax/imageio/stream/MemoryCacheImageInputStream.java113
-rw-r--r--awt/javax/imageio/stream/MemoryCacheImageOutputStream.java130
-rw-r--r--awt/org/apache/harmony/awt/ChoiceStyle.java33
-rw-r--r--awt/org/apache/harmony/awt/ClipRegion.java84
-rw-r--r--awt/org/apache/harmony/awt/ComponentInternals.java212
-rw-r--r--awt/org/apache/harmony/awt/ContextStorage.java154
-rw-r--r--awt/org/apache/harmony/awt/ContextThreadGroup.java34
-rw-r--r--awt/org/apache/harmony/awt/ListenerList.java194
-rw-r--r--awt/org/apache/harmony/awt/ReadOnlyIterator.java53
-rw-r--r--awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java65
-rw-r--r--awt/org/apache/harmony/awt/gl/CommonGraphics2D.java1132
-rw-r--r--awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java78
-rw-r--r--awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java67
-rw-r--r--awt/org/apache/harmony/awt/gl/Crossing.java889
-rw-r--r--awt/org/apache/harmony/awt/gl/GLVolatileImage.java30
-rw-r--r--awt/org/apache/harmony/awt/gl/ICompositeContext.java90
-rw-r--r--awt/org/apache/harmony/awt/gl/ImageSurface.java323
-rw-r--r--awt/org/apache/harmony/awt/gl/MultiRectArea.java836
-rw-r--r--awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java837
-rw-r--r--awt/org/apache/harmony/awt/gl/Surface.java309
-rw-r--r--awt/org/apache/harmony/awt/gl/TextRenderer.java59
-rw-r--r--awt/org/apache/harmony/awt/gl/XORComposite.java48
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ColorConverter.java257
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ColorScaler.java355
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java82
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ICC_Transform.java156
-rw-r--r--awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java148
-rw-r--r--awt/org/apache/harmony/awt/gl/color/NativeCMM.java92
-rw-r--r--awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java642
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidFont.java254
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java277
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java81
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java219
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java120
-rw-r--r--awt/org/apache/harmony/awt/gl/font/BasicMetrics.java134
-rw-r--r--awt/org/apache/harmony/awt/gl/font/CaretManager.java530
-rw-r--r--awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java954
-rw-r--r--awt/org/apache/harmony/awt/gl/font/CompositeFont.java486
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java145
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontFinder.java121
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontManager.java819
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java282
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java499
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontProperty.java106
-rw-r--r--awt/org/apache/harmony/awt/gl/font/Glyph.java236
-rw-r--r--awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java412
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextDecorator.java433
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java209
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java861
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunSegment.java165
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java979
-rw-r--r--awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java79
-rw-r--r--awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java136
-rw-r--r--awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java62
-rw-r--r--awt/org/apache/harmony/awt/gl/image/DataBufferListener.java31
-rw-r--r--awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java261
-rw-r--r--awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java68
-rw-r--r--awt/org/apache/harmony/awt/gl/image/GifDecoder.java692
-rw-r--r--awt/org/apache/harmony/awt/gl/image/ImageDecoder.java258
-rw-r--r--awt/org/apache/harmony/awt/gl/image/ImageLoader.java208
-rw-r--r--awt/org/apache/harmony/awt/gl/image/JpegDecoder.java231
-rw-r--r--awt/org/apache/harmony/awt/gl/image/OffscreenImage.java532
-rw-r--r--awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java153
-rw-r--r--awt/org/apache/harmony/awt/gl/image/PngDecoder.java270
-rw-r--r--awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java282
-rw-r--r--awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java77
-rw-r--r--awt/org/apache/harmony/awt/gl/render/Blitter.java53
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java502
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaBlitter.java611
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java760
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java475
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java263
-rw-r--r--awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java218
-rw-r--r--awt/org/apache/harmony/awt/gl/render/NullBlitter.java56
-rw-r--r--awt/org/apache/harmony/awt/im/InputMethodContext.java563
-rw-r--r--awt/org/apache/harmony/awt/internal/nls/Messages.java143
-rw-r--r--awt/org/apache/harmony/awt/internal/nls/MsgHelp.java86
-rw-r--r--awt/org/apache/harmony/awt/state/MenuItemState.java51
-rw-r--r--awt/org/apache/harmony/awt/state/MenuState.java46
-rw-r--r--awt/org/apache/harmony/awt/state/State.java55
-rw-r--r--awt/org/apache/harmony/awt/wtk/CreationParams.java133
-rw-r--r--awt/org/apache/harmony/awt/wtk/CursorFactory.java85
-rw-r--r--awt/org/apache/harmony/awt/wtk/GraphicsFactory.java82
-rw-r--r--awt/org/apache/harmony/awt/wtk/KeyInfo.java53
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeCursor.java45
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeEvent.java268
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeEventQueue.java117
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeEventThread.java78
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeIM.java130
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java42
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeRobot.java75
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeWindow.java220
-rw-r--r--awt/org/apache/harmony/awt/wtk/ShutdownThread.java83
-rw-r--r--awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java86
-rw-r--r--awt/org/apache/harmony/awt/wtk/Synchronizer.java200
-rw-r--r--awt/org/apache/harmony/awt/wtk/SystemProperties.java59
-rw-r--r--awt/org/apache/harmony/awt/wtk/WTK.java61
-rw-r--r--awt/org/apache/harmony/awt/wtk/WindowFactory.java85
-rw-r--r--awt/org/apache/harmony/beans/internal/nls/Messages.java132
-rw-r--r--awt/org/apache/harmony/beans/internal/nls/messages.properties103
-rw-r--r--awt/org/apache/harmony/x/imageio/internal/nls/Messages.java124
-rw-r--r--awt/org/apache/harmony/x/imageio/internal/nls/messages.properties18
-rw-r--r--awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java94
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java115
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java44
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java126
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java86
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java402
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java56
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java57
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java106
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java88
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java247
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java41
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java113
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java53
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java52
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java59
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java60
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java54
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java53
-rw-r--r--awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java226
-rw-r--r--awt/resources/org/apache/harmony/awt/internal/nls/messages.properties495
426 files changed, 110898 insertions, 0 deletions
diff --git a/awt/Android.mk b/awt/Android.mk
new file mode 100644
index 0000000..c7480f5
--- /dev/null
+++ b/awt/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_RESOURCE_DIRS := resources
+
+LOCAL_JAVA_LIBRARIES := core framework
+
+LOCAL_MODULE:= android.awt
+
+LOCAL_DX_FLAGS := --core-library
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/awt/com/android/internal/awt/AndroidGraphics2D.java b/awt/com/android/internal/awt/AndroidGraphics2D.java
new file mode 100644
index 0000000..9a8ae02
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphics2D.java
@@ -0,0 +1,1354 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import com.android.internal.awt.AndroidGraphicsConfiguration;
+import com.android.internal.graphics.NativeUtils;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.PathIterator;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Typeface;
+import android.graphics.PixelXorXfermode;
+import android.view.Display;
+import android.view.WindowManager;
+import android.content.Context;
+
+public class AndroidGraphics2D extends Graphics2D {
+
+ private int displayWidth, displayHeight;
+
+ protected Surface dstSurf = null;
+ protected MultiRectArea clip = null;
+
+ protected Composite composite = AlphaComposite.SrcOver;
+ protected AffineTransform transform = new AffineTransform();
+
+ private static AndroidGraphics2D mAg;
+ private static Canvas mC;
+
+ // Android Paint
+ public static Paint mP;
+
+ private static java.awt.Font mFnt;
+
+ // Cached Matrix
+ public static Matrix mM;
+ private static FontMetrics mFm;
+ private static RenderingHints mRh;
+ private static Color mBc;
+
+ private Area mCurrClip;
+
+ public final static double RAD_360 = Math.PI / 180 * 360;
+
+ // Image drawing
+ private AndroidJavaBlitter blitter;
+ private DirectColorModel cm;
+ private SinglePixelPackedSampleModel sm;
+ private WritableRaster wr;
+
+
+ public static AndroidGraphics2D getInstance() {
+ if (mAg == null) {
+ throw new RuntimeException("AndroidGraphics2D not instantiated!");
+ }
+ return mAg;
+ }
+
+ public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) {
+ if (c == null || ctx == null) {
+ throw new RuntimeException(
+ "Illegal argument, Canvas cannot be null!");
+ }
+ mAg = new AndroidGraphics2D(ctx, c, p);
+ return mAg;
+ }
+
+ private AndroidGraphics2D(Context ctx, Canvas c, Paint p) {
+ super();
+ mC = c;
+ mP = p;
+ mM = new Matrix();
+ mM.reset();
+ mM = mC.getMatrix();
+ Rect r = mC.getClipBounds();
+ int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left};
+ mCurrClip = new Area(createShape(cl));
+ if(ctx != null) {
+ WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE);
+ Display d = wm.getDefaultDisplay();
+ displayWidth = d.getWidth();
+ displayHeight = d.getHeight();
+ }
+ blitter = new AndroidJavaBlitter(c);
+ cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000);
+ sm = new SinglePixelPackedSampleModel(
+ DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks());
+ wr = Raster.createWritableRaster(sm, null);
+ dstSurf = new ImageSurface(cm, wr);
+ }
+
+ @Override
+ public void addRenderingHints(Map<?, ?> hints) {
+ if (mRh == null) {
+ mRh = (RenderingHints) hints;
+ }
+ mRh.add((RenderingHints) hints);
+ }
+
+ public float[] getMatrix() {
+ float[] f = new float[9];
+ mC.getMatrix().getValues(f);
+ return f;
+ }
+
+ /**
+ *
+ * @return a Matrix in Android format
+ */
+ public float[] getInverseMatrix() {
+ AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix()));
+ try {
+ af = af.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ }
+ return createMatrix(af);
+ }
+
+ private Path getPath(Shape s) {
+ Path path = new Path();
+ PathIterator pi = s.getPathIterator(null);
+ while (pi.isDone() == false) {
+ getCurrentSegment(pi, path);
+ pi.next();
+ }
+ return path;
+ }
+
+ private void getCurrentSegment(PathIterator pi, Path path) {
+ float[] coordinates = new float[6];
+ int type = pi.currentSegment(coordinates);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ path.moveTo(coordinates[0], coordinates[1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ path.lineTo(coordinates[0], coordinates[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ path.quadTo(coordinates[0], coordinates[1], coordinates[2],
+ coordinates[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ path.cubicTo(coordinates[0], coordinates[1], coordinates[2],
+ coordinates[3], coordinates[4], coordinates[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ path.close();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private Shape createShape(int[] arr) {
+ Shape s = new GeneralPath();
+ for(int i = 0; i < arr.length; i++) {
+ int type = arr[i];
+ switch (type) {
+ case -1:
+ //MOVETO
+ ((GeneralPath)s).moveTo(arr[++i], arr[++i]);
+ break;
+ case -2:
+ //LINETO
+ ((GeneralPath)s).lineTo(arr[++i], arr[++i]);
+ break;
+ case -3:
+ //QUADTO
+ ((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i],
+ arr[++i]);
+ break;
+ case -4:
+ //CUBICTO
+ ((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i],
+ arr[++i], arr[++i], arr[++i]);
+ break;
+ case -5:
+ //CLOSE
+ return s;
+ default:
+ break;
+ }
+ }
+ return s;
+ }
+ /*
+ public int[] getPixels() {
+ return mC.getPixels();
+ }*/
+
+ public static float getRadian(float degree) {
+ return (float) ((Math.PI / 180) * degree);
+ }
+
+ private Shape getShape() {
+ return null;
+ }
+
+ public static float getDegree(float radian) {
+ return (float) ((180 / Math.PI) * radian);
+ }
+
+ /*
+ * Degree in radian
+ */
+ public static float getEllipsisX(float degree, float princAxis) {
+ return (float) Math.cos(degree) * princAxis;
+ }
+
+ public static float getEllipsisY(float degree, float conAxis) {
+ return (float) Math.sin(degree) * conAxis;
+ }
+
+ @Override
+ public void clip(Shape s) {
+ mC.clipPath(getPath(s));
+ }
+
+ public void setCanvas(Canvas c) {
+ mC = c;
+ }
+
+ @Override
+ public void draw(Shape s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.STROKE);
+ mC.drawPath(getPath(s), mP);
+ mP.setStyle(tmp);
+ }
+/*
+ private ArrayList getSegments(Shape s) {
+ ArrayList arr = new ArrayList();
+ PathIterator pi = s.getPathIterator(null);
+ while (pi.isDone() == false) {
+ getCurrentSegment(pi, arr);
+ pi.next();
+ }
+ return arr;
+ }
+
+ private void getCurrentSegment(PathIterator pi, ArrayList arr) {
+ float[] coordinates = new float[6];
+ int type = pi.currentSegment(coordinates);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ arr.add(new Integer(-1));
+ break;
+ case PathIterator.SEG_LINETO:
+ arr.add(new Integer(-2));
+ break;
+ case PathIterator.SEG_QUADTO:
+ arr.add(new Integer(-3));
+ break;
+ case PathIterator.SEG_CUBICTO:
+ arr.add(new Integer(-4));
+ break;
+ case PathIterator.SEG_CLOSE:
+ arr.add(new Integer(-5));
+ break;
+ default:
+ break;
+ }
+ }
+*/
+ /*
+ * Convenience method, not standard AWT
+ */
+ public void draw(Path s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.STROKE);
+ s.transform(mM);
+ mC.drawPath(s, mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void drawGlyphVector(GlyphVector g, float x, float y) {
+ // TODO draw at x, y
+ // draw(g.getOutline());
+ /*
+ Matrix matrix = new Matrix();
+ matrix.setTranslate(x, y);
+ Path pth = getPath(g.getOutline());
+ pth.transform(matrix);
+ draw(pth);
+ */
+ Path path = new Path();
+ char[] c = ((AndroidGlyphVector)g).getGlyphs();
+ mP.getTextPath(c, 0, c.length, x, y, path);
+ mC.drawPath(path, mP);
+ }
+
+ @Override
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, float x,
+ float y) {
+ throw new RuntimeException("AttributedCharacterIterator not supported!");
+
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ throw new RuntimeException("AttributedCharacterIterator not supported!");
+
+ }
+
+ @Override
+ public void drawString(String s, float x, float y) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+
+ mP.setStyle(Paint.Style.FILL);
+ Path pth = new Path();
+ mP.getTextPath(s, 0, s.length(), x, y, pth);
+ mC.drawPath(pth, mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void drawString(String str, int x, int y) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStrokeWidth(0);
+
+ mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y,
+ mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void fill(Shape s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawPath(getPath(s), mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public Color getBackground() {
+ return mBc;
+ }
+
+ @Override
+ public Composite getComposite() {
+ throw new RuntimeException("Composite not implemented!");
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return new AndroidGraphicsConfiguration();
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return new FontRenderContext(getTransform(), mP.isAntiAlias(), true);
+ }
+
+ @Override
+ public java.awt.Paint getPaint() {
+ throw new RuntimeException("AWT Paint not implemented in Android!");
+ }
+
+ public static Canvas getAndroidCanvas() {
+ return mC;
+ }
+
+ public static Paint getAndroidPaint() {
+ return mP;
+ }
+
+ @Override
+ public RenderingHints getRenderingHints() {
+ return mRh;
+ }
+
+ @Override
+ public Stroke getStroke() {
+ if (mP != null) {
+ return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap()
+ .ordinal(), mP.getStrokeJoin().ordinal());
+ }
+ return null;
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ return new AffineTransform(createAWTMatrix(getMatrix()));
+ }
+
+ @Override
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ // ???AWT TODO check if on stroke
+ return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect
+ .getHeight());
+ }
+
+ @Override
+ public void rotate(double theta) {
+ mM.preRotate((float) AndroidGraphics2D
+ .getDegree((float) (RAD_360 - theta)));
+ mC.concat(mM);
+ }
+
+ @Override
+ public void rotate(double theta, double x, double y) {
+ mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta),
+ (float) x, (float) y);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void scale(double sx, double sy) {
+ mM.setScale((float) sx, (float) sy);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void setBackground(Color color) {
+ mBc = color;
+ mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight()));
+ // TODO don't limit to current clip
+ mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color
+ .getBlue());
+ }
+
+ @Override
+ public void setComposite(Composite comp) {
+ throw new RuntimeException("Composite not implemented!");
+ }
+
+ public void setSpaint(Paint paint) {
+ mP = paint;
+ }
+
+ @Override
+ public void setPaint(java.awt.Paint paint) {
+ setColor((Color)paint);
+ }
+
+ @Override
+ public Object getRenderingHint(RenderingHints.Key key) {
+ if (mRh == null) {
+ return null;
+ }
+ return mRh.get(key);
+ }
+
+ @Override
+ public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
+ if (mRh == null) {
+ mRh = new RenderingHints(hintKey, hintValue);
+ } else {
+ mRh.put(hintKey, hintValue);
+ }
+ applyHints();
+ }
+
+ @Override
+ public void setRenderingHints(Map<?, ?> hints) {
+ mRh = (RenderingHints) hints;
+ applyHints();
+ }
+
+ private void applyHints() {
+ Object o;
+
+ // TODO do something like this:
+ /*
+ * Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) {
+ * o = it.next(); }
+ */
+
+ // /////////////////////////////////////////////////////////////////////
+ // not supported in skia
+ /*
+ * o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if
+ * (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else
+ * if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { }
+ * else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if
+ * (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if
+ * (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_DITHERING); if
+ * (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if
+ * (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if
+ * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else
+ * if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if
+ * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_INTERPOLATION); if
+ * (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if
+ * (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if
+ * (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_RENDERING); if
+ * (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if
+ * (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if
+ * (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if
+ * (o.equals(RenderingHints.VALUE_STROKE_PURE)) { }
+ */
+
+ o = mRh.get(RenderingHints.KEY_ANTIALIASING);
+ if (o != null) {
+ if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) {
+ mP.setAntiAlias(true);
+ }
+ }
+
+ o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING);
+ if (o != null) {
+ if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) {
+ mP.setAntiAlias(true);
+ }
+ }
+ }
+
+ @Override
+ public void setStroke(Stroke s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ BasicStroke bs = (BasicStroke) s;
+ mP.setStyle(Paint.Style.STROKE);
+ mP.setStrokeWidth(bs.getLineWidth());
+
+ int cap = bs.getEndCap();
+ if (cap == 0) {
+ mP.setStrokeCap(Paint.Cap.BUTT);
+ } else if (cap == 1) {
+ mP.setStrokeCap(Paint.Cap.ROUND);
+ } else if (cap == 2) {
+ mP.setStrokeCap(Paint.Cap.SQUARE);
+ }
+
+ int join = bs.getLineJoin();
+ if (join == 0) {
+ mP.setStrokeJoin(Paint.Join.MITER);
+ } else if (join == 1) {
+ mP.setStrokeJoin(Paint.Join.ROUND);
+ } else if (join == 2) {
+ mP.setStrokeJoin(Paint.Join.BEVEL);
+ }
+ }
+
+ public static float[] createMatrix(AffineTransform Tx) {
+ double[] at = new double[9];
+ Tx.getMatrix(at);
+ float[] f = new float[at.length];
+ f[0] = (float) at[0];
+ f[1] = (float) at[2];
+ f[2] = (float) at[4];
+ f[3] = (float) at[1];
+ f[4] = (float) at[3];
+ f[5] = (float) at[5];
+ f[6] = 0;
+ f[7] = 0;
+ f[8] = 1;
+ return f;
+ }
+
+ private float[] createAWTMatrix(float[] matrix) {
+ float[] at = new float[9];
+ at[0] = matrix[0];
+ at[1] = matrix[3];
+ at[2] = matrix[1];
+ at[3] = matrix[4];
+ at[4] = matrix[2];
+ at[5] = matrix[5];
+ at[6] = 0;
+ at[7] = 0;
+ at[8] = 1;
+ return at;
+ }
+
+ public static Matrix createMatrixObj(AffineTransform Tx) {
+ Matrix m = new Matrix();
+ m.reset();
+ m.setValues(createMatrix(Tx));
+ return m;
+ }
+
+ @Override
+ public void setTransform(AffineTransform Tx) {
+ mM.reset();
+ /*
+ * if(Tx.isIdentity()) { mM = new Matrix(); }
+ */
+ mM.setValues(createMatrix(Tx));
+ Matrix m = new Matrix();
+ m.setValues(getInverseMatrix());
+ mC.concat(m);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void shear(double shx, double shy) {
+ mM.setSkew((float) shx, (float) shy);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void transform(AffineTransform Tx) {
+ Matrix m = new Matrix();
+ m.setValues(createMatrix(Tx));
+ mC.concat(m);
+ }
+
+ @Override
+ public void translate(double tx, double ty) {
+ mM.setTranslate((float) tx, (float) ty);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void translate(int x, int y) {
+ mM.setTranslate((float) x, (float) y);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void clearRect(int x, int y, int width, int height) {
+ mC.clipRect(x, y, x + width, y + height);
+ if (mBc != null) {
+ mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc
+ .getRed());
+ } else {
+ mC.drawARGB(0xff, 0xff, 0xff, 0xff);
+ }
+ }
+
+ @Override
+ public void clipRect(int x, int y, int width, int height) {
+ int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
+ Shape shp = createShape(cl);
+ mCurrClip.intersect(new Area(shp));
+ mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT);
+ }
+
+ @Override
+ public void copyArea(int sx, int sy, int width, int height, int dx, int dy) {
+ copyArea(mC, sx, sy, width + dx, height + dy, dx, dy);
+ }
+
+ @Override
+ public Graphics create() {
+ return this;
+ }
+
+ @Override
+ public void dispose() {
+ mC = null;
+ mP = null;
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int sa, int ea) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setStrokeWidth(0);
+ mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa),
+ ea, true, mP);
+ }
+
+
+ // ???AWT: only used for debuging, delete in final version
+ public void drawBitmap(Bitmap bm, float x, float y, Paint p) {
+ mC.drawBitmap(bm, x, y, null);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
+ return drawImage(image, x, y, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(width == 0 || height == 0) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ if(w == width && h == height){
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)width / w, (float)height / h);
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ ImageObserver imageObserver) {
+ return drawImage(image, x, y, width, height, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+
+ int dstX = dx1;
+ int dstY = dy1;
+ int srcX = sx1;
+ int srcY = sy1;
+
+ int dstW = dx2 - dx1;
+ int dstH = dy2 - dy1;
+ int srcW = sx2 - sx1;
+ int srcH = sy2 - sy1;
+
+ if(srcW == dstW && srcH == dstH){
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
+
+ return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
+ imageObserver);
+ }
+
+ @Override
+ public void drawImage(BufferedImage bufImage, BufferedImageOp op,
+ int x, int y) {
+
+ if(bufImage == null) {
+ return;
+ }
+
+ if(op == null) {
+ drawImage(bufImage, x, y, null);
+ } else if(op instanceof AffineTransformOp){
+ AffineTransformOp atop = (AffineTransformOp) op;
+ AffineTransform xform = atop.getTransform();
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(), xform,
+ composite, null, clip);
+ } else {
+ bufImage = op.filter(bufImage, null);
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, null, clip);
+ }
+ }
+
+ @Override
+ public boolean drawImage(Image image, AffineTransform trans,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(trans == null || trans.isIdentity()) {
+ return drawImage(image, 0, 0, imageObserver);
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ AffineTransform xform = (AffineTransform) transform.clone();
+ xform.concatenate(trans);
+ blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
+ null, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mC.drawLine(x1, y1, x2, y2, mP);
+ }
+
+ @Override
+ public void drawOval(int x, int y, int width, int height) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setStyle(Paint.Style.STROKE);
+ mC.drawOval(new RectF(x, y, x + width, y + height), mP);
+ }
+
+ @Override
+ public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0],
+ ypoints[0], mP);
+ for (int i = 0; i < npoints - 1; i++) {
+ mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1],
+ ypoints[i + 1], mP);
+ }
+ }
+
+ @Override
+ public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
+ for (int i = 0; i < npoints - 1; i++) {
+ drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]);
+ }
+
+ }
+
+ @Override
+ public void drawRoundRect(int x, int y, int width, int height,
+ int arcWidth, int arcHeight) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mC.drawRoundRect(new RectF(x, y, width, height), arcWidth,
+ arcHeight, mP);
+ }
+
+ @Override
+ public void fillArc(int x, int y, int width, int height, int sa, int ea) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL_AND_STROKE);
+ mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea),
+ ea, true, mP);
+
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawOval(new RectF(x, y, x + width, y + height), mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mC.save(Canvas.CLIP_SAVE_FLAG);
+
+ mP.setStyle(Paint.Style.FILL);
+
+ GeneralPath filledPolygon = new GeneralPath(
+ GeneralPath.WIND_EVEN_ODD, npoints);
+ filledPolygon.moveTo(xpoints[0], ypoints[0]);
+ for (int index = 1; index < xpoints.length; index++) {
+ filledPolygon.lineTo(xpoints[index], ypoints[index]);
+ }
+ filledPolygon.closePath();
+ Path path = getPath(filledPolygon);
+ mC.clipPath(path);
+ mC.drawPath(path, mP);
+
+ mP.setStyle(tmp);
+ mC.restore();
+ }
+
+ @Override
+ public void fillRect(int x, int y, int width, int height) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawRect(new Rect(x, y, x + width, y + height), mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void drawRect(int x, int y, int width, int height) {
+ int[] xpoints = { x, x, x + width, x + width };
+ int[] ypoints = { y, y + height, y + height, y };
+ drawPolygon(xpoints, ypoints, 4);
+ }
+
+ @Override
+ public void fillRoundRect(int x, int y, int width, int height,
+ int arcWidth, int arcHeight) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth,
+ arcHeight, mP);
+ }
+
+ @Override
+ public Shape getClip() {
+ return mCurrClip;
+ }
+
+ @Override
+ public Rectangle getClipBounds() {
+ Rect r = mC.getClipBounds();
+ return new Rectangle(r.left, r.top, r.width(), r.height());
+ }
+
+ @Override
+ public Color getColor() {
+ if (mP != null) {
+ return new Color(mP.getColor());
+ }
+ return null;
+ }
+
+ @Override
+ public Font getFont() {
+ return mFnt;
+ }
+
+ @Override
+ public FontMetrics getFontMetrics(Font font) {
+ mFm = new FontMetricsImpl(font);
+ return mFm;
+ }
+
+ @Override
+ public void setClip(int x, int y, int width, int height) {
+ int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
+ mCurrClip = new Area(createShape(cl));
+ mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE);
+
+ }
+
+ @Override
+ public void setClip(Shape clip) {
+ mCurrClip = new Area(clip);
+ mC.clipPath(getPath(clip), Region.Op.REPLACE);
+ }
+
+ @Override
+ public void setColor(Color c) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setColor(c.getRGB());
+ }
+
+ /**
+ * Font mapping:
+ *
+ * Family:
+ *
+ * Android AWT
+ * -------------------------------------
+ * serif Serif / TimesRoman
+ * sans-serif SansSerif / Helvetica
+ * monospace Monospaced / Courier
+ *
+ * Style:
+ *
+ * Android AWT
+ * -------------------------------------
+ * normal Plain
+ * bold bold
+ * italic italic
+ *
+ */
+ @Override
+ public void setFont(Font font) {
+ if (font == null) {
+ return;
+ }
+ if (mP == null) {
+ mP = new Paint();
+ }
+
+ mFnt = font;
+ Typeface tf = null;
+ int sty = font.getStyle();
+ String nam = font.getName();
+ String aF = "";
+ if (nam != null) {
+ if (nam.equalsIgnoreCase("Serif")
+ || nam.equalsIgnoreCase("TimesRoman")) {
+ aF = "serif";
+ } else if (nam.equalsIgnoreCase("SansSerif")
+ || nam.equalsIgnoreCase("Helvetica")) {
+ aF = "sans-serif";
+ } else if (nam.equalsIgnoreCase("Monospaced")
+ || nam.equalsIgnoreCase("Courier")) {
+ aF = "monospace";
+ }
+ }
+
+ switch (sty) {
+ case Font.PLAIN:
+ tf = Typeface.create(aF, Typeface.NORMAL);
+ break;
+ case Font.BOLD:
+ tf = Typeface.create(aF, Typeface.BOLD);
+ break;
+ case Font.ITALIC:
+ tf = Typeface.create(aF, Typeface.ITALIC);
+ break;
+ case Font.BOLD | Font.ITALIC:
+ tf = Typeface.create(aF, Typeface.BOLD_ITALIC);
+ break;
+ default:
+ tf = Typeface.DEFAULT;
+ }
+
+ mP.setTextSize(font.getSize());
+ mP.setTypeface(tf);
+ }
+
+ @Override
+ public void drawBytes(byte[] data, int offset, int length, int x, int y) {
+ drawString(new String(data, offset, length), x, y);
+ }
+
+ @Override
+ public void drawPolygon(Polygon p) {
+ drawPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ @Override
+ public void fillPolygon(Polygon p) {
+ fillPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ @Override
+ public Rectangle getClipBounds(Rectangle r) {
+ Shape clip = getClip();
+ if (clip != null) {
+ Rectangle b = clip.getBounds();
+ r.x = b.x;
+ r.y = b.y;
+ r.width = b.width;
+ r.height = b.height;
+ }
+ return r;
+ }
+
+ @Override
+ public boolean hitClip(int x, int y, int width, int height) {
+ return getClipBounds().intersects(new Rectangle(x, y, width, height));
+ }
+
+ @Override
+ public void drawChars(char[] data, int offset, int length, int x, int y) {
+ mC.drawText(data, offset, length, x, y, mP);
+ }
+
+ @Override
+ public void setPaintMode() {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setXfermode(null);
+ }
+
+ @Override
+ public void setXORMode(Color color) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setXfermode(new PixelXorXfermode(color.getRGB()));
+ }
+
+ @Override
+ public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ setColor(color);
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ setColor(colorUp);
+ }
+
+ width--;
+ height--;
+ fillRect(x+1, y+1, width-1, height-1);
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ @Override
+ public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ }
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) {
+ sx += getTransform().getTranslateX();
+ sy += getTransform().getTranslateY();
+
+ NativeUtils.nativeScrollRect(canvas,
+ new Rect(sx, sy, sx + width, sy + height),
+ dx, dy);
+ }
+}
diff --git a/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java b/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
new file mode 100644
index 0000000..0c888cd
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+import android.graphics.Canvas;
+
+public class AndroidGraphicsConfiguration extends GraphicsConfiguration {
+
+ @Override
+ public BufferedImage createCompatibleImage(int width, int height) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BufferedImage createCompatibleImage(int width, int height,
+ int transparency) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public VolatileImage createCompatibleVolatileImage(int width, int height) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ int transparency) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Rectangle getBounds() {
+ Canvas c = AndroidGraphics2D.getAndroidCanvas();
+ if(c != null)
+ return new Rectangle(0, 0, c.getWidth(), c.getHeight());
+ return null;
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ColorModel getColorModel(int transparency) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AffineTransform getDefaultTransform() {
+ return new AffineTransform();
+ }
+
+ @Override
+ public GraphicsDevice getDevice() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AffineTransform getNormalizingTransform() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidGraphicsFactory.java b/awt/com/android/internal/awt/AndroidGraphicsFactory.java
new file mode 100644
index 0000000..ca255b5
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphicsFactory.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.peer.FontPeer;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.font.AndroidFont;
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.font.AndroidFontManager;
+import org.apache.harmony.awt.wtk.NativeWindow;
+import org.apache.harmony.awt.wtk.WindowFactory;
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.content.Context;
+
+public class AndroidGraphicsFactory extends CommonGraphics2DFactory {
+
+ public GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Font embedFont(String fontFilePath) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public FontManager getFontManager() {
+ return AndroidFontManager.inst;
+ }
+
+ public FontMetrics getFontMetrics(Font font) {
+ return new FontMetricsImpl(font);
+ }
+
+ public FontPeer getFontPeer(Font font) {
+ //return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize());
+ return new AndroidFont(font.getName(), font.getStyle(), font.getSize());
+ }
+
+ public Graphics2D getGraphics2D(NativeWindow win, int translateX,
+ int translateY, MultiRectArea clip) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Graphics2D getGraphics2D(NativeWindow win, int translateX,
+ int translateY, int width, int height) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Graphics2D getGraphics2D(Context ctx, Canvas c, Paint p) {
+ return AndroidGraphics2D.getInstance(ctx, c, p);
+ }
+
+ public Graphics2D getGraphics2D(Canvas c, Paint p) {
+ throw new RuntimeException("Not supported!");
+ }
+
+ public Graphics2D getGraphics2D() {
+ return AndroidGraphics2D.getInstance();
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidImageDecoder.java b/awt/com/android/internal/awt/AndroidImageDecoder.java
new file mode 100644
index 0000000..81b2e1a
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidImageDecoder.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.awt;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+//import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.ImageDecoder;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class AndroidImageDecoder extends ImageDecoder {
+
+ private static final int hintflags =
+ ImageConsumer.SINGLEFRAME | // PNG is a static image
+ ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+ ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+
+ // Each pixel is a grayscale sample.
+ private static final int PNG_COLOR_TYPE_GRAY = 0;
+ // Each pixel is an R,G,B triple.
+ private static final int PNG_COLOR_TYPE_RGB = 2;
+ // Each pixel is a palette index, a PLTE chunk must appear.
+ private static final int PNG_COLOR_TYPE_PLTE = 3;
+ // Each pixel is a grayscale sample, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+ // Each pixel is an R,G,B triple, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+ private static final int NB_OF_LINES_PER_CHUNK = 1; // 0 = full image
+
+ Bitmap bm; // The image as decoded by Android
+
+ // Header information
+ int imageWidth; // Image size
+ int imageHeight;
+ int colorType; // One of the PNG_ constants from above
+ int bitDepth; // Number of bits per color
+ byte cmap[]; // The color palette for index color models
+ ColorModel model; // The corresponding AWT color model
+
+ boolean transferInts; // Is transfer of type int or byte?
+ int dataElementsPerPixel;
+
+ // Buffers for decoded image data
+ byte byteOut[];
+ int intOut[];
+
+
+ public AndroidImageDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ dataElementsPerPixel = 1;
+ }
+
+ @Override
+ /**
+ * All the decoding is done in Android
+ *
+ * AWT???: Method returns only once the image is completly
+ * decoded; decoding is not done asynchronously
+ */
+ public void decodeImage() throws IOException {
+ try {
+ bm = BitmapFactory.decodeStream(inputStream);
+ if (bm == null) {
+ throw new IOException("Input stream empty and no image cached");
+ }
+
+ // Check size
+ imageWidth = bm.getWidth();
+ imageHeight = bm.getHeight();
+ if (imageWidth < 0 || imageHeight < 0 ) {
+ throw new RuntimeException("Illegal image size: "
+ + imageWidth + ", " + imageHeight);
+ }
+
+ // We got the image fully decoded; now send all image data to AWT
+ setDimensions(imageWidth, imageHeight);
+ model = createColorModel();
+ setColorModel(model);
+ setHints(hintflags);
+ setProperties(new Hashtable<Object, Object>()); // Empty
+ sendPixels(NB_OF_LINES_PER_CHUNK != 0 ? NB_OF_LINES_PER_CHUNK : imageHeight);
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ imageComplete(ImageConsumer.IMAGEERROR);
+ throw e;
+ } finally {
+ closeStream();
+ }
+ }
+
+ /**
+ * Create the AWT color model
+ *
+ * ???AWT: Android Bitmaps are always of type: ARGB-8888-Direct color model
+ *
+ * However, we leave the code here for a more powerfull decoder
+ * that returns a native model, and the conversion is then handled
+ * in AWT. With such a decoder, we would need to get the colorType,
+ * the bitDepth, (and the color palette for an index color model)
+ * from the image and construct the correct color model here.
+ */
+ private ColorModel createColorModel() {
+ ColorModel cm = null;
+ int bmModel = 5; // TODO This doesn't exist: bm.getColorModel();
+ cmap = null;
+
+ switch (bmModel) {
+ // A1_MODEL
+ case 1:
+ colorType = PNG_COLOR_TYPE_GRAY;
+ bitDepth = 1;
+ break;
+
+ // A8_MODEL
+ case 2:
+ colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
+ bitDepth = 8;
+ break;
+
+ // INDEX8_MODEL
+ // RGB_565_MODEL
+ // ARGB_8888_MODEL
+ case 3:
+ case 4:
+ case 5:
+ colorType = bm.hasAlpha() ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB;
+ bitDepth = 8;
+ break;
+
+ default:
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ switch (colorType) {
+
+ case PNG_COLOR_TYPE_GRAY: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ // Create gray color model
+ int numEntries = 1 << bitDepth;
+ int scaleFactor = 255 / (numEntries-1);
+ byte comps[] = new byte[numEntries];
+ for (int i = 0; i < numEntries; i++) {
+ comps[i] = (byte) (i * scaleFactor);
+ }
+ cm = new IndexColorModel(bitDepth, numEntries, comps, comps, comps);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGB: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new DirectColorModel(24, 0xff0000, 0xFF00, 0xFF);
+
+ transferInts = true;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_PLTE: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ if (cmap == null) {
+ throw new IllegalStateException("Palette color type is not supported");
+ }
+
+ cm = new IndexColorModel(bitDepth, cmap.length / 3, cmap, 0, false);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ true, false,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+
+ transferInts = false;
+ dataElementsPerPixel = 2;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGBA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = ColorModel.getRGBdefault();
+
+ transferInts = true;
+ break;
+ }
+ default:
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ return cm;
+ }
+
+ private void sendPixels(int nbOfLinesPerChunk) {
+ int w = imageWidth;
+ int h = imageHeight;
+ int n = 1;
+ if (nbOfLinesPerChunk > 0 && nbOfLinesPerChunk <= h) {
+ n = nbOfLinesPerChunk;
+ }
+
+ if (transferInts) {
+ // Create output buffer
+ intOut = new int[w * n];
+ for (int yi = 0; yi < h; yi += n) {
+ // Last chunk might contain less liness
+ if (n > 1 && h - yi < n ) {
+ n = h - yi;
+ }
+ bm.getPixels(intOut, 0, w, 0, yi, w, n);
+ setPixels(0, yi, w, n, model, intOut, 0, w);
+ }
+ } else {
+ // Android bitmaps always store ints (ARGB-8888 direct model)
+ throw new RuntimeException("Byte transfer not supported");
+ }
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidJavaBlitter.java b/awt/com/android/internal/awt/AndroidJavaBlitter.java
new file mode 100644
index 0000000..423b534
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidJavaBlitter.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+import org.apache.harmony.awt.gl.render.Blitter;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+public class AndroidJavaBlitter implements Blitter {
+
+ private Canvas canvas;
+ private Paint paint;
+ private int colorCache;
+
+ public AndroidJavaBlitter(Canvas c) {
+ this.canvas = c;
+ this.paint = new Paint();
+ this.paint.setStrokeWidth(1);
+ }
+
+ /**
+ * Instead of multiplication and division we are using values from
+ * Lookup tables.
+ */
+ static byte mulLUT[][]; // Lookup table for multiplication
+ static byte divLUT[][]; // Lookup table for division
+
+ static{
+ mulLUT = new byte[256][256];
+ for(int i = 0; i < 256; i++){
+ for(int j = 0; j < 256; j++){
+ mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f);
+ }
+ }
+ divLUT = new byte[256][256];
+ for(int i = 1; i < 256; i++){
+ for(int j = 0; j < i; j++){
+ divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f);
+ }
+ for(int j = i; j < 256; j++){
+ divLUT[i][j] = (byte)255;
+ }
+ }
+ }
+
+ final static int AlphaCompositeMode = 1;
+ final static int XORMode = 2;
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+
+ if(xform == null){
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ double scaledX = dstX / scaleX;
+ double scaledY = dstY / scaleY;
+ AffineTransform at = new AffineTransform();
+ at.setToTranslation(scaledX, scaledY);
+ xform.concatenate(at);
+ sysxform.concatenate(xform);
+ blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+
+ if(sysxform == null) {
+ sysxform = new AffineTransform();
+ }
+ int type = sysxform.getType();
+ switch(type){
+ case AffineTransform.TYPE_TRANSLATION:
+ dstX += sysxform.getTranslateX();
+ dstY += sysxform.getTranslateY();
+ case AffineTransform.TYPE_IDENTITY:
+ simpleBlit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+ width, height, comp, bgcolor, clip);
+ break;
+ default:
+ int srcW = srcSurf.getWidth();
+ int srcH = srcSurf.getHeight();
+
+ int w = srcX + width < srcW ? width : srcW - srcX;
+ int h = srcY + height < srcH ? height : srcH - srcY;
+
+ ColorModel srcCM = srcSurf.getColorModel();
+ Raster srcR = srcSurf.getRaster().createChild(srcX, srcY,
+ w, h, 0, 0, null);
+
+ ColorModel dstCM = dstSurf.getColorModel();
+ WritableRaster dstR = dstSurf.getRaster();
+
+ transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h,
+ sysxform, comp, bgcolor, clip);
+
+ }
+ }
+
+ public void simpleBlit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ // TODO It's possible, though unlikely that we might encounter non-int[]
+ // data buffers. In this case the following code needs to have several
+ // branches that take this into account.
+ data = (DataBufferInt)srcSurf.getRaster().getDataBuffer();
+ int[] pixels = data.getData();
+ if (!srcSurf.getColorModel().hasAlpha()) {
+ // This wouldn't be necessary if Android supported RGB_888.
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = pixels[i] | 0xff000000;
+ }
+ }
+ bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+ canvas.drawBitmap(bmap, dstX, dstY, paint);
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(),
+ srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY,
+ dstSurf.getWidth(), dstSurf.getHeight(),
+ dstSurf.getColorModel(), dstSurf.getRaster(),
+ width, height, comp, bgcolor, clip);
+
+ }
+
+ public void javaBlt(int srcX, int srcY, int srcW, int srcH,
+ ColorModel srcCM, Raster srcRast, int dstX, int dstY,
+ int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Composite comp, Color bgcolor,
+ MultiRectArea clip){
+
+ int srcX2 = srcW - 1;
+ int srcY2 = srcH - 1;
+ int dstX2 = dstW - 1;
+ int dstY2 = dstH - 1;
+
+ if(srcX < 0){
+ width += srcX;
+ srcX = 0;
+ }
+ if(srcY < 0){
+ height += srcY;
+ srcY = 0;
+ }
+
+ if(dstX < 0){
+ width += dstX;
+ srcX -= dstX;
+ dstX = 0;
+ }
+ if(dstY < 0){
+ height += dstY;
+ srcY -= dstY;
+ dstY = 0;
+ }
+
+ if(srcX > srcX2 || srcY > srcY2) {
+ return;
+ }
+ if(dstX > dstX2 || dstY > dstY2) {
+ return;
+ }
+
+ if(srcX + width > srcX2) {
+ width = srcX2 - srcX + 1;
+ }
+ if(srcY + height > srcY2) {
+ height = srcY2 - srcY + 1;
+ }
+ if(dstX + width > dstX2) {
+ width = dstX2 - dstX + 1;
+ }
+ if(dstY + height > dstY2) {
+ height = dstY2 - dstY + 1;
+ }
+
+ if(width <= 0 || height <= 0) {
+ return;
+ }
+
+ int clipRects[];
+ if(clip != null) {
+ clipRects = clip.rect;
+ } else {
+ clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1};
+ }
+
+ boolean isAlphaComp = false;
+ int rule = 0;
+ float alpha = 0;
+ boolean isXORComp = false;
+ Color xorcolor = null;
+ CompositeContext cont = null;
+
+ if(comp instanceof AlphaComposite){
+ isAlphaComp = true;
+ AlphaComposite ac = (AlphaComposite) comp;
+ rule = ac.getRule();
+ alpha = ac.getAlpha();
+ }else if(comp instanceof XORComposite){
+ isXORComp = true;
+ XORComposite xcomp = (XORComposite) comp;
+ xorcolor = xcomp.getXORColor();
+ }else{
+ cont = comp.createContext(srcCM, dstCM, null);
+ }
+
+ for(int i = 1; i < clipRects[0]; i += 4){
+ int _sx = srcX;
+ int _sy = srcY;
+
+ int _dx = dstX;
+ int _dy = dstY;
+
+ int _w = width;
+ int _h = height;
+
+ int cx = clipRects[i]; // Clipping left top X
+ int cy = clipRects[i + 1]; // Clipping left top Y
+ int cx2 = clipRects[i + 2]; // Clipping right bottom X
+ int cy2 = clipRects[i + 3]; // Clipping right bottom Y
+
+ if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) {
+ continue;
+ }
+
+ if(cx > _dx){
+ int shx = cx - _dx;
+ _w -= shx;
+ _dx = cx;
+ _sx += shx;
+ }
+
+ if(cy > _dy){
+ int shy = cy - _dy;
+ _h -= shy;
+ _dy = cy;
+ _sy += shy;
+ }
+
+ if(_dx + _w > cx2 + 1){
+ _w = cx2 - _dx + 1;
+ }
+
+ if(_dy + _h > cy2 + 1){
+ _h = cy2 - _dy + 1;
+ }
+
+ if(_sx > srcX2 || _sy > srcY2) {
+ continue;
+ }
+
+ if(isAlphaComp){
+ alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, rule, alpha, bgcolor);
+ }else if(isXORComp){
+ xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, xorcolor);
+ }else{
+ Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null);
+ WritableRaster dr = dstRast.createWritableChild(_dx, _dy,
+ _w, _h, 0, 0, null);
+ cont.compose(sr, dr, dr);
+ }
+ }
+
+ }
+
+ DataBufferInt data;
+ Bitmap bmap, bmp;
+
+ void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, int rule, float alpha, Color bgcolor){
+
+ Object srcPixel = getTransferArray(srcRast, 1);
+ data = (DataBufferInt)srcRast.getDataBuffer();
+ int pix[] = data.getData();
+ bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565);
+ canvas.drawBitmap(bmap, dstX, dstY, paint);
+ }
+
+ void render(int[] img, int x, int y, int width, int height) {
+ canvas.drawBitmap(Bitmap.createBitmap(img, width, height, Bitmap.Config.ARGB_8888), x, y, paint);
+ }
+
+ void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Color xorcolor){
+
+ data = (DataBufferInt)srcRast.getDataBuffer();
+ int pix[] = data.getData();
+ bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565);
+ canvas.drawBitmap(bmap, dstX, dstY, paint);
+ }
+
+ private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY,
+ ColorModel dstCM, WritableRaster dstR, int dstX, int dstY,
+ int width, int height, AffineTransform at, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ data = (DataBufferInt)srcR.getDataBuffer();
+ int[] pixels = data.getData();
+ if (!srcCM.hasAlpha()) {
+ // This wouldn't be necessary if Android supported RGB_888.
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = pixels[i] | 0xff000000;
+ }
+ }
+ bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+
+ Matrix tm = new Matrix();
+ tm.setConcat(canvas.getMatrix(), AndroidGraphics2D.createMatrixObj(at));
+ if(at.getType() > 1) {
+ bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, true);
+ } else {
+ bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, false);
+ }
+ canvas.drawBitmap(bmp, dstX + (float)at.getTranslateX(), dstY + (float)at.getTranslateY(), paint);
+ }
+
+ private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) {
+ int x = r.x;
+ int y = r.y;
+ int width = r.width;
+ int height = r.height;
+
+ float[] corners = {
+ x, y,
+ x + width, y,
+ x + width, y + height,
+ x, y + height
+ };
+
+ at.transform(corners, 0, corners, 0, 4);
+
+ Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+ bounds.add(corners[2], corners[3]);
+ bounds.add(corners[4], corners[5]);
+ bounds.add(corners[6], corners[7]);
+
+ return bounds;
+ }
+
+ private int compose(int srcRGB, boolean isSrcAlphaPre,
+ int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre,
+ int rule, int srcConstAlpha){
+
+ int sa, sr, sg, sb, da, dr, dg, db;
+
+ sa = (srcRGB >> 24) & 0xff;
+ sr = (srcRGB >> 16) & 0xff;
+ sg = (srcRGB >> 8) & 0xff;
+ sb = srcRGB & 0xff;
+
+ if(isSrcAlphaPre){
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[srcConstAlpha][sr] & 0xff;
+ sg = mulLUT[srcConstAlpha][sg] & 0xff;
+ sb = mulLUT[srcConstAlpha][sb] & 0xff;
+ }else{
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[sa][sr] & 0xff;
+ sg = mulLUT[sa][sg] & 0xff;
+ sb = mulLUT[sa][sb] & 0xff;
+ }
+
+ da = (dstRGB >> 24) & 0xff;
+ dr = (dstRGB >> 16) & 0xff;
+ dg = (dstRGB >> 8) & 0xff;
+ db = dstRGB & 0xff;
+
+ if(!isDstAlphaPre){
+ dr = mulLUT[da][dr] & 0xff;
+ dg = mulLUT[da][dg] & 0xff;
+ db = mulLUT[da][db] & 0xff;
+ }
+
+ int Fs = 0;
+ int Fd = 0;
+ switch(rule){
+ case AlphaComposite.CLEAR:
+ break;
+
+ case AlphaComposite.DST:
+ Fd = 255;
+ break;
+
+ case AlphaComposite.DST_ATOP:
+ Fs = 255 - da;
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_IN:
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_OUT:
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.DST_OVER:
+ Fs = 255 - da;
+ Fd = 255;
+ break;
+
+ case AlphaComposite.SRC:
+ Fs = 255;
+ break;
+
+ case AlphaComposite.SRC_ATOP:
+ Fs = da;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.SRC_IN:
+ Fs = da;
+ break;
+
+ case AlphaComposite.SRC_OUT:
+ Fs = 255 - da;
+ break;
+
+ case AlphaComposite.SRC_OVER:
+ Fs = 255;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.XOR:
+ Fs = 255 - da;
+ Fd = 255 - sa;
+ break;
+ }
+ dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff);
+ dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff);
+ db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff);
+
+ da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff);
+
+ if(!isDstAlphaPre){
+ if(da != 255){
+ dr = divLUT[da][dr] & 0xff;
+ dg = divLUT[da][dg] & 0xff;
+ db = divLUT[da][db] & 0xff;
+ }
+ }
+ if(!dstHasAlpha) {
+ da = 0xff;
+ }
+ dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db;
+
+ return dstRGB;
+
+ }
+
+ /**
+ * Allocate an array that can be use to store the result for a
+ * Raster.getDataElements call.
+ * @param raster Raster (type) where the getDataElements call will be made.
+ * @param nbPixels How many pixels to store in the array at most
+ * @return the result array or null
+ */
+ private Object getTransferArray(Raster raster, int nbPixels) {
+ int transferType = raster.getTransferType();
+ int nbDataElements = raster.getSampleModel().getNumDataElements();
+ int n = nbDataElements * nbPixels;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ return new byte[n];
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ return new short[n];
+ case DataBuffer.TYPE_INT:
+ return new int[n];
+ case DataBuffer.TYPE_FLOAT:
+ return new float[n];
+ case DataBuffer.TYPE_DOUBLE:
+ return new double[n];
+ case DataBuffer.TYPE_UNDEFINED:
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Draw a pixel
+ */
+ private void dot(int x, int y, int clr) {
+ if (colorCache != clr) {
+ paint.setColor(clr);
+ colorCache = clr;
+ }
+ canvas.drawLine(x, y, x + 1, y + 1, paint);
+ }
+}
diff --git a/awt/com/android/internal/awt/AndroidNativeEventQueue.java b/awt/com/android/internal/awt/AndroidNativeEventQueue.java
new file mode 100644
index 0000000..fc30614
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidNativeEventQueue.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+
+public class AndroidNativeEventQueue extends NativeEventQueue {
+
+ private Object eventMonitor;
+
+ public AndroidNativeEventQueue() {
+ super();
+ eventMonitor = getEventMonitor();
+ }
+
+ @Override
+ public void awake() {
+ synchronized (eventMonitor) {
+ eventMonitor.notify();
+ }
+ }
+
+ @Override
+ public void dispatchEvent() {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ }
+
+ @Override
+ public long getJavaWindow() {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ return 0;
+ }
+
+ @Override
+ public void performLater(Task task) {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ }
+
+ @Override
+ public void performTask(Task task) {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ }
+
+ @Override
+ public boolean waitEvent() {
+ while (isEmpty() ) {
+ synchronized (eventMonitor) {
+ try {
+ eventMonitor.wait(1000);
+ } catch (InterruptedException ignore) {
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidWTK.java b/awt/com/android/internal/awt/AndroidWTK.java
new file mode 100644
index 0000000..1609d11
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidWTK.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.awt.GraphicsDevice;
+
+import org.apache.harmony.awt.wtk.CursorFactory;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.NativeIM;
+import org.apache.harmony.awt.wtk.NativeMouseInfo;
+import org.apache.harmony.awt.wtk.NativeRobot;
+import org.apache.harmony.awt.wtk.SystemProperties;
+import org.apache.harmony.awt.wtk.WTK;
+import org.apache.harmony.awt.wtk.WindowFactory;
+
+public class AndroidWTK extends WTK {
+
+ private AndroidGraphicsFactory mAgf;
+ private AndroidNativeEventQueue mAneq;
+
+ @Override
+ public CursorFactory getCursorFactory() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public GraphicsFactory getGraphicsFactory() {
+ if(mAgf == null) {
+ mAgf = new AndroidGraphicsFactory();
+ }
+ return mAgf;
+ }
+
+ @Override
+ public NativeEventQueue getNativeEventQueue() {
+ if(mAneq == null) {
+ mAneq = new AndroidNativeEventQueue();
+ }
+ return mAneq;
+ }
+
+ @Override
+ public NativeIM getNativeIM() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NativeMouseInfo getNativeMouseInfo() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NativeRobot getNativeRobot(GraphicsDevice screen) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SystemProperties getSystemProperties() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public WindowFactory getWindowFactory() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AwtFactory.java b/awt/com/android/internal/awt/AwtFactory.java
new file mode 100644
index 0000000..6e667b2
--- /dev/null
+++ b/awt/com/android/internal/awt/AwtFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+public class AwtFactory {
+
+ private static GraphicsFactory gf;
+
+ /**
+ * Use this method to get acces to AWT drawing primitives and to
+ * render into the surface area of a Android widget. Origin and
+ * clip of the returned graphics object are the same as in the
+ * corresponding Android widget.
+ *
+ * @param c Canvas of the android widget to draw into
+ * @param p The default drawing parameters such as font,
+ * stroke, foreground and background colors, etc.
+ * @return The AWT Graphics object that makes all AWT
+ * drawing primitives available in the androind world.
+ */
+ public static Graphics2D getAwtGraphics(Canvas c, Paint p) {
+ // AWT?? TODO: test it!
+ if (null == gf) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ gf = tk.getGraphicsFactory();
+ }
+ return gf.getGraphics2D(c, p);
+ }
+
+}
diff --git a/awt/com/android/internal/awt/ImageOutputStreamWrapper.java b/awt/com/android/internal/awt/ImageOutputStreamWrapper.java
new file mode 100644
index 0000000..92185fd
--- /dev/null
+++ b/awt/com/android/internal/awt/ImageOutputStreamWrapper.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.imageio.stream.ImageOutputStream;
+
+public class ImageOutputStreamWrapper extends OutputStream {
+
+ protected ImageOutputStream mIos;
+
+ private byte[] mBuff;
+
+ public ImageOutputStreamWrapper(ImageOutputStream ios) {
+ if (null == ios) {
+ throw new IllegalArgumentException("ImageOutputStream must not be null");
+ }
+ this.mIos = ios;
+ this.mBuff = new byte[1];
+ }
+
+ public ImageOutputStream getImageOutputStream() {
+ return mIos;
+ }
+
+ @Override
+ public void write(int oneByte) throws IOException {
+ mBuff[0] = (byte)oneByte;
+ mIos.write(mBuff, 0, 1);
+ }
+
+ public void write(byte[] b) throws IOException {
+ mIos.write(b, 0, b.length);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ mIos.write(b, off, len);
+ }
+
+ public void flush() throws IOException {
+ mIos.flush();
+ }
+
+ public void close() throws IOException {
+ if (mIos == null) {
+ throw new IOException("Stream already closed");
+ }
+ mIos = null;
+ }
+}
diff --git a/awt/java/awt/AWTEvent.java b/awt/java/awt/AWTEvent.java
new file mode 100644
index 0000000..1ed9a37
--- /dev/null
+++ b/awt/java/awt/AWTEvent.java
@@ -0,0 +1,618 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev, Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.util.EventObject;
+import java.util.Hashtable;
+import java.util.EventListener;
+
+import java.awt.event.*;
+
+/**
+ * The abstract AWT events is base class for all AWT events.
+ * This class and its subclasses supercede the original java.awt.Event class.
+ */
+public abstract class AWTEvent extends EventObject {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1825314779160409405L;
+
+ /** The Constant COMPONENT_EVENT_MASK indicates the event relates to a component. */
+ public static final long COMPONENT_EVENT_MASK = 1;
+
+ /** The Constant CONTAINER_EVENT_MASK indicates the event relates to a container. */
+ public static final long CONTAINER_EVENT_MASK = 2;
+
+ /** The Constant FOCUS_EVENT_MASK indicates the event relates to the focus. */
+ public static final long FOCUS_EVENT_MASK = 4;
+
+ /** The Constant KEY_EVENT_MASK indicates the event relates to a key. */
+ public static final long KEY_EVENT_MASK = 8;
+
+ /** The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse. */
+ public static final long MOUSE_EVENT_MASK = 16;
+
+ /** The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a mouse motion. */
+ public static final long MOUSE_MOTION_EVENT_MASK = 32;
+
+ /** The Constant WINDOW_EVENT_MASK indicates the event relates to a window. */
+ public static final long WINDOW_EVENT_MASK = 64;
+
+ /** The Constant ACTION_EVENT_MASK indicates the event relates to an action. */
+ public static final long ACTION_EVENT_MASK = 128;
+
+ /** The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an adjustment. */
+ public static final long ADJUSTMENT_EVENT_MASK = 256;
+
+ /** The Constant ITEM_EVENT_MASK indicates the event relates to an item. */
+ public static final long ITEM_EVENT_MASK = 512;
+
+ /** The Constant TEXT_EVENT_MASK indicates the event relates to text. */
+ public static final long TEXT_EVENT_MASK = 1024;
+
+ /** The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an input method. */
+ public static final long INPUT_METHOD_EVENT_MASK = 2048;
+
+ /** The Constant PAINT_EVENT_MASK indicates the event relates to a paint method. */
+ public static final long PAINT_EVENT_MASK = 8192;
+
+ /** The Constant INVOCATION_EVENT_MASK indicates the event relates to a method invocation. */
+ public static final long INVOCATION_EVENT_MASK = 16384;
+
+ /** The Constant HIERARCHY_EVENT_MASK indicates the event relates to a hierarchy. */
+ public static final long HIERARCHY_EVENT_MASK = 32768;
+
+ /**
+ * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to hierarchy bounds.
+ */
+ public static final long HIERARCHY_BOUNDS_EVENT_MASK = 65536;
+
+ /** The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the mouse wheel. */
+ public static final long MOUSE_WHEEL_EVENT_MASK = 131072;
+
+ /** The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a window state. */
+ public static final long WINDOW_STATE_EVENT_MASK = 262144;
+
+ /** The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a window focus. */
+ public static final long WINDOW_FOCUS_EVENT_MASK = 524288;
+
+ /** The Constant RESERVED_ID_MAX indicates the maximum value for reserved
+ * AWT event IDs.
+ */
+ public static final int RESERVED_ID_MAX = 1999;
+
+ /** The Constant eventsMap. */
+ private static final Hashtable<Integer, EventDescriptor> eventsMap = new Hashtable<Integer, EventDescriptor>();
+
+ /** The converter. */
+ private static EventConverter converter;
+
+ /** The ID of the event. */
+ protected int id;
+
+ /**
+ * The consumed indicates whether or not the event is sent back down to
+ * the peer once the source has processed it (false means it's sent to the peer,
+ * true means it's not).
+ */
+ protected boolean consumed;
+
+ /** The dispatched by kfm. */
+ boolean dispatchedByKFM;
+
+ /** The is posted. */
+ transient boolean isPosted;
+
+ static {
+ eventsMap.put(new Integer(KeyEvent.KEY_TYPED),
+ new EventDescriptor(KEY_EVENT_MASK, KeyListener.class));
+ eventsMap.put(new Integer(KeyEvent.KEY_PRESSED),
+ new EventDescriptor(KEY_EVENT_MASK, KeyListener.class));
+ eventsMap.put(new Integer(KeyEvent.KEY_RELEASED),
+ new EventDescriptor(KEY_EVENT_MASK, KeyListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED),
+ new EventDescriptor(MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED),
+ new EventDescriptor(MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL),
+ new EventDescriptor(MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED),
+ new EventDescriptor(FOCUS_EVENT_MASK, FocusListener.class));
+ eventsMap.put(new Integer(FocusEvent.FOCUS_LOST),
+ new EventDescriptor(FOCUS_EVENT_MASK, FocusListener.class));
+ eventsMap.put(new Integer(PaintEvent.PAINT),
+ new EventDescriptor(PAINT_EVENT_MASK, null));
+ eventsMap.put(new Integer(PaintEvent.UPDATE),
+ new EventDescriptor(PAINT_EVENT_MASK, null));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED),
+ new EventDescriptor(WINDOW_STATE_EVENT_MASK, WindowStateListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS),
+ new EventDescriptor(WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS),
+ new EventDescriptor(WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED),
+ new EventDescriptor(HIERARCHY_EVENT_MASK, HierarchyListener.class));
+ eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED),
+ new EventDescriptor(HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class));
+ eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED),
+ new EventDescriptor(HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class));
+ eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED),
+ new EventDescriptor(CONTAINER_EVENT_MASK, ContainerListener.class));
+ eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED),
+ new EventDescriptor(CONTAINER_EVENT_MASK, ContainerListener.class));
+ eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED),
+ new EventDescriptor(INPUT_METHOD_EVENT_MASK, InputMethodListener.class));
+ eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED),
+ new EventDescriptor(INPUT_METHOD_EVENT_MASK, InputMethodListener.class));
+ eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT),
+ new EventDescriptor(INVOCATION_EVENT_MASK, null));
+ eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED),
+ new EventDescriptor(ITEM_EVENT_MASK, ItemListener.class));
+ eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED),
+ new EventDescriptor(TEXT_EVENT_MASK, TextListener.class));
+ eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED),
+ new EventDescriptor(ACTION_EVENT_MASK, ActionListener.class));
+ eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED),
+ new EventDescriptor(ADJUSTMENT_EVENT_MASK, AdjustmentListener.class));
+ converter = new EventConverter();
+ }
+
+ /**
+ * Instantiates a new AWT event from the specified Event object.
+ *
+ * @param event the Event object.
+ */
+ public AWTEvent(Event event) {
+ this(event.target, event.id);
+ }
+
+ /**
+ * Instantiates a new AWT event with the specified object and type.
+ *
+ * @param source the source Object.
+ * @param id the event's type.
+ */
+ public AWTEvent(Object source, int id) {
+ super(source);
+ this.id = id;
+ consumed = false;
+ }
+
+ /**
+ * Gets the event's type.
+ *
+ * @return the event type ID.
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Sets a new source for the AWTEvent.
+ *
+ * @param newSource the new source Object for the AWTEvent.
+ */
+ public void setSource(Object newSource) {
+ source = newSource;
+ }
+
+ /**
+ * Returns a String representation of the AWTEvent.
+ *
+ * @return the String representation of the AWTEvent.
+ */
+ @Override
+ public String toString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * AWTEvent event = new AWTEvent(new Component(){}, 1){};
+ * System.out.println(event);
+ */
+ String name = ""; //$NON-NLS-1$
+
+ if (source instanceof Component && (source != null)) {
+ Component comp = (Component) getSource();
+ name = comp.getName();
+ if (name == null) {
+ name = ""; //$NON-NLS-1$
+ }
+ }
+
+ return (getClass().getName() + "[" + paramString() + "]" //$NON-NLS-1$ //$NON-NLS-2$
+ + " on " + (name.length() > 0 ? name : source)); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a string representation of the AWTEvent state.
+ *
+ * @return a string representation of the AWTEvent state.
+ */
+ public String paramString() {
+ //nothing to implement: all event types must override this method
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Checks whether or not this AWTEvent has been consumed.
+ *
+ * @return true, if this AWTEvent has been consumed, false otherwise.
+ */
+ protected boolean isConsumed() {
+ return consumed;
+ }
+
+ /**
+ * Consumes the AWTEvent.
+ */
+ protected void consume() {
+ consumed = true;
+ }
+
+ /**
+ * Convert AWTEvent object to a corresponding (deprecated) Event object.
+ *
+ * @return new Event object which is a converted AWTEvent object or null
+ * if the conversion is not possible
+ */
+ Event getEvent() {
+
+ if (id == ActionEvent.ACTION_PERFORMED) {
+ ActionEvent ae = (ActionEvent) this;
+ return converter.convertActionEvent(ae);
+
+ } else if (id == AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED) {
+ AdjustmentEvent ae = (AdjustmentEvent) this;
+ return converter.convertAdjustmentEvent(ae);
+
+//???AWT
+// } else if (id == ComponentEvent.COMPONENT_MOVED
+// && source instanceof Window) {
+// //the only type of Component events is COMPONENT_MOVED on window
+// ComponentEvent ce = (ComponentEvent) this;
+// return converter.convertComponentEvent(ce);
+
+ } else if (id >= FocusEvent.FOCUS_FIRST && id <= FocusEvent.FOCUS_LAST) {
+ //nothing to convert
+
+//???AWT
+// } else if (id == ItemEvent.ITEM_STATE_CHANGED) {
+// ItemEvent ie = (ItemEvent) this;
+// return converter.convertItemEvent(ie);
+
+ } else if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) {
+ KeyEvent ke = (KeyEvent) this;
+ return converter.convertKeyEvent(ke);
+ } else if (id >= MouseEvent.MOUSE_FIRST && id <= MouseEvent.MOUSE_LAST) {
+ MouseEvent me = (MouseEvent) this;
+ return converter.convertMouseEvent(me);
+ } else if (id == WindowEvent.WINDOW_CLOSING
+ || id == WindowEvent.WINDOW_ICONIFIED
+ || id == WindowEvent.WINDOW_DEICONIFIED) {
+ //nothing to convert
+ } else {
+ return null;
+ }
+ return new Event(source, id, null);
+ }
+
+
+ /**
+ * The Class EventDescriptor.
+ */
+ static final class EventDescriptor {
+
+ /** The event mask. */
+ final long eventMask;
+
+ /** The listener type. */
+ final Class<? extends EventListener> listenerType;
+
+ /**
+ * Instantiates a new event descriptor.
+ *
+ * @param eventMask the event mask
+ * @param listenerType the listener type
+ */
+ EventDescriptor(long eventMask, Class<? extends EventListener> listenerType) {
+ this.eventMask = eventMask;
+ this.listenerType = listenerType;
+ }
+
+ }
+
+ /**
+ * The Class EventTypeLookup.
+ */
+ static final class EventTypeLookup {
+
+ /** The last event. */
+ private AWTEvent lastEvent = null;
+
+ /** The last event descriptor. */
+ private EventDescriptor lastEventDescriptor = null;
+
+ /**
+ * Gets the event descriptor.
+ *
+ * @param event the event
+ *
+ * @return the event descriptor
+ */
+ EventDescriptor getEventDescriptor(AWTEvent event) {
+ synchronized (this) {
+ if (event != lastEvent) {
+ lastEvent = event;
+ lastEventDescriptor = eventsMap.get(new Integer(event.id));
+ }
+
+ return lastEventDescriptor;
+ }
+ }
+
+ /**
+ * Gets the event mask.
+ *
+ * @param event the event
+ *
+ * @return the event mask
+ */
+ long getEventMask(AWTEvent event) {
+ final EventDescriptor ed = getEventDescriptor(event);
+ return ed == null ? -1 : ed.eventMask;
+ }
+ }
+
+ /**
+ * The Class EventConverter.
+ */
+ static final class EventConverter {
+
+ /** The Constant OLD_MOD_MASK. */
+ static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK
+ | Event.META_MASK | Event.SHIFT_MASK;
+
+ /**
+ * Convert action event.
+ *
+ * @param ae the ae
+ *
+ * @return the event
+ */
+ Event convertActionEvent(ActionEvent ae) {
+ Event evt = new Event(ae.getSource(), ae.getID(), ae.getActionCommand());
+ evt.when = ae.getWhen();
+ evt.modifiers = ae.getModifiers() & OLD_MOD_MASK;
+
+ /* if (source instanceof Button) {
+ arg = ((Button) source).getLabel();
+ } else if (source instanceof Checkbox) {
+ arg = new Boolean(((Checkbox) source).getState());
+ } else if (source instanceof CheckboxMenuItem) {
+ arg = ((CheckboxMenuItem) source).getLabel();
+ } else if (source instanceof Choice) {
+ arg = ((Choice) source).getSelectedItem();
+ } else if (source instanceof List) {
+ arg = ((List) source).getSelectedItem();
+ } else if (source instanceof MenuItem) {
+ arg = ((MenuItem) source).getLabel();
+ } else if (source instanceof TextField) {
+ arg = ((TextField) source).getText();
+ }
+*/
+ return evt;
+ }
+
+
+ /**
+ * Convert adjustment event.
+ *
+ * @param ae the ae
+ *
+ * @return the event
+ */
+ Event convertAdjustmentEvent(AdjustmentEvent ae) {
+ //TODO: Event.SCROLL_BEGIN/SCROLL_END
+ return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1,
+ new Integer(ae.getValue()));
+ }
+
+ /**
+ * Convert component event.
+ *
+ * @param ce the ce
+ *
+ * @return the event
+ */
+ Event convertComponentEvent(ComponentEvent ce) {
+ Component comp = ce.getComponent();
+ Event evt = new Event(comp, Event.WINDOW_MOVED, null);
+ evt.x = comp.getX();
+ evt.y = comp.getY();
+ return evt;
+ }
+
+ //???AWT
+ /*
+ Event convertItemEvent(ItemEvent ie) {
+ int oldId = ie.id + ie.getStateChange() - 1;
+ Object source = ie.source;
+ int idx = -1;
+ if (source instanceof List) {
+ List list = (List) source;
+ idx = list.getSelectedIndex();
+ }
+ else if (source instanceof Choice) {
+ Choice choice = (Choice) source;
+ idx = choice.getSelectedIndex();
+ }
+ Object arg = idx >= 0 ? new Integer(idx) : null;
+ return new Event(source, oldId, arg);
+ }
+ */
+
+ /**
+ * Convert key event.
+ *
+ * @param ke the ke
+ *
+ * @return the event
+ */
+ Event convertKeyEvent(KeyEvent ke) {
+ int oldId = ke.id;
+ //leave only old Event's modifiers
+
+ int mod = ke.getModifiers() & OLD_MOD_MASK;
+ Component comp = ke.getComponent();
+ char keyChar = ke.getKeyChar();
+ int keyCode = ke.getKeyCode();
+ int key = convertKey(keyChar, keyCode);
+ if (key >= Event.HOME && key <= Event.INSERT) {
+ oldId += 2; //non-ASCII key -> action key
+ }
+ return new Event(comp, ke.getWhen(), oldId, 0, 0, key, mod);
+ }
+
+ /**
+ * Convert mouse event.
+ *
+ * @param me the me
+ *
+ * @return the event
+ */
+ Event convertMouseEvent(MouseEvent me) {
+ int id = me.id;
+ if (id != MouseEvent.MOUSE_CLICKED) {
+ Event evt = new Event(me.source, id, null);
+ evt.x = me.getX();
+ evt.y = me.getY();
+ int mod = me.getModifiers();
+ //in Event modifiers mean button number for mouse events:
+ evt.modifiers = mod & (Event.ALT_MASK | Event.META_MASK);
+ if (id == MouseEvent.MOUSE_PRESSED) {
+ evt.clickCount = me.getClickCount();
+ }
+ return evt;
+ }
+ return null;
+ }
+
+ /**
+ * Convert key.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ *
+ * @return the int
+ */
+ int convertKey(char keyChar, int keyCode) {
+ int key;
+ //F1 - F12
+ if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) {
+ key = Event.F1 + keyCode - KeyEvent.VK_F1;
+ } else {
+ switch (keyCode) {
+ default: //non-action key
+ key = keyChar;
+ break;
+ //action keys:
+ case KeyEvent.VK_HOME:
+ key = Event.HOME;
+ break;
+ case KeyEvent.VK_END:
+ key = Event.END;
+ break;
+ case KeyEvent.VK_PAGE_UP:
+ key = Event.PGUP;
+ break;
+ case KeyEvent.VK_PAGE_DOWN:
+ key = Event.PGDN;
+ break;
+ case KeyEvent.VK_UP:
+ key = Event.UP;
+ break;
+ case KeyEvent.VK_DOWN:
+ key = Event.DOWN;
+ break;
+ case KeyEvent.VK_LEFT:
+ key = Event.LEFT;
+ break;
+ case KeyEvent.VK_RIGHT:
+ key = Event.RIGHT;
+ break;
+ case KeyEvent.VK_PRINTSCREEN:
+ key = Event.PRINT_SCREEN;
+ break;
+ case KeyEvent.VK_SCROLL_LOCK:
+ key = Event.SCROLL_LOCK;
+ break;
+ case KeyEvent.VK_CAPS_LOCK:
+ key = Event.CAPS_LOCK;
+ break;
+ case KeyEvent.VK_NUM_LOCK:
+ key = Event.NUM_LOCK;
+ break;
+ case KeyEvent.VK_PAUSE:
+ key = Event.PAUSE;
+ break;
+ case KeyEvent.VK_INSERT:
+ key = Event.INSERT;
+ break;
+ }
+ }
+ return key;
+ }
+
+ }
+
+}
diff --git a/awt/java/awt/AWTException.java b/awt/java/awt/AWTException.java
new file mode 100644
index 0000000..70ce6e1
--- /dev/null
+++ b/awt/java/awt/AWTException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+
+/**
+ * The AWTException class is used to provide notification and information
+ * about AWT errors.
+ */
+public class AWTException extends Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1900414231151323879L;
+
+ /**
+ * Instantiates a new AWT exception with the specified message.
+ *
+ * @param msg the specific message for current exception.
+ */
+ public AWTException(String msg) {
+ super(msg);
+ }
+
+}
+
diff --git a/awt/java/awt/AWTKeyStroke.java b/awt/java/awt/AWTKeyStroke.java
new file mode 100644
index 0000000..5e7de4e
--- /dev/null
+++ b/awt/java/awt/AWTKeyStroke.java
@@ -0,0 +1,678 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AWTKeyStroke holds all of the information for the complete act of
+ * typing a character. This includes the events that are generated when
+ * the key is pressed, released, or typed (pressed and released generating
+ * a unicode character result) which are associated with the event
+ * objects KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED, or KeyEvent.KEY_TYPED.
+ * It also holds information about which modifiers (such as control or
+ * shift) were used in conjunction with the keystroke. The following masks
+ * are available to identify the modifiers:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ * <br>
+ * The AWTKeyStroke is unique, and applications should not create their own
+ * instances of AWTKeyStroke. All applications should use getAWTKeyStroke
+ * methods for obtaining instances of AWTKeyStroke.
+ */
+public class AWTKeyStroke implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -6430539691155161871L;
+
+ /** The Constant cache. */
+ private static final Map<AWTKeyStroke, AWTKeyStroke> cache = new HashMap<AWTKeyStroke, AWTKeyStroke>(); //Map<AWTKeyStroke, ? extends AWTKeyStroke>
+
+ /** The Constant keyEventTypesMap. */
+ private static final Map<Integer, String> keyEventTypesMap = new HashMap<Integer, String>(); //Map<int, String>
+
+ private static Constructor<?> subConstructor;
+
+ static {
+ keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED), "pressed"); //$NON-NLS-1$
+ keyEventTypesMap.put(new Integer(KeyEvent.KEY_RELEASED), "released"); //$NON-NLS-1$
+ keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$
+ }
+
+ /** The key char. */
+ private char keyChar;
+
+ /** The key code. */
+ private int keyCode;
+
+ /** The modifiers. */
+ private int modifiers;
+
+ /** The on key release. */
+ private boolean onKeyRelease;
+
+ /**
+ * Instantiates a new AWTKeyStroke.
+ * getAWTKeyStroke method should be used by applications code.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease true if AWTKeyStroke is for a key release, overwise false.
+ */
+ protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
+ boolean onKeyRelease)
+ {
+ setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease);
+ }
+
+ /** Sets the awt key stroke.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease the on key release
+ */
+ private void setAWTKeyStroke( char keyChar, int keyCode, int modifiers,
+ boolean onKeyRelease)
+ {
+ this.keyChar = keyChar;
+ this.keyCode = keyCode;
+ this.modifiers = modifiers;
+ this.onKeyRelease = onKeyRelease;
+ }
+
+ /**
+ * Instantiates a new AWTKeyStroke with default parameters:
+ * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code,
+ * without modifiers and false key realised value.
+ */
+ protected AWTKeyStroke() {
+ this(KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false);
+ }
+
+ /**
+ * Returns the unique number value for AWTKeyStroke object.
+ *
+ * @return the int unique value of the AWTKeyStroke object.
+ */
+ @Override
+ public int hashCode() {
+ return modifiers + ( keyCode != KeyEvent.VK_UNDEFINED ?
+ keyCode : keyChar) + (onKeyRelease ? -1 : 0);
+ }
+
+ /**
+ * Gets the set of modifiers for the AWTKeyStroke object.
+ *
+ * @return the int value which contains modifiers.
+ */
+ public final int getModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Compares the AWTKeyStroke object to the specified object.
+ *
+ * @return true, if objects are identical, overwise false.
+ */
+ @Override
+ public final boolean equals(Object anObject) {
+ if (anObject instanceof AWTKeyStroke) {
+ AWTKeyStroke key = (AWTKeyStroke)anObject;
+ return ((key.keyCode == keyCode) && (key.keyChar == keyChar) &&
+ (key.modifiers == modifiers) &&
+ (key.onKeyRelease == onKeyRelease));
+ }
+ return false;
+ }
+
+ /**
+ * Returns the string representation of the AWTKeyStroke.
+ * This string should contain key stroke properties.
+ *
+ * @return the string representation of the AWTKeyStroke.
+ */
+ @Override
+ public String toString() {
+ int type = getKeyEventType();
+ return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$
+ keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$
+ (type == KeyEvent.KEY_TYPED ? new String(new char[] {keyChar}) :
+ KeyEvent.getKeyText(keyCode));
+ }
+
+ /**
+ * Gets the key code for the AWTKeyStroke object.
+ *
+ * @return the key code for the AWTKeyStroke object.
+ */
+ public final int getKeyCode() {
+ return keyCode;
+ }
+
+ /**
+ * Gets the key character for the AWTKeyStroke object.
+ *
+ * @return the key character for the AWTKeyStroke object.
+ */
+ public final char getKeyChar() {
+ return keyChar;
+ }
+
+ /**
+ * Gets the AWT key stroke.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease the on key release
+ *
+ * @return the AWT key stroke
+ */
+ private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode,
+ int modifiers,
+ boolean onKeyRelease) {
+ AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers, onKeyRelease);
+
+ AWTKeyStroke value = cache.get(key);
+ if (value == null) {
+ value = key;
+ cache.put(key, value);
+ }
+ return value;
+ }
+
+ /**
+ * New instance.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease the on key release
+ *
+ * @return the AWT key stroke
+ */
+ private static AWTKeyStroke newInstance(char keyChar, int keyCode,
+ int modifiers,
+ boolean onKeyRelease) {
+ AWTKeyStroke key;
+ //???AWT
+// if (subConstructor == null) {
+ key = new AWTKeyStroke();
+ //???AWT
+// } else {
+// try {
+// key = (AWTKeyStroke) subConstructor.newInstance();
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+// }
+ int allModifiers = getAllModifiers(modifiers);
+ key.setAWTKeyStroke(keyChar, keyCode, allModifiers, onKeyRelease);
+ return key;
+ }
+
+ /**
+ * Adds the mask.
+ *
+ * @param mod the mod
+ * @param mask the mask
+ *
+ * @return the int
+ */
+ private static int addMask(int mod, int mask) {
+ return ((mod & mask) != 0) ? (mod | mask) : mod;
+ }
+
+ /**
+ * return all (old & new) modifiers corresponding to.
+ *
+ * @param mod old or new modifiers
+ *
+ * @return old and new modifiers together
+ */
+ static int getAllModifiers(int mod) {
+ int allMod = mod;
+ int shift = (InputEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK);
+ int ctrl = (InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK);
+ int meta = (InputEvent.META_MASK | InputEvent.META_DOWN_MASK);
+ int alt = (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK);
+ int altGr = (InputEvent.ALT_GRAPH_MASK | InputEvent.ALT_GRAPH_DOWN_MASK);
+ // button modifiers are not converted between old & new
+
+ allMod = addMask(allMod, shift);
+ allMod = addMask(allMod, ctrl);
+ allMod = addMask(allMod, meta);
+ allMod = addMask(allMod, alt);
+ allMod = addMask(allMod, altGr);
+
+ return allMod;
+ }
+
+ /**
+ * Returns an instance of AWTKeyStroke for parsed string.
+ *
+ * The string must have the following syntax:
+ *<p>
+ * &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)
+ *<p>
+ * modifiers := shift | control | ctrl | meta | alt | altGraph
+ * <br>
+ * typedID := typed <typedKey>
+ * <br>
+ * typedKey := string of length 1 giving the Unicode character.
+ * <br>
+ * pressedReleasedID := (pressed | released) <key>
+ * <br>
+ * key := KeyEvent key code name, i.e. the name following "VK_".
+ * <p>
+ * @param s the String which contains key stroke parameters.
+ *
+ * @return the AWTKeyStroke for string.
+ *
+ * @throws IllegalArgumentException if string has incorrect format or null.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(String s) {
+ if (s == null) {
+ // awt.65=null argument
+ throw new IllegalArgumentException(Messages.getString("awt.65")); //$NON-NLS-1$
+ }
+
+ StringTokenizer tokenizer = new StringTokenizer(s);
+
+ Boolean release = null;
+ int modifiers = 0;
+ int keyCode = KeyEvent.VK_UNDEFINED;
+ char keyChar = KeyEvent.CHAR_UNDEFINED;
+ boolean typed = false;
+ long modifier = 0;
+ String token = null;
+ do {
+ token = getNextToken(tokenizer);
+ modifier = parseModifier(token);
+ modifiers |= modifier;
+ } while (modifier > 0);
+
+ typed = parseTypedID(token);
+
+ if (typed) {
+ token = getNextToken(tokenizer);
+ keyChar = parseTypedKey(token);
+
+ }
+ if (keyChar == KeyEvent.CHAR_UNDEFINED) {
+ release = parsePressedReleasedID(token);
+ if (release != null) {
+ token = getNextToken(tokenizer);
+ }
+ keyCode = parseKey(token);
+ }
+ if (tokenizer.hasMoreTokens()) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+
+ return getAWTKeyStroke(keyChar, keyCode, modifiers,
+ release == Boolean.TRUE);
+ }
+
+ /**
+ * Gets the next token.
+ *
+ * @param tokenizer the tokenizer
+ *
+ * @return the next token
+ */
+ private static String getNextToken(StringTokenizer tokenizer) {
+ try {
+ return tokenizer.nextToken();
+ } catch (NoSuchElementException exception) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Gets the key code.
+ *
+ * @param s the s
+ *
+ * @return the key code
+ */
+ static int getKeyCode(String s) {
+ try {
+ Field vk = KeyEvent.class.getField("VK_" + s); //$NON-NLS-1$
+ return vk.getInt(null);
+ } catch (Exception e) {
+ if (s.length() != 1) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ return KeyEvent.VK_UNDEFINED;
+ }
+ }
+
+ /**
+ * Gets an instance of the AWTKeyStroke for specified character.
+ *
+ * @param keyChar the keyboard character value.
+ *
+ * @return a AWTKeyStroke for specified character.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
+ return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
+ }
+
+ /**
+ * Returns an instance of AWTKeyStroke for a given key code, set
+ * of modifiers, and specified key released flag value.
+ * The key codes are defined in java.awt.event.KeyEvent class.
+ * The set of modifiers is given as a bitwise combination
+ * of masks taken from the following list:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ * <br>
+ *
+ * @param keyCode the specified key code of keyboard.
+ * @param modifiers the bit set of modifiers.
+ *
+ * @return the AWTKeyStroke.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,
+ boolean onKeyRelease) {
+ return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
+ onKeyRelease);
+ }
+
+ /**
+ * Returns AWTKeyStroke for a specified character and set of modifiers.
+ * The set of modifiers is given as a bitwise combination
+ * of masks taken from the following list:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ *
+ * @param keyChar the Character object which represents keyboard character value.
+ * @param modifiers the bit set of modifiers.
+ *
+ * @return the AWTKeyStroke object.
+ *
+ * @throws IllegalArgumentException if keyChar value is null.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) {
+ if (keyChar == null) {
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,
+ modifiers, false);
+ }
+
+ /**
+ * Returns an instance of AWTKeyStroke for a specified key code and
+ * set of modifiers.
+ * The key codes are defined in java.awt.event.KeyEvent class.
+ * The set of modifiers is given as a bitwise combination
+ * of masks taken from the following list:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ *
+ * @param keyCode the specified key code of keyboard.
+ * @param modifiers the bit set of modifiers.
+ *
+ * @return the AWTKeyStroke
+ */
+ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {
+ return getAWTKeyStroke(keyCode, modifiers, false);
+ }
+
+ /**
+ * Gets the AWTKeyStroke for a key event. This method obtains the key char
+ * and key code from the specified key event.
+ *
+ * @param anEvent the key event which identifies the desired AWTKeyStroke.
+ *
+ * @return the AWTKeyStroke for the key event.
+ */
+ public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
+ int id = anEvent.getID();
+ char undef = KeyEvent.CHAR_UNDEFINED;
+ char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() :
+ undef);
+ int keyCode = (keyChar == undef ? anEvent.getKeyCode() :
+ KeyEvent.VK_UNDEFINED);
+ return getAWTKeyStroke(keyChar, keyCode, anEvent.getModifiersEx(),
+ id == KeyEvent.KEY_RELEASED);
+ }
+
+ /**
+ * Gets the key event type for the AWTKeyStroke object.
+ *
+ * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or KeyEvent.KEY_RELEASED
+ */
+ public final int getKeyEventType() {
+ if (keyCode == KeyEvent.VK_UNDEFINED) {
+ return KeyEvent.KEY_TYPED;
+ }
+ return (onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED);
+ }
+
+ /**
+ * Retuns true if the key event is associated with the AWTKeyStroke is
+ * KEY_RELEASED, overwise false.
+ *
+ * @return true, if if the key event associated with the AWTKeyStroke is
+ * KEY_RELEASED, overwise false.
+ */
+ public final boolean isOnKeyRelease() {
+ return onKeyRelease;
+ }
+
+ /**
+ * Read resolve.
+ *
+ * @return the object
+ *
+ * @throws ObjectStreamException the object stream exception
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ return getAWTKeyStroke(this.keyChar, this.keyCode,
+ this.modifiers, this.onKeyRelease);
+ }
+
+ /**
+ * Register subclass.
+ *
+ * @param subclass the subclass
+ */
+ protected static void registerSubclass(Class<?> subclass) {
+ //???AWT
+ /*
+ if (subclass == null) {
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "subclass")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (! AWTKeyStroke.class.isAssignableFrom(subclass)) {
+ // awt.67=subclass is not derived from AWTKeyStroke
+ throw new ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$
+ }
+ try {
+ subConstructor = subclass.getDeclaredConstructor();
+ subConstructor.setAccessible(true);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ // awt.68=subclass could not be instantiated
+ throw new IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$
+ }
+ cache.clear(); //flush the cache
+ */
+ }
+
+ /**
+ * Parses the modifier.
+ *
+ * @param strMod the str mod
+ *
+ * @return the long
+ */
+ private static long parseModifier(String strMod) {
+ long modifiers = 0l;
+ if (strMod.equals("shift")) { //$NON-NLS-1$
+ modifiers |= InputEvent.SHIFT_DOWN_MASK;
+ } else if (strMod.equals("control") || strMod.equals("ctrl")) { //$NON-NLS-1$ //$NON-NLS-2$
+ modifiers |= InputEvent.CTRL_DOWN_MASK;
+ } else if (strMod.equals("meta")) { //$NON-NLS-1$
+ modifiers |= InputEvent.META_DOWN_MASK;
+ } else if (strMod.equals("alt")) { //$NON-NLS-1$
+ modifiers |= InputEvent.ALT_DOWN_MASK;
+ } else if (strMod.equals("altGraph")) { //$NON-NLS-1$
+ modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
+ } else if (strMod.equals("button1")) { //$NON-NLS-1$
+ modifiers |= InputEvent.BUTTON1_DOWN_MASK;
+ } else if (strMod.equals("button2")) { //$NON-NLS-1$
+ modifiers |= InputEvent.BUTTON2_DOWN_MASK;
+ } else if (strMod.equals("button3")) { //$NON-NLS-1$
+ modifiers |= InputEvent.BUTTON3_DOWN_MASK;
+ }
+ return modifiers;
+ }
+
+ /**
+ * Parses the typed id.
+ *
+ * @param strTyped the str typed
+ *
+ * @return true, if successful
+ */
+ private static boolean parseTypedID(String strTyped) {
+ if (strTyped.equals("typed")) { //$NON-NLS-1$
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Parses the typed key.
+ *
+ * @param strChar the str char
+ *
+ * @return the char
+ */
+ private static char parseTypedKey(String strChar) {
+ char keyChar = KeyEvent.CHAR_UNDEFINED;
+
+ if (strChar.length() != 1) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ keyChar = strChar.charAt(0);
+ return keyChar;
+ }
+
+ /**
+ * Parses the pressed released id.
+ *
+ * @param str the str
+ *
+ * @return the boolean
+ */
+ private static Boolean parsePressedReleasedID(String str) {
+
+ if (str.equals("pressed")) { //$NON-NLS-1$
+ return Boolean.FALSE;
+ } else if (str.equals("released")) { //$NON-NLS-1$
+ return Boolean.TRUE;
+ }
+ return null;
+ }
+
+ /**
+ * Parses the key.
+ *
+ * @param strCode the str code
+ *
+ * @return the int
+ */
+ private static int parseKey(String strCode) {
+ int keyCode = KeyEvent.VK_UNDEFINED;
+
+ keyCode = getKeyCode(strCode);
+
+ if (keyCode == KeyEvent.VK_UNDEFINED) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ return keyCode;
+ }
+}
+
diff --git a/awt/java/awt/AWTListenerList.java b/awt/java/awt/AWTListenerList.java
new file mode 100644
index 0000000..3327d63
--- /dev/null
+++ b/awt/java/awt/AWTListenerList.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.util.EventListener;
+
+import org.apache.harmony.awt.ListenerList;
+
+final class AWTListenerList<T extends EventListener> extends ListenerList<T> {
+ private static final long serialVersionUID = -2622077171532840953L;
+
+ private final Component owner;
+
+ AWTListenerList() {
+ super();
+ this.owner = null;
+ }
+
+ AWTListenerList(Component owner) {
+ super();
+ this.owner = owner;
+ }
+
+ @Override
+ public void addUserListener(T listener) {
+ super.addUserListener(listener);
+
+ if (owner != null) {
+ owner.deprecatedEventHandler = false;
+ }
+ }
+}
diff --git a/awt/java/awt/AWTPermission.java b/awt/java/awt/AWTPermission.java
new file mode 100644
index 0000000..25326ab
--- /dev/null
+++ b/awt/java/awt/AWTPermission.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.security.BasicPermission;
+
+/**
+ * The AWTPermission specifies the name of the permission and the
+ * corresponding action list.
+ */
+public final class AWTPermission extends BasicPermission {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8890392402588814465L;
+
+ /**
+ * Instantiates a new AWTPermission with defined name and actions.
+ *
+ * @param name the name of a new AWTPermission.
+ * @param actions the actions of a new AWTPermission.
+ */
+ public AWTPermission(String name, String actions) {
+ super(name, actions);
+ }
+
+ /**
+ * Instantiates a new AWT permission with the defined name.
+ *
+ * @param name the name of a new AWTPermission.
+ */
+ public AWTPermission(String name) {
+ super(name);
+ }
+
+}
+
diff --git a/awt/java/awt/ActiveEvent.java b/awt/java/awt/ActiveEvent.java
new file mode 100644
index 0000000..4133752
--- /dev/null
+++ b/awt/java/awt/ActiveEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * This interface defines events that know how to dispatch themselves.
+ * Such event can be placed upon the event queue and its dispatch method
+ * will be called when the event is dispatched.
+ */
+public interface ActiveEvent {
+
+ /**
+ * Dispatches the event to the listeners of the event's source,
+ * or does whatever it is this event is supposed to do.
+ */
+ public void dispatch();
+
+}
diff --git a/awt/java/awt/Adjustable.java b/awt/java/awt/Adjustable.java
new file mode 100644
index 0000000..3241cad
--- /dev/null
+++ b/awt/java/awt/Adjustable.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.AdjustmentListener;
+
+/**
+ * The Adjustable interface represents an adjustable numeric value
+ * contained within a bounded range of values, such as the current
+ * location in scrollable region or the value of a gauge.
+ */
+public interface Adjustable {
+
+ /**
+ * The Constant HORIZONTAL indicates that the Adjustable's orientation
+ * is horizontal.
+ */
+ public static final int HORIZONTAL = 0;
+
+ /**
+ * The Constant VERTICAL indicates that the Adjustable's orientation
+ * is vertical.
+ */
+ public static final int VERTICAL = 1;
+
+ /**
+ * The Constant NO_ORIENTATION indicates that the Adjustable
+ * has no orientation.
+ */
+ public static final int NO_ORIENTATION = 2;
+
+ /**
+ * Gets the value of the Adjustable.
+ *
+ * @return the current value of the Adjustable.
+ */
+ public int getValue();
+
+ /**
+ * Sets the value to the Adjustable object.
+ *
+ * @param a0 the new value of the Adjustable object.
+ */
+ public void setValue(int a0);
+
+ /**
+ * Adds the AdjustmentListener to current Adjustment.
+ *
+ * @param a0 the AdjustmentListener object.
+ */
+ public void addAdjustmentListener(AdjustmentListener a0);
+
+ /**
+ * Gets the block increment of the Adjustable.
+ *
+ * @return the block increment of the Adjustable.
+ */
+ public int getBlockIncrement();
+
+ /**
+ * Gets the maximum value of the Adjustable.
+ *
+ * @return the maximum value of the Adjustable.
+ */
+ public int getMaximum();
+
+ /**
+ * Gets the minimum value of the Adjustable.
+ *
+ * @return the minimum value of the Adjustable.
+ */
+ public int getMinimum();
+
+ /**
+ * Gets the orientation of the Adjustable.
+ *
+ * @return the orientation of the Adjustable.
+ */
+ public int getOrientation();
+
+ /**
+ * Gets the unit increment of the Adjustable.
+ *
+ * @return the unit increment of the Adjustable.
+ */
+ public int getUnitIncrement();
+
+ /**
+ * Gets the visible amount of the Adjustable.
+ *
+ * @return the visible amount of the Adjustable.
+ */
+ public int getVisibleAmount();
+
+ /**
+ * Removes the adjustment listener of the Adjustable.
+ *
+ * @param a0 the specified AdjustmentListener to be removed.
+ */
+ public void removeAdjustmentListener(AdjustmentListener a0);
+
+ /**
+ * Sets the block increment for the Adjustable.
+ *
+ * @param a0 the new block increment.
+ */
+ public void setBlockIncrement(int a0);
+
+ /**
+ * Sets the maximum value of the Adjustable.
+ *
+ * @param a0 the new maximum of the Adjustable.
+ */
+ public void setMaximum(int a0);
+
+ /**
+ * Sets the minimum value of the Adjustable.
+ *
+ * @param a0 the new minimum of the Adjustable.
+ */
+ public void setMinimum(int a0);
+
+ /**
+ * Sets the unit increment of the Adjustable.
+ *
+ * @param a0 the new unit increment of the Adjustable.
+ */
+ public void setUnitIncrement(int a0);
+
+ /**
+ * Sets the visible amount of the Adjustable.
+ *
+ * @param a0 the new visible amount of the Adjustable.
+ */
+ public void setVisibleAmount(int a0);
+
+}
+
diff --git a/awt/java/awt/AlphaComposite.java b/awt/java/awt/AlphaComposite.java
new file mode 100644
index 0000000..d26753c
--- /dev/null
+++ b/awt/java/awt/AlphaComposite.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+
+import org.apache.harmony.awt.gl.ICompositeContext;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * The AlphaComposite class defines a basic alpha compositing rules for
+ * combining source and destination colors to achieve blending and
+ * transparency effects with graphics and images.
+ */
+public final class AlphaComposite implements Composite {
+
+ /**
+ * The Constant CLEAR indicates that both the color and the alpha of
+ * the destination are cleared (Porter-Duff Clear rule).
+ */
+ public static final int CLEAR = 1;
+
+ /**
+ * The Constant SRC indicates that the source is copied to the destination
+ * (Porter-Duff Source rule).
+ */
+ public static final int SRC = 2;
+
+ /** The Constant DST indicates that the destination is left untouched
+ * (Porter-Duff Destination rule).
+ */
+ public static final int DST = 9;
+
+ /**
+ * The Constant SRC_OVER indicates that the source is composited over
+ * the destination (Porter-Duff Source Over Destination rule).
+ */
+ public static final int SRC_OVER = 3;
+
+ /**
+ * The Constant DST_OVER indicates that The destination is composited over
+ * the source and the result replaces the destination
+ * (Porter-Duff Destination Over Source rule).
+ */
+ public static final int DST_OVER = 4;
+
+ /**
+ * The Constant SRC_IN indicates that the part of the source lying
+ * inside of the destination replaces the destination (Porter-Duff
+ * Source In Destination rule).
+ */
+ public static final int SRC_IN = 5;
+
+ /**
+ * The Constant DST_IN indicates that the part of the destination
+ * lying inside of the source replaces the destination
+ * (Porter-Duff Destination In Source rule).
+ */
+ public static final int DST_IN = 6;
+
+ /**
+ * The Constant SRC_OUT indicates that the part of the source lying
+ * outside of the destination replaces the destination (Porter-Duff
+ * Source Held Out By Destination rule).
+ */
+ public static final int SRC_OUT = 7;
+
+ /**
+ * The Constant DST_OUT indicates that the part of the destination
+ * lying outside of the source replaces the destination (Porter-Duff
+ * Destination Held Out By Source rule).
+ */
+ public static final int DST_OUT = 8;
+
+ /**
+ * The Constant SRC_ATOP indicates that the part of the source lying
+ * inside of the destination is composited onto the destination
+ * (Porter-Duff Source Atop Destination rule).
+ */
+ public static final int SRC_ATOP = 10;
+
+ /**
+ * The Constant DST_ATOP indicates that the part of the destination
+ * lying inside of the source is composited over the source and replaces
+ * the destination (Porter-Duff Destination Atop Source rule).
+ */
+ public static final int DST_ATOP = 11;
+
+ /**
+ * The Constant XOR indicates that the part of the source that lies
+ * outside of the destination is combined with the part of the destination
+ * that lies outside of the source (Porter-Duff Source Xor Destination rule).
+ */
+ public static final int XOR = 12;
+
+ /** AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f. */
+ public static final AlphaComposite Clear = new AlphaComposite(CLEAR);
+
+ /** AlphaComposite object with the opaque SRC rule and an alpha of 1.0f. */
+ public static final AlphaComposite Src = new AlphaComposite(SRC);
+
+ /** AlphaComposite object with the opaque DST rule and an alpha of 1.0f. */
+ public static final AlphaComposite Dst = new AlphaComposite(DST);
+
+ /** AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcOver = new AlphaComposite(SRC_OVER);
+
+ /** AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstOver = new AlphaComposite(DST_OVER);
+
+ /** AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcIn = new AlphaComposite(SRC_IN);
+
+ /** AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstIn = new AlphaComposite(DST_IN);
+
+ /** AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcOut = new AlphaComposite(SRC_OUT);
+
+ /** AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstOut = new AlphaComposite(DST_OUT);
+
+ /** AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcAtop = new AlphaComposite(SRC_ATOP);
+
+ /** AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstAtop = new AlphaComposite(DST_ATOP);
+
+ /** AlphaComposite object with the opaque XOR rule and an alpha of 1.0f. */
+ public static final AlphaComposite Xor = new AlphaComposite(XOR);
+
+ /** The rule. */
+ private int rule;
+
+ /** The alpha. */
+ private float alpha;
+
+ /**
+ * Instantiates a new alpha composite.
+ * Creates a context for the compositing operation. The context contains state that is used in performing the compositing operation.
+ *
+ * @param rule the rule
+ * @param alpha the alpha
+ */
+ private AlphaComposite(int rule, float alpha){
+ if(rule < CLEAR || rule > XOR) {
+ // awt.11D=Unknown rule
+ throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$
+ }
+ if(alpha < 0.0f || alpha > 1.0f) {
+ // awt.11E=Wrong alpha value
+ throw new IllegalArgumentException(Messages.getString("awt.11E")); //$NON-NLS-1$
+ }
+
+ this.rule = rule;
+ this.alpha = alpha;
+ }
+
+ /**
+ * Instantiates a new alpha composite.
+ *
+ * @param rule the rule
+ */
+ private AlphaComposite(int rule){
+ this(rule, 1.0f);
+ }
+
+ /**
+ * Creates a CompositeContext object with the specified source ColorModel,
+ * destination ColorModel and RenderingHints parameters for a composing
+ * operation.
+ *
+ * @param srcColorModel the source's ColorModel.
+ * @param dstColorModel the destination's ColorModel.
+ * @param hints the RenderingHints object.
+ *
+ * @return the CompositeContext object.
+ *
+ * @see java.awt.Composite#createContext(java.awt.image.ColorModel, java.awt.image.ColorModel, java.awt.RenderingHints)
+ */
+ public CompositeContext createContext(ColorModel srcColorModel,
+ ColorModel dstColorModel, RenderingHints hints) {
+ return new ICompositeContext(this, srcColorModel, dstColorModel);
+ }
+
+ /**
+ * Compares the AlphaComposite object with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the AlphaComposite object is equal to the specified
+ * object.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if(!(obj instanceof AlphaComposite)) {
+ return false;
+ }
+ AlphaComposite other = (AlphaComposite)obj;
+ return (this.rule == other.getRule() && this.alpha == other.getAlpha());
+ }
+
+ /**
+ * Returns the hash code of the AlphaComposite object.
+ *
+ * @return the hash code of the AlphaComposite object.
+ */
+ @Override
+ public int hashCode() {
+ int hash = Float.floatToIntBits(alpha);
+ int tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= rule;
+ return hash;
+ }
+
+ /**
+ * Gets the compositing rule of this AlphaComposite object.
+ *
+ * @return the compositing rule of this AlphaComposite object.
+ */
+ public int getRule() {
+ return rule;
+ }
+
+ /**
+ * Gets the alpha value of this AlphaComposite object; returns 1.0 if
+ * this AlphaComposite object doesn't have alpha value.
+ *
+ * @return the alpha value of this AlphaComposite object or 1.0 if
+ * this AlphaComposite object doesn't have alpha value.
+ */
+ public float getAlpha() {
+ return alpha;
+ }
+
+ /**
+ * Gets the AlphaComposite instance with the specified rule and alpha value.
+ *
+ * @param rule the compositing rule.
+ * @param alpha the alpha value.
+ *
+ * @return AlphaComposite instance.
+ */
+ public static AlphaComposite getInstance(int rule, float alpha) {
+ if(alpha == 1.0f) {
+ return getInstance(rule);
+ }
+ return new AlphaComposite(rule, alpha);
+ }
+
+ /**
+ * Gets the AlphaComposite instance with the specified rule.
+ *
+ * @param rule the compositing rule.
+ *
+ * @return AlphaComposite instance.
+ */
+ public static AlphaComposite getInstance(int rule) {
+ switch(rule){
+ case CLEAR:
+ return Clear;
+ case SRC:
+ return Src;
+ case DST:
+ return Dst;
+ case SRC_OVER:
+ return SrcOver;
+ case DST_OVER:
+ return DstOver;
+ case SRC_IN:
+ return SrcIn;
+ case DST_IN:
+ return DstIn;
+ case SRC_OUT:
+ return SrcOut;
+ case DST_OUT:
+ return DstOut;
+ case SRC_ATOP:
+ return SrcAtop;
+ case DST_ATOP:
+ return DstAtop;
+ case XOR:
+ return Xor;
+ default:
+ // awt.11D=Unknown rule
+ throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/BasicStroke.java b/awt/java/awt/BasicStroke.java
new file mode 100644
index 0000000..955dc6b
--- /dev/null
+++ b/awt/java/awt/BasicStroke.java
@@ -0,0 +1,2204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The BasicStroke class specifies a set of rendering attributes for the outlines
+ * of graphics primitives. The BasicStroke attributes describe the shape of the
+ * pen which draws the outline of a Shape and the decorations applied at the ends
+ * and joins of path segments of the Shape. The BasicStroke has the following
+ * rendering attributes:
+ * <p>
+ * <ul>
+ * <li> line width -the pen width which draws the outlines.</li>
+ * <li> end caps - indicates the decoration applied to the ends of unclosed
+ * subpaths and dash segments. The BasicStroke defines three different decorations:
+ * CAP_BUTT, CAP_ROUND, and CAP_SQUARE.</li>
+ * <li>line joins - indicates the decoration applied at the intersection of
+ * two path segments and at the intersection of the endpoints of a subpath.
+ * The BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER,
+ * and JOIN_ROUND.</li>
+ * <li>miter limit - the limit to trim a line join that has a JOIN_MITER
+ * decoration.</li>
+ * <li>dash attributes - the definition of how to make a dash pattern by
+ * alternating between opaque and transparent sections </li>
+ * </ul>
+ */
+public class BasicStroke implements Stroke {
+
+ /**
+ * The Constant CAP_BUTT indicates the ends of unclosed subpaths
+ * and dash segments have no added decoration.
+ */
+ public static final int CAP_BUTT = 0;
+
+ /**
+ * The Constant CAP_ROUND indicates the ends of unclosed subpaths
+ * and dash segments have a round decoration.
+ */
+ public static final int CAP_ROUND = 1;
+
+ /**
+ * The Constant CAP_SQUARE indicates the ends of unclosed subpaths
+ * and dash segments have a square projection.
+ */
+ public static final int CAP_SQUARE = 2;
+
+ /**
+ * The Constant JOIN_MITER indicates that path segments are joined by
+ * extending their outside edges until they meet.
+ */
+ public static final int JOIN_MITER = 0;
+
+ /**
+ * The Constant JOIN_ROUND indicates that path segments are joined by
+ * rounding off the corner at a radius of half the line width.
+ */
+ public static final int JOIN_ROUND = 1;
+
+ /**
+ * The Constant JOIN_BEVEL indicates that path segments are joined by
+ * connecting the outer corners of their wide outlines with
+ * a straight segment.
+ */
+ public static final int JOIN_BEVEL = 2;
+
+ /** Constants for calculating. */
+ static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision
+
+ /** The Constant CURVE_DELTA. */
+ static final double CURVE_DELTA = 2.0; // Width tolerance
+
+ /** The Constant CORNER_ANGLE. */
+ static final double CORNER_ANGLE = 4.0; // Minimum corner angle
+
+ /** The Constant CORNER_ZERO. */
+ static final double CORNER_ZERO = 0.01; // Zero angle
+
+ /** The Constant CUBIC_ARC. */
+ static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1);
+
+ /** Stroke width. */
+ float width;
+
+ /** Stroke cap type. */
+ int cap;
+
+ /** Stroke join type. */
+ int join;
+
+ /** Stroke miter limit. */
+ float miterLimit;
+
+ /** Stroke dashes array. */
+ float dash[];
+
+ /** Stroke dash phase. */
+ float dashPhase;
+
+ /** The temporary pre-calculated values. */
+ double curveDelta;
+
+ /** The corner delta. */
+ double cornerDelta;
+
+ /** The zero delta. */
+ double zeroDelta;
+
+ /** The w2. */
+ double w2;
+
+ /** The fmy. */
+ double fmx, fmy;
+
+ /** The smy. */
+ double scx, scy, smx, smy;
+
+ /** The cy. */
+ double mx, my, cx, cy;
+
+ /** The temporary indicators. */
+ boolean isMove;
+
+ /** The is first. */
+ boolean isFirst;
+
+ /** The check move. */
+ boolean checkMove;
+
+ /** The temporary and destination work paths. */
+ BufferedPath dst, lp, rp, sp;
+
+ /** Stroke dasher class. */
+ Dasher dasher;
+
+ /**
+ * Instantiates a new BasicStroke with default width, cap, join, limit,
+ * dash attributes parameters. The default parameters are a solid line of
+ * width 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes,
+ * and a dash phase of 0.0f.
+ */
+ public BasicStroke() {
+ this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
+ }
+
+ /**
+ * Instantiates a new BasicStroke with the specified width,
+ * caps, joins, limit, dash attributes, dash phase parameters.
+ *
+ * @param width the width of BasikStroke.
+ * @param cap the end decoration of BasikStroke.
+ * @param join the join segments decoration.
+ * @param miterLimit the limit to trim the miter join.
+ * @param dash the array with the dashing pattern.
+ * @param dashPhase the offset to start the dashing pattern.
+ */
+ public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, float dashPhase) {
+ if (width < 0.0f) {
+ // awt.133=Negative width
+ throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$
+ }
+ if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
+ // awt.134=Illegal cap
+ throw new IllegalArgumentException(Messages.getString("awt.134")); //$NON-NLS-1$
+ }
+ if (join != JOIN_MITER && join != JOIN_ROUND && join != JOIN_BEVEL) {
+ // awt.135=Illegal join
+ throw new IllegalArgumentException(Messages.getString("awt.135")); //$NON-NLS-1$
+ }
+ if (join == JOIN_MITER && miterLimit < 1.0f) {
+ // awt.136=miterLimit less than 1.0f
+ throw new IllegalArgumentException(Messages.getString("awt.136")); //$NON-NLS-1$
+ }
+ if (dash != null) {
+ if (dashPhase < 0.0f) {
+ // awt.137=Negative dashPhase
+ throw new IllegalArgumentException(Messages.getString("awt.137")); //$NON-NLS-1$
+ }
+ if (dash.length == 0) {
+ // awt.138=Zero dash length
+ throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$
+ }
+ ZERO: {
+ for(int i = 0; i < dash.length; i++) {
+ if (dash[i] < 0.0) {
+ // awt.139=Negative dash[{0}]
+ throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$
+ }
+ if (dash[i] > 0.0) {
+ break ZERO;
+ }
+ }
+ // awt.13A=All dash lengths zero
+ throw new IllegalArgumentException(Messages.getString("awt.13A")); //$NON-NLS-1$
+ }
+ }
+ this.width = width;
+ this.cap = cap;
+ this.join = join;
+ this.miterLimit = miterLimit;
+ this.dash = dash;
+ this.dashPhase = dashPhase;
+ }
+
+ /**
+ * Instantiates a new BasicStroke with specified width, cap, join, limit
+ * and default dash attributes parameters.
+ *
+ * @param width the width of BasikStroke.
+ * @param cap the end decoration of BasikStroke.
+ * @param join the join segments decoration.
+ * @param miterLimit the limit to trim the miter join.
+ */
+ public BasicStroke(float width, int cap, int join, float miterLimit) {
+ this(width, cap, join, miterLimit, null, 0.0f);
+ }
+
+ /**
+ * Instantiates a new BasicStroke with specified width, cap, join
+ * and default limit and dash attributes parameters.
+ *
+ * @param width the width of BasikStroke.
+ * @param cap the end decoration of BasikStroke.
+ * @param join the join segments decoration.
+ */
+ public BasicStroke(float width, int cap, int join) {
+ this(width, cap, join, 10.0f, null, 0.0f);
+ }
+
+ /**
+ * Instantiates a new BasicStroke with specified width and default cap, join,
+ * limit, dash attributes parameters.
+ *
+ * @param width the width of BasicStroke.
+ */
+ public BasicStroke(float width) {
+ this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
+ }
+
+ /**
+ * Gets the line width of the BasicStroke.
+ *
+ * @return the line width of the BasicStroke.
+ */
+ public float getLineWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the end cap style of the BasicStroke.
+ *
+ * @return the end cap style of the BasicStroke.
+ */
+ public int getEndCap() {
+ return cap;
+ }
+
+ /**
+ * Gets the line join style of the BasicStroke.
+ *
+ * @return the line join style of the BasicStroke.
+ */
+ public int getLineJoin() {
+ return join;
+ }
+
+ /**
+ * Gets the miter limit of the BasicStroke (the limit to trim the miter join).
+ *
+ * @return the miter limit of the BasicStroke.
+ */
+ public float getMiterLimit() {
+ return miterLimit;
+ }
+
+ /**
+ * Gets the dash attributes array of the BasicStroke.
+ *
+ * @return the dash attributes array of the BasicStroke.
+ */
+ public float[] getDashArray() {
+ return dash;
+ }
+
+ /**
+ * Gets the dash phase of the BasicStroke.
+ *
+ * @return the dash phase of the BasicStroke.
+ */
+ public float getDashPhase() {
+ return dashPhase;
+ }
+
+ /**
+ * Returns hash code of this BasicStroke.
+ *
+ * @return the hash code of this BasicStroke.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(width);
+ hash.append(cap);
+ hash.append(join);
+ hash.append(miterLimit);
+ if (dash != null) {
+ hash.append(dashPhase);
+ for (float element : dash) {
+ hash.append(element);
+ }
+ }
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares this BasicStroke object with the specified Object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the Object is a BasicStroke with the same data
+ * values as this BasicStroke; false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof BasicStroke) {
+ BasicStroke bs = (BasicStroke)obj;
+ return
+ bs.width == width &&
+ bs.cap == cap &&
+ bs.join == join &&
+ bs.miterLimit == miterLimit &&
+ bs.dashPhase == dashPhase &&
+ java.util.Arrays.equals(bs.dash, dash);
+ }
+ return false;
+ }
+
+ /**
+ * Calculates allowable curve derivation.
+ *
+ * @param width the width
+ *
+ * @return the curve delta
+ */
+ double getCurveDelta(double width) {
+ double a = width + CURVE_DELTA;
+ double cos = 1.0 - 2.0 * width * width / (a * a);
+ double sin = Math.sqrt(1.0 - cos * cos);
+ return Math.abs(sin / cos);
+ }
+
+ /**
+ * Calculates the value to detect a small angle.
+ *
+ * @param width the width
+ *
+ * @return the corner delta
+ */
+ double getCornerDelta(double width) {
+ return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0);
+ }
+
+ /**
+ * Calculates value to detect a zero angle.
+ *
+ * @param width the width
+ *
+ * @return the zero delta
+ */
+ double getZeroDelta(double width) {
+ return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0);
+ }
+
+ /**
+ * Creates a Shape from the outline of the specified shape
+ * drawn with this BasicStroke.
+ *
+ * @param s the specified Shape to be stroked.
+ *
+ * @return the Shape of the stroked outline.
+ *
+ * @see java.awt.Stroke#createStrokedShape(java.awt.Shape)
+ */
+ public Shape createStrokedShape(Shape s) {
+ w2 = width / 2.0;
+ curveDelta = getCurveDelta(w2);
+ cornerDelta = getCornerDelta(w2);
+ zeroDelta = getZeroDelta(w2);
+
+ dst = new BufferedPath();
+ lp = new BufferedPath();
+ rp = new BufferedPath();
+
+ if (dash == null) {
+ createSolidShape(s.getPathIterator(null));
+ } else {
+ createDashedShape(s.getPathIterator(null));
+ }
+
+ return dst.createGeneralPath();
+ }
+
+ /**
+ * Generates a shape with a solid (not dashed) outline.
+ *
+ * @param p - the PathIterator of source shape
+ */
+ void createSolidShape(PathIterator p) {
+ double coords[] = new double[6];
+ mx = my = cx = cy = 0.0;
+ isMove = false;
+ isFirst = false;
+ checkMove = true;
+ boolean isClosed = true;
+
+ while(!p.isDone()) {
+ switch(p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!isClosed) {
+ closeSolidShape();
+ }
+ rp.clean();
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ isMove = true;
+ isClosed = false;
+ break;
+ case PathIterator.SEG_LINETO:
+ addLine(cx, cy, cx = coords[0], cy = coords[1], true);
+ break;
+ case PathIterator.SEG_QUADTO:
+ addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ addLine(cx, cy, mx, my, false);
+ addJoin(lp, mx, my, lp.xMove, lp.yMove, true);
+ addJoin(rp, mx, my, rp.xMove, rp.yMove, false);
+ lp.closePath();
+ rp.closePath();
+ lp.appendReverse(rp);
+ isClosed = true;
+ break;
+ }
+ p.next();
+ }
+ if (!isClosed) {
+ closeSolidShape();
+ }
+
+ dst = lp;
+ }
+
+ /**
+ * Closes solid shape path.
+ */
+ void closeSolidShape() {
+ addCap(lp, cx, cy, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ addCap(lp, mx, my, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+
+ /**
+ * Generates dashed stroked shape.
+ *
+ * @param p - the PathIterator of source shape
+ */
+ void createDashedShape(PathIterator p) {
+ double coords[] = new double[6];
+ mx = my = cx = cy = 0.0;
+ smx = smy = scx = scy = 0.0;
+ isMove = false;
+ checkMove = false;
+ boolean isClosed = true;
+
+ while(!p.isDone()) {
+ switch(p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+
+ if (!isClosed) {
+ closeDashedShape();
+ }
+
+ dasher = new Dasher(dash, dashPhase);
+ lp.clean();
+ rp.clean();
+ sp = null;
+ isFirst = true;
+ isMove = true;
+ isClosed = false;
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ addDashLine(cx, cy, cx = coords[0], cy = coords[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ addDashLine(cx, cy, cx = mx, cy = my);
+
+ if (dasher.isConnected()) {
+ // Connect current and head segments
+ addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true);
+ lp.join(sp);
+ addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true);
+ lp.combine(rp);
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ dst.append(lp);
+ sp = null;
+ } else {
+ closeDashedShape();
+ }
+
+ isClosed = true;
+ break;
+ }
+ p.next();
+ }
+
+ if (!isClosed) {
+ closeDashedShape();
+ }
+
+ }
+
+ /**
+ * Closes dashed shape path.
+ */
+ void closeDashedShape() {
+ // Add head segment
+ if (sp != null) {
+ addCap(sp, fmx, fmy, sp.xMove, sp.yMove);
+ sp.closePath();
+ dst.append(sp);
+ }
+ if (lp.typeSize > 0) {
+ // Close current segment
+ if (!dasher.isClosed()) {
+ addCap(lp, scx, scy, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ dst.append(lp);
+ }
+ }
+
+ /**
+ * Adds cap to the work path.
+ *
+ * @param p - the BufferedPath object of work path
+ * @param x0 - the x coordinate of the source path
+ * @param y0 - the y coordinate on the source path
+ * @param x2 - the x coordinate of the next point on the work path
+ * @param y2 - the y coordinate of the next point on the work path
+ */
+ void addCap(BufferedPath p, double x0, double y0, double x2, double y2) {
+ double x1 = p.xLast;
+ double y1 = p.yLast;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x20 = x2 - x0;
+ double y20 = y2 - y0;
+
+ switch(cap) {
+ case CAP_BUTT:
+ p.lineTo(x2, y2);
+ break;
+ case CAP_ROUND:
+ double mx = x10 * CUBIC_ARC;
+ double my = y10 * CUBIC_ARC;
+
+ double x3 = x0 + y10;
+ double y3 = y0 - x10;
+
+ x10 *= CUBIC_ARC;
+ y10 *= CUBIC_ARC;
+ x20 *= CUBIC_ARC;
+ y20 *= CUBIC_ARC;
+
+ p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3);
+ p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2);
+ break;
+ case CAP_SQUARE:
+ p.lineTo(x1 + y10, y1 - x10);
+ p.lineTo(x2 - y20, y2 + x20);
+ p.lineTo(x2, y2);
+ break;
+ }
+ }
+
+ /**
+ * Adds bevel and miter join to the work path.
+ *
+ * @param p - the BufferedPath object of work path
+ * @param x0 - the x coordinate of the source path
+ * @param y0 - the y coordinate on the source path
+ * @param x2 - the x coordinate of the next point on the work path
+ * @param y2 - the y coordinate of the next point on the work path
+ * @param isLeft - the orientation of work path, true if work path lies to the left from source path, false otherwise
+ */
+ void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) {
+ double x1 = p.xLast;
+ double y1 = p.yLast;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x20 = x2 - x0;
+ double y20 = y2 - y0;
+ double sin0 = x10 * y20 - y10 * x20;
+
+ // Small corner
+ if (-cornerDelta < sin0 && sin0 < cornerDelta) {
+ double cos0 = x10 * x20 + y10 * y20;
+ if (cos0 > 0.0) {
+ // if zero corner do nothing
+ if (-zeroDelta > sin0 || sin0 > zeroDelta) {
+ double x3 = x0 + w2 * w2 * (y20 - y10) / sin0;
+ double y3 = y0 + w2 * w2 * (x10 - x20) / sin0;
+ p.setLast(x3, y3);
+ }
+ return;
+ }
+ // Zero corner
+ if (-zeroDelta < sin0 && sin0 < zeroDelta) {
+ p.lineTo(x2, y2);
+ }
+ return;
+ }
+
+ if (isLeft ^ (sin0 < 0.0)) {
+ // Twisted corner
+ p.lineTo(x0, y0);
+ p.lineTo(x2, y2);
+ } else {
+ switch(join) {
+ case JOIN_BEVEL:
+ p.lineTo(x2, y2);
+ break;
+ case JOIN_MITER:
+ double s1 = x1 * x10 + y1 * y10;
+ double s2 = x2 * x20 + y2 * y20;
+ double x3 = (s1 * y20 - s2 * y10) / sin0;
+ double y3 = (s2 * x10 - s1 * x20) / sin0;
+ double x30 = x3 - x0;
+ double y30 = y3 - y0;
+ double miterLength = Math.sqrt(x30 * x30 + y30 * y30);
+ if (miterLength < miterLimit * w2) {
+ p.lineTo(x3, y3);
+ }
+ p.lineTo(x2, y2);
+ break;
+ case JOIN_ROUND:
+ addRoundJoin(p, x0, y0, x2, y2, isLeft);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adds round join to the work path.
+ *
+ * @param p - the BufferedPath object of work path
+ * @param x0 - the x coordinate of the source path
+ * @param y0 - the y coordinate on the source path
+ * @param x2 - the x coordinate of the next point on the work path
+ * @param y2 - the y coordinate of the next point on the work path
+ * @param isLeft - the orientation of work path, true if work path lies to the left from source path, false otherwise
+ */
+ void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) {
+ double x1 = p.xLast;
+ double y1 = p.yLast;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x20 = x2 - x0;
+ double y20 = y2 - y0;
+
+ double x30 = x10 + x20;
+ double y30 = y10 + y20;
+
+ double l30 = Math.sqrt(x30 * x30 + y30 * y30);
+
+ if (l30 < 1E-5) {
+ p.lineTo(x2, y2);
+ return;
+ }
+
+ double w = w2 / l30;
+
+ x30 *= w;
+ y30 *= w;
+
+ double x3 = x0 + x30;
+ double y3 = y0 + y30;
+
+ double cos = x10 * x20 + y10 * y20;
+ double a = Math.acos(cos / (w2 * w2));
+ if (cos >= 0.0) {
+ double k = 4.0 / 3.0 * Math.tan(a / 4.0);
+ if (isLeft) {
+ k = -k;
+ }
+
+ x10 *= k;
+ y10 *= k;
+ x20 *= k;
+ y20 *= k;
+
+ p.cubicTo(x1 - y10, y1 + x10, x2 + y20, y2 - x20, x2, y2);
+ } else {
+ double k = 4.0 / 3.0 * Math.tan(a / 8.0);
+ if (isLeft) {
+ k = -k;
+ }
+
+ x10 *= k;
+ y10 *= k;
+ x20 *= k;
+ y20 *= k;
+ x30 *= k;
+ y30 *= k;
+
+ p.cubicTo(x1 - y10, y1 + x10, x3 + y30, y3 - x30, x3, y3);
+ p.cubicTo(x3 - y30, y3 + x30, x2 + y20, y2 - x20, x2, y2);
+ }
+
+ }
+
+ /**
+ * Adds solid line segment to the work path.
+ *
+ * @param x1 - the x coordinate of the start line point
+ * @param y1 - the y coordinate of the start line point
+ * @param x2 - the x coordinate of the end line point
+ * @param y2 - the y coordinate of the end line point
+ * @param zero - if true it's allowable to add zero length line segment
+ */
+ void addLine(double x1, double y1, double x2, double y2, boolean zero) {
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+
+ if (dx == 0.0 && dy == 0.0) {
+ if (!zero) {
+ return;
+ }
+ dx = w2;
+ dy = 0;
+ } else {
+ double w = w2 / Math.sqrt(dx * dx + dy * dy);
+ dx *= w;
+ dy *= w;
+ }
+
+ double lx1 = x1 - dy;
+ double ly1 = y1 + dx;
+ double rx1 = x1 + dy;
+ double ry1 = y1 - dx;
+
+ if (checkMove) {
+ if (isMove) {
+ isMove = false;
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ }
+
+ lp.lineTo(x2 - dy, y2 + dx);
+ rp.lineTo(x2 + dy, y2 - dx);
+ }
+
+ /**
+ * Adds solid quad segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ */
+ void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) {
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+
+ if (l21 == 0.0 && l23 == 0.0) {
+ addLine(x1, y1, x3, y3, false);
+ return;
+ }
+
+ if (l21 == 0.0) {
+ addLine(x2, y2, x3, y3, false);
+ return;
+ }
+
+ if (l23 == 0.0) {
+ addLine(x1, y1, x2, y2, false);
+ return;
+ }
+
+ double w;
+ w = w2 / l21;
+ double mx1 = - y21 * w;
+ double my1 = x21 * w;
+ w = w2 / l23;
+ double mx3 = y23 * w;
+ double my3 = - x23 * w;
+
+ double lx1 = x1 + mx1;
+ double ly1 = y1 + my1;
+ double rx1 = x1 - mx1;
+ double ry1 = y1 - my1;
+
+ if (checkMove) {
+ if (isMove) {
+ isMove = false;
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ }
+
+ if (x21 * y23 - y21 * x23 == 0.0) {
+ // On line curve
+ if (x21 * x23 + y21 * y23 > 0.0) {
+ // Twisted curve
+ if (l21 == l23) {
+ double px = x1 + (x21 + x23) / 4.0;
+ double py = y1 + (y21 + y23) / 4.0;
+ lp.lineTo(px + mx1, py + my1);
+ rp.lineTo(px - mx1, py - my1);
+ lp.lineTo(px - mx1, py - my1);
+ rp.lineTo(px + mx1, py + my1);
+ lp.lineTo(x3 - mx1, y3 - my1);
+ rp.lineTo(x3 + mx1, y3 + my1);
+ } else {
+ double px1, py1;
+ double k = l21 / (l21 + l23);
+ double px = x1 + (x21 + x23) * k * k;
+ double py = y1 + (y21 + y23) * k * k;
+ px1 = (x1 + px) / 2.0;
+ py1 = (y1 + py) / 2.0;
+ lp.quadTo(px1 + mx1, py1 + my1, px + mx1, py + my1);
+ rp.quadTo(px1 - mx1, py1 - my1, px - mx1, py - my1);
+ lp.lineTo(px - mx1, py - my1);
+ rp.lineTo(px + mx1, py + my1);
+ px1 = (x3 + px) / 2.0;
+ py1 = (y3 + py) / 2.0;
+ lp.quadTo(px1 - mx1, py1 - my1, x3 - mx1, y3 - my1);
+ rp.quadTo(px1 + mx1, py1 + my1, x3 + mx1, y3 + my1);
+ }
+ } else {
+ // Simple curve
+ lp.quadTo(x2 + mx1, y2 + my1, x3 + mx3, y3 + my3);
+ rp.quadTo(x2 - mx1, y2 - my1, x3 - mx3, y3 - my3);
+ }
+ } else {
+ addSubQuad(x1, y1, x2, y2, x3, y3, 0);
+ }
+ }
+
+ /**
+ * Subdivides solid quad curve to make outline for source quad segment and adds it to work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param level - the maximum level of subdivision deepness
+ */
+ void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) {
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+
+ double cos = x21 * x23 + y21 * y23;
+ double sin = x21 * y23 - y21 * x23;
+
+ if (level < MAX_LEVEL && (cos >= 0.0 || (Math.abs(sin / cos) > curveDelta))) {
+ double c1x = (x2 + x1) / 2.0;
+ double c1y = (y2 + y1) / 2.0;
+ double c2x = (x2 + x3) / 2.0;
+ double c2y = (y2 + y3) / 2.0;
+ double c3x = (c1x + c2x) / 2.0;
+ double c3y = (c1y + c2y) / 2.0;
+ addSubQuad(x1, y1, c1x, c1y, c3x, c3y, level + 1);
+ addSubQuad(c3x, c3y, c2x, c2y, x3, y3, level + 1);
+ } else {
+ double w;
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ w = w2 / sin;
+ double mx2 = (x21 * l23 + x23 * l21) * w;
+ double my2 = (y21 * l23 + y23 * l21) * w;
+ w = w2 / l23;
+ double mx3 = y23 * w;
+ double my3 = - x23 * w;
+ lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3);
+ rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3);
+ }
+ }
+
+ /**
+ * Adds solid cubic segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param x4 - the x coordinate of the fours control point
+ * @param y4 - the y coordinate of the fours control point
+ */
+ void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+ double x12 = x1 - x2;
+ double y12 = y1 - y2;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+ double x34 = x3 - x4;
+ double y34 = y3 - y4;
+
+ double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+ // All edges are zero
+ if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) {
+ addLine(x1, y1, x4, y4, false);
+ return;
+ }
+
+ // One zero edge
+ if (l12 == 0.0 && l23 == 0.0) {
+ addLine(x3, y3, x4, y4, false);
+ return;
+ }
+
+ if (l23 == 0.0 && l34 == 0.0) {
+ addLine(x1, y1, x2, y2, false);
+ return;
+ }
+
+ if (l12 == 0.0 && l34 == 0.0) {
+ addLine(x2, y2, x3, y3, false);
+ return;
+ }
+
+ double w, mx1, my1, mx4, my4;
+ boolean onLine;
+
+ if (l12 == 0.0) {
+ w = w2 / l23;
+ mx1 = y23 * w;
+ my1 = - x23 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ onLine = - x23 * y34 + y23 * x34 == 0.0; // sin3
+ } else
+ if (l34 == 0.0) {
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l23;
+ mx4 = y23 * w;
+ my4 = - x23 * w;
+ onLine = - x12 * y23 + y12 * x23 == 0.0; // sin2
+ } else {
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ if (l23 == 0.0) {
+ onLine = - x12 * y34 + y12 * x34 == 0.0;
+ } else {
+ onLine =
+ - x12 * y34 + y12 * x34 == 0.0 &&
+ - x12 * y23 + y12 * x23 == 0.0 && // sin2
+ - x23 * y34 + y23 * x34 == 0.0; // sin3
+ }
+ }
+
+ double lx1 = x1 + mx1;
+ double ly1 = y1 + my1;
+ double rx1 = x1 - mx1;
+ double ry1 = y1 - my1;
+
+ if (checkMove) {
+ if (isMove) {
+ isMove = false;
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ }
+
+ if (onLine) {
+ if ((x1 == x2 && y1 < y2) || x1 < x2) {
+ l12 = -l12;
+ }
+ if ((x2 == x3 && y2 < y3) || x2 < x3) {
+ l23 = -l23;
+ }
+ if ((x3 == x4 && y3 < y4) || x3 < x4) {
+ l34 = -l34;
+ }
+ double d = l23 * l23 - l12 * l34;
+ double roots[] = new double[3];
+ int rc = 0;
+ if (d == 0.0) {
+ double t = (l12 - l23) / (l12 + l34 - l23 - l23);
+ if (0.0 < t && t < 1.0) {
+ roots[rc++] = t;
+ }
+ } else
+ if (d > 0.0) {
+ d = Math.sqrt(d);
+ double z = l12 + l34 - l23 - l23;
+ double t;
+ t = (l12 - l23 + d) / z;
+ if (0.0 < t && t < 1.0) {
+ roots[rc++] = t;
+ }
+ t = (l12 - l23 - d) / z;
+ if (0.0 < t && t < 1.0) {
+ roots[rc++] = t;
+ }
+ }
+
+ if (rc > 0) {
+ // Sort roots
+ if (rc == 2 && roots[0] > roots[1]) {
+ double tmp = roots[0];
+ roots[0] = roots[1];
+ roots[1] = tmp;
+ }
+ roots[rc++] = 1.0;
+
+ double ax = - x34 - x12 + x23 + x23;
+ double ay = - y34 - y12 + y23 + y23;
+ double bx = 3.0 * (- x23 + x12);
+ double by = 3.0 * (- y23 + y12);
+ double cx = 3.0 * (- x12);
+ double cy = 3.0 * (- y12);
+ double xPrev = x1;
+ double yPrev = y1;
+ for(int i = 0; i < rc; i++) {
+ double t = roots[i];
+ double px = t * (t * (t * ax + bx) + cx) + x1;
+ double py = t * (t * (t * ay + by) + cy) + y1;
+ double px1 = (xPrev + px) / 2.0;
+ double py1 = (yPrev + py) / 2.0;
+ lp.cubicTo(px1 + mx1, py1 + my1, px1 + mx1, py1 + my1, px + mx1, py + my1);
+ rp.cubicTo(px1 - mx1, py1 - my1, px1 - mx1, py1 - my1, px - mx1, py - my1);
+ if (i < rc - 1) {
+ lp.lineTo(px - mx1, py - my1);
+ rp.lineTo(px + mx1, py + my1);
+ }
+ xPrev = px;
+ yPrev = py;
+ mx1 = - mx1;
+ my1 = - my1;
+ }
+ } else {
+ lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4);
+ rp.cubicTo(x2 - mx1, y2 - my1, x3 - mx4, y3 - my4, x4 - mx4, y4 - my4);
+ }
+ } else {
+ addSubCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0);
+ }
+ }
+
+ /**
+ * Subdivides solid cubic curve to make outline for source quad segment and adds it to work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param x4 - the x coordinate of the fours control point
+ * @param y4 - the y coordinate of the fours control point
+ * @param level - the maximum level of subdivision deepness
+ */
+ void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, int level) {
+ double x12 = x1 - x2;
+ double y12 = y1 - y2;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+ double x34 = x3 - x4;
+ double y34 = y3 - y4;
+
+ double cos2 = - x12 * x23 - y12 * y23;
+ double cos3 = - x23 * x34 - y23 * y34;
+ double sin2 = - x12 * y23 + y12 * x23;
+ double sin3 = - x23 * y34 + y23 * x34;
+ double sin0 = - x12 * y34 + y12 * x34;
+ double cos0 = - x12 * x34 - y12 * y34;
+
+ if (level < MAX_LEVEL && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) &&
+ (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 ||
+ (Math.abs(sin2 / cos2) > curveDelta) ||
+ (Math.abs(sin3 / cos3) > curveDelta) ||
+ (Math.abs(sin0 / cos0) > curveDelta)))
+ {
+ double cx = (x2 + x3) / 2.0;
+ double cy = (y2 + y3) / 2.0;
+ double lx2 = (x2 + x1) / 2.0;
+ double ly2 = (y2 + y1) / 2.0;
+ double rx3 = (x3 + x4) / 2.0;
+ double ry3 = (y3 + y4) / 2.0;
+ double lx3 = (cx + lx2) / 2.0;
+ double ly3 = (cy + ly2) / 2.0;
+ double rx2 = (cx + rx3) / 2.0;
+ double ry2 = (cy + ry3) / 2.0;
+ cx = (lx3 + rx2) / 2.0;
+ cy = (ly3 + ry2) / 2.0;
+ addSubCubic(x1, y1, lx2, ly2, lx3, ly3, cx, cy, level + 1);
+ addSubCubic(cx, cy, rx2, ry2, rx3, ry3, x4, y4, level + 1);
+ } else {
+ double w, mx1, my1, mx2, my2, mx3, my3, mx4, my4;
+ double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+ if (l12 == 0.0) {
+ w = w2 / l23;
+ mx1 = y23 * w;
+ my1 = - x23 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ } else
+ if (l34 == 0.0) {
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l23;
+ mx4 = y23 * w;
+ my4 = - x23 * w;
+ } else {
+ // Common case
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ }
+
+ if (sin2 == 0.0) {
+ mx2 = mx1;
+ my2 = my1;
+ } else {
+ w = w2 / sin2;
+ mx2 = -(x12 * l23 - x23 * l12) * w;
+ my2 = -(y12 * l23 - y23 * l12) * w;
+ }
+ if (sin3 == 0.0) {
+ mx3 = mx4;
+ my3 = my4;
+ } else {
+ w = w2 / sin3;
+ mx3 = -(x23 * l34 - x34 * l23) * w;
+ my3 = -(y23 * l34 - y34 * l23) * w;
+ }
+
+ lp.cubicTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3, x4 + mx4, y4 + my4);
+ rp.cubicTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3, x4 - mx4, y4 - my4);
+ }
+ }
+
+ /**
+ * Adds dashed line segment to the work path.
+ *
+ * @param x1 - the x coordinate of the start line point
+ * @param y1 - the y coordinate of the start line point
+ * @param x2 - the x coordinate of the end line point
+ * @param y2 - the y coordinate of the end line point
+ */
+ void addDashLine(double x1, double y1, double x2, double y2) {
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+
+ if (l21 == 0.0) {
+ return;
+ }
+
+ double px1, py1;
+ px1 = py1 = 0.0;
+ double w = w2 / l21;
+ double mx = - y21 * w;
+ double my = x21 * w;
+
+ dasher.init(new DashIterator.Line(l21));
+
+ while(!dasher.eof()) {
+ double t = dasher.getValue();
+ scx = x1 + t * x21;
+ scy = y1 + t * y21;
+
+ if (dasher.isOpen()) {
+ px1 = scx;
+ py1 = scy;
+ double lx1 = px1 + mx;
+ double ly1 = py1 + my;
+ double rx1 = px1 - mx;
+ double ry1 = py1 - my;
+ if (isMove) {
+ isMove = false;
+ smx = px1;
+ smy = py1;
+ rp.clean();
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ } else
+ if (dasher.isContinue()) {
+ double px2 = scx;
+ double py2 = scy;
+ lp.lineTo(px2 + mx, py2 + my);
+ rp.lineTo(px2 - mx, py2 - my);
+ if (dasher.close) {
+ addCap(lp, px2, py2, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ if (isFirst) {
+ isFirst = false;
+ fmx = smx;
+ fmy = smy;
+ sp = lp;
+ lp = new BufferedPath();
+ } else {
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ isMove = true;
+ }
+ }
+
+ dasher.next();
+ }
+ }
+
+ /**
+ * Adds dashed quad segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ */
+ void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) {
+
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+
+ if (l21 == 0.0 && l23 == 0.0) {
+ return;
+ }
+
+ if (l21 == 0.0) {
+ addDashLine(x2, y2, x3, y3);
+ return;
+ }
+
+ if (l23 == 0.0) {
+ addDashLine(x1, y1, x2, y2);
+ return;
+ }
+
+ double ax = x1 + x3 - x2 - x2;
+ double ay = y1 + y3 - y2 - y2;
+ double bx = x2 - x1;
+ double by = y2 - y1;
+ double cx = x1;
+ double cy = y1;
+
+ double px1, py1, dx1, dy1;
+ px1 = py1 = dx1 = dy1 = 0.0;
+ double prev = 0.0;
+
+ dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3));
+
+ while(!dasher.eof()) {
+ double t = dasher.getValue();
+ double dx = t * ax + bx;
+ double dy = t * ay + by;
+ scx = t * (dx + bx) + cx; // t^2 * ax + 2.0 * t * bx + cx
+ scy = t * (dy + by) + cy; // t^2 * ay + 2.0 * t * by + cy
+ if (dasher.isOpen()) {
+ px1 = scx;
+ py1 = scy;
+ dx1 = dx;
+ dy1 = dy;
+ double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1);
+ double mx1 = - dy1 * w;
+ double my1 = dx1 * w;
+ double lx1 = px1 + mx1;
+ double ly1 = py1 + my1;
+ double rx1 = px1 - mx1;
+ double ry1 = py1 - my1;
+ if (isMove) {
+ isMove = false;
+ smx = px1;
+ smy = py1;
+ rp.clean();
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ } else
+ if (dasher.isContinue()) {
+ double px3 = scx;
+ double py3 = scy;
+ double sx = x2 - x23 * prev;
+ double sy = y2 - y23 * prev;
+ double t2 = (t - prev) / (1 - prev);
+ double px2 = px1 + (sx - px1) * t2;
+ double py2 = py1 + (sy - py1) * t2;
+
+ addQuad(px1, py1, px2, py2, px3, py3);
+ if (dasher.isClosed()) {
+ addCap(lp, px3, py3, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ if (isFirst) {
+ isFirst = false;
+ fmx = smx;
+ fmy = smy;
+ sp = lp;
+ lp = new BufferedPath();
+ } else {
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ isMove = true;
+ }
+ }
+
+ prev = t;
+ dasher.next();
+ }
+ }
+
+ /**
+ * Adds dashed cubic segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param x4 - the x coordinate of the fours control point
+ * @param y4 - the y coordinate of the fours control point
+ */
+ void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+
+ double x12 = x1 - x2;
+ double y12 = y1 - y2;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+ double x34 = x3 - x4;
+ double y34 = y3 - y4;
+
+ double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+ // All edges are zero
+ if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) {
+ // NOTHING
+ return;
+ }
+
+ // One zero edge
+ if (l12 == 0.0 && l23 == 0.0) {
+ addDashLine(x3, y3, x4, y4);
+ return;
+ }
+
+ if (l23 == 0.0 && l34 == 0.0) {
+ addDashLine(x1, y1, x2, y2);
+ return;
+ }
+
+ if (l12 == 0.0 && l34 == 0.0) {
+ addDashLine(x2, y2, x3, y3);
+ return;
+ }
+
+ double ax = x4 - x1 + 3.0 * (x2 - x3);
+ double ay = y4 - y1 + 3.0 * (y2 - y3);
+ double bx = 3.0 * (x1 + x3 - x2 - x2);
+ double by = 3.0 * (y1 + y3 - y2 - y2);
+ double cx = 3.0 * (x2 - x1);
+ double cy = 3.0 * (y2 - y1);
+ double dx = x1;
+ double dy = y1;
+
+ double px1 = 0.0;
+ double py1 = 0.0;
+ double prev = 0.0;
+
+ dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4));
+
+ while(!dasher.eof()) {
+
+ double t = dasher.getValue();
+ scx = t * (t * (t * ax + bx) + cx) + dx;
+ scy = t * (t * (t * ay + by) + cy) + dy;
+ if (dasher.isOpen()) {
+ px1 = scx;
+ py1 = scy;
+ double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx;
+ double dy1 = t * (t * (ay + ay + ay) + by + by) + cy;
+ double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1);
+ double mx1 = - dy1 * w;
+ double my1 = dx1 * w;
+ double lx1 = px1 + mx1;
+ double ly1 = py1 + my1;
+ double rx1 = px1 - mx1;
+ double ry1 = py1 - my1;
+ if (isMove) {
+ isMove = false;
+ smx = px1;
+ smy = py1;
+ rp.clean();
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ } else
+ if (dasher.isContinue()) {
+ double sx1 = x2 - x23 * prev;
+ double sy1 = y2 - y23 * prev;
+ double sx2 = x3 - x34 * prev;
+ double sy2 = y3 - y34 * prev;
+ double sx3 = sx1 + (sx2 - sx1) * prev;
+ double sy3 = sy1 + (sy2 - sy1) * prev;
+ double t2 = (t - prev) / (1 - prev);
+ double sx4 = sx3 + (sx2 - sx3) * t2;
+ double sy4 = sy3 + (sy2 - sy3) * t2;
+
+ double px4 = scx;
+ double py4 = scy;
+ double px2 = px1 + (sx3 - px1) * t2;
+ double py2 = py1 + (sy3 - py1) * t2;
+ double px3 = px2 + (sx4 - px2) * t2;
+ double py3 = py2 + (sy4 - py2) * t2;
+
+ addCubic(px1, py1, px2, py2, px3, py3, px4, py4);
+ if (dasher.isClosed()) {
+ addCap(lp, px4, py4, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ if (isFirst) {
+ isFirst = false;
+ fmx = smx;
+ fmy = smy;
+ sp = lp;
+ lp = new BufferedPath();
+ } else {
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ isMove = true;
+ }
+ }
+
+ prev = t;
+ dasher.next();
+ }
+ }
+
+ /**
+ * Dasher class provides dashing for particular dash style.
+ */
+ class Dasher {
+
+ /** The pos. */
+ double pos;
+
+ /** The first. */
+ boolean close, visible, first;
+
+ /** The dash. */
+ float dash[];
+
+ /** The phase. */
+ float phase;
+
+ /** The index. */
+ int index;
+
+ /** The iter. */
+ DashIterator iter;
+
+ /**
+ * Instantiates a new dasher.
+ *
+ * @param dash the dash
+ * @param phase the phase
+ */
+ Dasher(float dash[], float phase) {
+ this.dash = dash;
+ this.phase = phase;
+ index = 0;
+ pos = phase;
+ visible = true;
+ while (pos >= dash[index]) {
+ visible = !visible;
+ pos -= dash[index];
+ index = (index + 1) % dash.length;
+ }
+ pos = -pos;
+ first = visible;
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param iter the iter
+ */
+ void init(DashIterator iter) {
+ this.iter = iter;
+ close = true;
+ }
+
+ /**
+ * Checks if is open.
+ *
+ * @return true, if is open
+ */
+ boolean isOpen() {
+ return visible && pos < iter.length;
+ }
+
+ /**
+ * Checks if is continue.
+ *
+ * @return true, if is continue
+ */
+ boolean isContinue() {
+ return !visible && pos > 0;
+ }
+
+ /**
+ * Checks if is closed.
+ *
+ * @return true, if is closed
+ */
+ boolean isClosed() {
+ return close;
+ }
+
+ /**
+ * Checks if is connected.
+ *
+ * @return true, if is connected
+ */
+ boolean isConnected() {
+ return first && !close;
+ }
+
+ /**
+ * Eof.
+ *
+ * @return true, if successful
+ */
+ boolean eof() {
+ if (!close) {
+ pos -= iter.length;
+ return true;
+ }
+ if (pos >= iter.length) {
+ if (visible) {
+ pos -= iter.length;
+ return true;
+ }
+ close = pos == iter.length;
+ }
+ return false;
+ }
+
+ /**
+ * Next.
+ */
+ void next() {
+ if (close) {
+ pos += dash[index];
+ index = (index + 1) % dash.length;
+ } else {
+ // Go back
+ index = (index + dash.length - 1) % dash.length;
+ pos -= dash[index];
+ }
+ visible = !visible;
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ */
+ double getValue() {
+ double t = iter.getNext(pos);
+ return t < 0 ? 0 : (t > 1 ? 1 : t);
+ }
+
+ }
+
+ /**
+ * DashIterator class provides dashing for particular segment type.
+ */
+ static abstract class DashIterator {
+
+ /** The Constant FLATNESS. */
+ static final double FLATNESS = 1.0;
+
+ /**
+ * The Class Line.
+ */
+ static class Line extends DashIterator {
+
+ /**
+ * Instantiates a new line.
+ *
+ * @param len the len
+ */
+ Line(double len) {
+ length = len;
+ }
+
+ @Override
+ double getNext(double dashPos) {
+ return dashPos / length;
+ }
+
+ }
+
+ /**
+ * The Class Quad.
+ */
+ static class Quad extends DashIterator {
+
+ /** The val size. */
+ int valSize;
+
+ /** The val pos. */
+ int valPos;
+
+ /** The cur len. */
+ double curLen;
+
+ /** The prev len. */
+ double prevLen;
+
+ /** The last len. */
+ double lastLen;
+
+ /** The values. */
+ double[] values;
+
+ /** The step. */
+ double step;
+
+ /**
+ * Instantiates a new quad.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ * @param x3 the x3
+ * @param y3 the y3
+ */
+ Quad(double x1, double y1, double x2, double y2, double x3, double y3) {
+
+ double nx = x1 + x3 - x2 - x2;
+ double ny = y1 + y3 - y2 - y2;
+
+ int n = (int)(1 + Math.sqrt(0.75 * (Math.abs(nx) + Math.abs(ny)) * FLATNESS));
+ step = 1.0 / n;
+
+ double ax = x1 + x3 - x2 - x2;
+ double ay = y1 + y3 - y2 - y2;
+ double bx = 2.0 * (x2 - x1);
+ double by = 2.0 * (y2 - y1);
+
+ double dx1 = step * (step * ax + bx);
+ double dy1 = step * (step * ay + by);
+ double dx2 = step * (step * ax * 2.0);
+ double dy2 = step * (step * ay * 2.0);
+ double vx = x1;
+ double vy = y1;
+
+ valSize = n;
+ values = new double[valSize];
+ double pvx = vx;
+ double pvy = vy;
+ length = 0.0;
+ for(int i = 0; i < n; i++) {
+ vx += dx1;
+ vy += dy1;
+ dx1 += dx2;
+ dy1 += dy2;
+ double lx = vx - pvx;
+ double ly = vy - pvy;
+ values[i] = Math.sqrt(lx * lx + ly * ly);
+ length += values[i];
+ pvx = vx;
+ pvy = vy;
+ }
+
+ valPos = 0;
+ curLen = 0.0;
+ prevLen = 0.0;
+ }
+
+ @Override
+ double getNext(double dashPos) {
+ double t = 2.0;
+ while (curLen <= dashPos && valPos < valSize) {
+ prevLen = curLen;
+ curLen += lastLen = values[valPos++];
+ }
+ if (curLen > dashPos) {
+ t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step;
+ }
+ return t;
+ }
+
+ }
+
+ /**
+ * The Class Cubic.
+ */
+ static class Cubic extends DashIterator {
+
+ /** The val size. */
+ int valSize;
+
+ /** The val pos. */
+ int valPos;
+
+ /** The cur len. */
+ double curLen;
+
+ /** The prev len. */
+ double prevLen;
+
+ /** The last len. */
+ double lastLen;
+
+ /** The values. */
+ double[] values;
+
+ /** The step. */
+ double step;
+
+ /**
+ * Instantiates a new cubic.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ * @param x3 the x3
+ * @param y3 the y3
+ * @param x4 the x4
+ * @param y4 the y4
+ */
+ Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+
+ double nx1 = x1 + x3 - x2 - x2;
+ double ny1 = y1 + y3 - y2 - y2;
+ double nx2 = x2 + x4 - x3 - x3;
+ double ny2 = y2 + y4 - y3 - y3;
+
+ double max = Math.max(Math.abs(nx1) + Math.abs(ny1), Math.abs(nx2) + Math.abs(ny2));
+ int n = (int)(1 + Math.sqrt(0.75 * max) * FLATNESS);
+ step = 1.0 / n;
+
+ double ax = x4 - x1 + 3.0 * (x2 - x3);
+ double ay = y4 - y1 + 3.0 * (y2 - y3);
+ double bx = 3.0 * (x1 + x3 - x2 - x2);
+ double by = 3.0 * (y1 + y3 - y2 - y2);
+ double cx = 3.0 * (x2 - x1);
+ double cy = 3.0 * (y2 - y1);
+
+ double dx1 = step * (step * (step * ax + bx) + cx);
+ double dy1 = step * (step * (step * ay + by) + cy);
+ double dx2 = step * (step * (step * ax * 6.0 + bx * 2.0));
+ double dy2 = step * (step * (step * ay * 6.0 + by * 2.0));
+ double dx3 = step * (step * (step * ax * 6.0));
+ double dy3 = step * (step * (step * ay * 6.0));
+ double vx = x1;
+ double vy = y1;
+
+ valSize = n;
+ values = new double[valSize];
+ double pvx = vx;
+ double pvy = vy;
+ length = 0.0;
+ for(int i = 0; i < n; i++) {
+ vx += dx1;
+ vy += dy1;
+ dx1 += dx2;
+ dy1 += dy2;
+ dx2 += dx3;
+ dy2 += dy3;
+ double lx = vx - pvx;
+ double ly = vy - pvy;
+ values[i] = Math.sqrt(lx * lx + ly * ly);
+ length += values[i];
+ pvx = vx;
+ pvy = vy;
+ }
+
+ valPos = 0;
+ curLen = 0.0;
+ prevLen = 0.0;
+ }
+
+ @Override
+ double getNext(double dashPos) {
+ double t = 2.0;
+ while (curLen <= dashPos && valPos < valSize) {
+ prevLen = curLen;
+ curLen += lastLen = values[valPos++];
+ }
+ if (curLen > dashPos) {
+ t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step;
+ }
+ return t;
+ }
+
+ }
+
+ /** The length. */
+ double length;
+
+ /**
+ * Gets the next.
+ *
+ * @param dashPos the dash pos
+ *
+ * @return the next
+ */
+ abstract double getNext(double dashPos);
+
+ }
+
+ /**
+ * BufferedPath class provides work path storing and processing.
+ */
+ static class BufferedPath {
+
+ /** The Constant bufCapacity. */
+ private static final int bufCapacity = 10;
+
+ /** The point shift. */
+ static int pointShift[] = {
+ 2, // MOVETO
+ 2, // LINETO
+ 4, // QUADTO
+ 6, // CUBICTO
+ 0}; // CLOSE
+
+ /** The types. */
+ byte[] types;
+
+ /** The points. */
+ float[] points;
+
+ /** The type size. */
+ int typeSize;
+
+ /** The point size. */
+ int pointSize;
+
+ /** The x last. */
+ float xLast;
+
+ /** The y last. */
+ float yLast;
+
+ /** The x move. */
+ float xMove;
+
+ /** The y move. */
+ float yMove;
+
+ /**
+ * Instantiates a new buffered path.
+ */
+ public BufferedPath() {
+ types = new byte[bufCapacity];
+ points = new float[bufCapacity * 2];
+ }
+
+ /**
+ * Check buf.
+ *
+ * @param typeCount the type count
+ * @param pointCount the point count
+ */
+ void checkBuf(int typeCount, int pointCount) {
+ if (typeSize + typeCount > types.length) {
+ byte tmp[] = new byte[typeSize + Math.max(bufCapacity, typeCount)];
+ System.arraycopy(types, 0, tmp, 0, typeSize);
+ types = tmp;
+ }
+ if (pointSize + pointCount > points.length) {
+ float tmp[] = new float[pointSize + Math.max(bufCapacity * 2, pointCount)];
+ System.arraycopy(points, 0, tmp, 0, pointSize);
+ points = tmp;
+ }
+ }
+
+ /**
+ * Checks if is empty.
+ *
+ * @return true, if is empty
+ */
+ boolean isEmpty() {
+ return typeSize == 0;
+ }
+
+ /**
+ * Clean.
+ */
+ void clean() {
+ typeSize = 0;
+ pointSize = 0;
+ }
+
+ /**
+ * Move to.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void moveTo(double x, double y) {
+ checkBuf(1, 2);
+ types[typeSize++] = PathIterator.SEG_MOVETO;
+ points[pointSize++] = xMove = (float)x;
+ points[pointSize++] = yMove = (float)y;
+ }
+
+ /**
+ * Line to.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void lineTo(double x, double y) {
+ checkBuf(1, 2);
+ types[typeSize++] = PathIterator.SEG_LINETO;
+ points[pointSize++] = xLast = (float)x;
+ points[pointSize++] = yLast = (float)y;
+ }
+
+ /**
+ * Quad to.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ */
+ void quadTo(double x1, double y1, double x2, double y2) {
+ checkBuf(1, 4);
+ types[typeSize++] = PathIterator.SEG_QUADTO;
+ points[pointSize++] = (float)x1;
+ points[pointSize++] = (float)y1;
+ points[pointSize++] = xLast = (float)x2;
+ points[pointSize++] = yLast = (float)y2;
+ }
+
+ /**
+ * Cubic to.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ * @param x3 the x3
+ * @param y3 the y3
+ */
+ void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) {
+ checkBuf(1, 6);
+ types[typeSize++] = PathIterator.SEG_CUBICTO;
+ points[pointSize++] = (float)x1;
+ points[pointSize++] = (float)y1;
+ points[pointSize++] = (float)x2;
+ points[pointSize++] = (float)y2;
+ points[pointSize++] = xLast = (float)x3;
+ points[pointSize++] = yLast = (float)y3;
+ }
+
+ /**
+ * Close path.
+ */
+ void closePath() {
+ checkBuf(1, 0);
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ }
+
+ /**
+ * Sets the last.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void setLast(double x, double y) {
+ points[pointSize - 2] = xLast = (float)x;
+ points[pointSize - 1] = yLast = (float)y;
+ }
+
+ /**
+ * Append.
+ *
+ * @param p the p
+ */
+ void append(BufferedPath p) {
+ checkBuf(p.typeSize, p.pointSize);
+ System.arraycopy(p.points, 0, points, pointSize, p.pointSize);
+ System.arraycopy(p.types, 0, types, typeSize, p.typeSize);
+ pointSize += p.pointSize;
+ typeSize += p.typeSize;
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Append reverse.
+ *
+ * @param p the p
+ */
+ void appendReverse(BufferedPath p) {
+ checkBuf(p.typeSize, p.pointSize);
+ // Skip last point, beacause it's the first point of the second path
+ for(int i = p.pointSize - 2; i >= 0; i -= 2) {
+ points[pointSize++] = p.points[i + 0];
+ points[pointSize++] = p.points[i + 1];
+ }
+ // Skip first type, beacuse it's always MOVETO
+ int closeIndex = 0;
+ for(int i = p.typeSize - 1; i >= 0; i--) {
+ byte type = p.types[i];
+ if (type == PathIterator.SEG_MOVETO) {
+ types[closeIndex] = PathIterator.SEG_MOVETO;
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ } else {
+ if (type == PathIterator.SEG_CLOSE) {
+ closeIndex = typeSize;
+ }
+ types[typeSize++] = type;
+ }
+ }
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Join.
+ *
+ * @param p the p
+ */
+ void join(BufferedPath p) {
+ // Skip MOVETO
+ checkBuf(p.typeSize - 1, p.pointSize - 2);
+ System.arraycopy(p.points, 2, points, pointSize, p.pointSize - 2);
+ System.arraycopy(p.types, 1, types, typeSize, p.typeSize - 1);
+ pointSize += p.pointSize - 2;
+ typeSize += p.typeSize - 1;
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Combine.
+ *
+ * @param p the p
+ */
+ void combine(BufferedPath p) {
+ checkBuf(p.typeSize - 1, p.pointSize - 2);
+ // Skip last point, beacause it's the first point of the second path
+ for(int i = p.pointSize - 4; i >= 0; i -= 2) {
+ points[pointSize++] = p.points[i + 0];
+ points[pointSize++] = p.points[i + 1];
+ }
+ // Skip first type, beacuse it's always MOVETO
+ for(int i = p.typeSize - 1; i >= 1; i--) {
+ types[typeSize++] = p.types[i];
+ }
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Creates the general path.
+ *
+ * @return the general path
+ */
+ GeneralPath createGeneralPath() {
+ GeneralPath p = new GeneralPath();
+ int j = 0;
+ for(int i = 0; i < typeSize; i++) {
+ int type = types[i];
+ switch(type){
+ case PathIterator.SEG_MOVETO:
+ p.moveTo(points[j], points[j + 1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ p.lineTo(points[j], points[j + 1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], points[j + 4], points[j + 5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ p.closePath();
+ break;
+ }
+ j += pointShift[type];
+ }
+ return p;
+ }
+
+ }
+
+}
+
diff --git a/awt/java/awt/BufferCapabilities.java b/awt/java/awt/BufferCapabilities.java
new file mode 100644
index 0000000..80e8add
--- /dev/null
+++ b/awt/java/awt/BufferCapabilities.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+
+/**
+ * The BufferCapabilities class represents the capabilities
+ * and other properties of the image buffers.
+ */
+public class BufferCapabilities implements Cloneable {
+
+ /** The front buffer capabilities. */
+ private final ImageCapabilities frontBufferCapabilities;
+
+ /** The back buffer capabilities. */
+ private final ImageCapabilities backBufferCapabilities;
+
+ /** The flip contents. */
+ private final FlipContents flipContents;
+
+ /**
+ * Instantiates a new BufferCapabilities object.
+ *
+ * @param frontBufferCapabilities the front buffer capabilities,
+ * can not be null.
+ * @param backBufferCapabilities the the back and intermediate
+ * buffers capabilities, can not be null.
+ * @param flipContents the back buffer contents after page flipping,
+ * null if page flipping is not used.
+ */
+ public BufferCapabilities(ImageCapabilities frontBufferCapabilities,
+ ImageCapabilities backBufferCapabilities, FlipContents flipContents) {
+ if (frontBufferCapabilities == null || backBufferCapabilities == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.frontBufferCapabilities = frontBufferCapabilities;
+ this.backBufferCapabilities = backBufferCapabilities;
+ this.flipContents = flipContents;
+ }
+
+ /**
+ * Returns a copy of the BufferCapabilities object.
+ *
+ * @return a copy of the BufferCapabilities object.
+ */
+ @Override
+ public Object clone() {
+ return new BufferCapabilities(frontBufferCapabilities, backBufferCapabilities, flipContents);
+ }
+
+ /**
+ * Gets the image capabilities of the front buffer.
+ *
+ * @return the ImageCapabilities object represented capabilities
+ * of the front buffer.
+ */
+ public ImageCapabilities getFrontBufferCapabilities() {
+ return frontBufferCapabilities;
+ }
+
+ /**
+ * Gets the image capabilities of the back buffer.
+ *
+ * @return the ImageCapabilities object represented capabilities
+ * of the back buffer.
+ */
+ public ImageCapabilities getBackBufferCapabilities() {
+ return backBufferCapabilities;
+ }
+
+ /**
+ * Gets the flip contents of the back buffer after page-flipping.
+ *
+ * @return the FlipContents of the back buffer after page-flipping.
+ */
+ public FlipContents getFlipContents() {
+ return flipContents;
+ }
+
+ /**
+ * Checks if the buffer strategy uses page flipping.
+ *
+ * @return true, if the buffer strategy uses page flipping,
+ * false otherwise.
+ */
+ public boolean isPageFlipping() {
+ return flipContents != null;
+ }
+
+ /**
+ * Checks if page flipping is only available in full-screen mode.
+ *
+ * @return true, if page flipping is only available in full-screen mode,
+ * false otherwise.
+ */
+ public boolean isFullScreenRequired() {
+ return false;
+ }
+
+ /**
+ * Checks if page flipping can be performed using more than two buffers.
+ *
+ * @return true, if page flipping can be performed using more than two buffers,
+ * false otherwise.
+ */
+ public boolean isMultiBufferAvailable() {
+ return false;
+ }
+
+ /**
+ * The FlipContents class represents a set of possible back buffer contents
+ * after page-flipping.
+ */
+ public static final class FlipContents {
+
+ /**
+ * The back buffered contents are cleared with the background color
+ * after flipping.
+ */
+ public static final FlipContents BACKGROUND = new FlipContents();
+
+ /**
+ * The back buffered contents are copied to the front buffer before
+ * flipping.
+ */
+ public static final FlipContents COPIED = new FlipContents();
+
+ /**
+ * The back buffer contents are the prior contents of the
+ * front buffer.
+ */
+ public static final FlipContents PRIOR = new FlipContents();
+
+ /**
+ * The back buffer contents are undefined after flipping
+ */
+ public static final FlipContents UNDEFINED = new FlipContents();
+
+ /**
+ * Instantiates a new flip contents.
+ */
+ private FlipContents() {
+
+ }
+
+ /**
+ * Returns the hash code of the FlipContents object.
+ *
+ * @return the hash code of the FlipContents object.
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Returns the String representation of the FlipContents object.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ }
+}
diff --git a/awt/java/awt/Color.java b/awt/java/awt/Color.java
new file mode 100644
index 0000000..e1e4178
--- /dev/null
+++ b/awt/java/awt/Color.java
@@ -0,0 +1,881 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Color class defines colors in the default sRGB color
+ * space or in the specified ColorSpace. Every Color contains alpha value.
+ * The alpha value defines the transparency of a color and can be represented
+ * by a float value in the range 0.0 - 1.0 or 0 - 255.
+ */
+public class Color implements Paint, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 118526816881161077L;
+
+ /*
+ * The values of the following colors are based on 1.5 release behavior which
+ * can be revealed using the following or similar code:
+ * Color c = Color.white;
+ * System.out.println(c);
+ */
+
+ /** The color white. */
+ public static final Color white = new Color(255, 255, 255);
+
+ /** The color white. */
+ public static final Color WHITE = white;
+
+ /** The color light gray. */
+ public static final Color lightGray = new Color(192, 192, 192);
+
+ /** The color light gray. */
+ public static final Color LIGHT_GRAY = lightGray;
+
+ /** The color gray. */
+ public static final Color gray = new Color(128, 128, 128);
+
+ /** The color gray. */
+ public static final Color GRAY = gray;
+
+ /** The color dark gray. */
+ public static final Color darkGray = new Color(64, 64, 64);
+
+ /** The color dark gray. */
+ public static final Color DARK_GRAY = darkGray;
+
+ /** The color black. */
+ public static final Color black = new Color(0, 0, 0);
+
+ /** The color black. */
+ public static final Color BLACK = black;
+
+ /** The color red. */
+ public static final Color red = new Color(255, 0, 0);
+
+ /** The color red. */
+ public static final Color RED = red;
+
+ /** The color pink. */
+ public static final Color pink = new Color(255, 175, 175);
+
+ /** The color pink. */
+ public static final Color PINK = pink;
+
+ /** The color orange. */
+ public static final Color orange = new Color(255, 200, 0);
+
+ /** The color orange. */
+ public static final Color ORANGE = orange;
+
+ /** The color yellow. */
+ public static final Color yellow = new Color(255, 255, 0);
+
+ /** The color yellow. */
+ public static final Color YELLOW = yellow;
+
+ /** The color green. */
+ public static final Color green = new Color(0, 255, 0);
+
+ /** The color green. */
+ public static final Color GREEN = green;
+
+ /** The color magenta. */
+ public static final Color magenta = new Color(255, 0, 255);
+
+ /** The color magenta. */
+ public static final Color MAGENTA = magenta;
+
+ /** The color cyan. */
+ public static final Color cyan = new Color(0, 255, 255);
+
+ /** The color cyan. */
+ public static final Color CYAN = cyan;
+
+ /** The color blue. */
+ public static final Color blue = new Color(0, 0, 255);
+
+ /** The color blue. */
+ public static final Color BLUE = blue;
+
+ /** integer RGB value. */
+ int value;
+
+ /** Float sRGB value. */
+ private float[] frgbvalue;
+
+ /** Color in an arbitrary color space with <code>float</code> components. If null, other value should be used. */
+ private float fvalue[];
+
+ /** Float alpha value. If frgbvalue is null, this is not valid data. */
+ private float falpha;
+
+ /** The color's color space if applicable. */
+ private ColorSpace cs;
+
+ /*
+ * The value of the SCALE_FACTOR is based on 1.5 release behavior which
+ * can be revealed using the following code:
+ * Color c = new Color(100, 100, 100);
+ * Color bc = c.brighter();
+ * System.out.println("Brighter factor: " + ((float)c.getRed())/((float)bc.getRed()));
+ * Color dc = c.darker();
+ * System.out.println("Darker factor: " + ((float)dc.getRed())/((float)c.getRed()));
+ * The result is the same for brighter and darker methods, so we need only
+ * one scale factor for both.
+ */
+ /** The Constant SCALE_FACTOR. */
+ private static final double SCALE_FACTOR = 0.7;
+
+ /** The Constant MIN_SCALABLE. */
+ private static final int MIN_SCALABLE = 3; // should increase when multiplied by SCALE_FACTOR
+
+ /** The current paint context. */
+ transient private PaintContext currentPaintContext;
+
+ /**
+ * Creates a color in the specified ColorSpace, the specified color
+ * components and the specified alpha.
+ *
+ * @param cspace the ColorSpace to be used to define the components.
+ * @param components the components.
+ * @param alpha the alpha.
+ */
+ public Color(ColorSpace cspace, float[] components, float alpha) {
+ int nComps = cspace.getNumComponents();
+ float comp;
+ fvalue = new float[nComps];
+
+ for(int i=0 ; i<nComps; i++) {
+ comp = components[i];
+ if(comp < 0.0f || comp > 1.0f) {
+ // awt.107=Color parameter outside of expected range: component {0}.
+ throw new IllegalArgumentException(
+ Messages.getString("awt.107", i)); //$NON-NLS-1$
+ }
+ fvalue[i] = components[i];
+ }
+
+ if (alpha < 0.0f || alpha > 1.0f) {
+ // awt.108=Alpha value outside of expected range.
+ throw new IllegalArgumentException(Messages.getString("awt.108")); //$NON-NLS-1$
+ }
+ falpha = alpha;
+
+ cs = cspace;
+
+ frgbvalue = cs.toRGB(fvalue);
+
+ value = ((int)(frgbvalue[2]*255 + 0.5)) |
+ (((int)(frgbvalue[1]*255 + 0.5)) << 8 ) |
+ (((int)(frgbvalue[0]*255 + 0.5)) << 16 ) |
+ (((int)(falpha*255 + 0.5)) << 24 );
+ }
+
+ /**
+ * Instantiates a new sRGB color with the specified combined
+ * RGBA value consisting of the alpha component in bits 24-31,
+ * the red component in bits 16-23, the green component in bits 8-15,
+ * and the blue component in bits 0-7. If the hasalpha argument is
+ * false, the alpha has default value - 255.
+ *
+ * @param rgba the RGBA components.
+ * @param hasAlpha alpha parameter is true if alpha bits are valid,
+ * false otherwise.
+ */
+ public Color(int rgba, boolean hasAlpha) {
+ if (!hasAlpha) {
+ value = rgba | 0xFF000000;
+ } else {
+ value = rgba;
+ }
+ }
+
+ /**
+ * Instantiates a new color with the specified red, green, blue and alpha
+ * components.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ * @param a the alpha component.
+ */
+ public Color(int r, int g, int b, int a) {
+ if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b || (a & 0xFF) != a) {
+ // awt.109=Color parameter outside of expected range.
+ throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$
+ }
+ value = b | (g << 8) | (r << 16) | (a << 24);
+ }
+
+ /**
+ * Instantiates a new opaque sRGB color with the specified red, green,
+ * and blue values. The Alpha component is set to the default - 1.0.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ */
+ public Color(int r, int g, int b) {
+ if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b) {
+ // awt.109=Color parameter outside of expected range.
+ throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$
+ }
+ // 0xFF for alpha channel
+ value = b | (g << 8) | (r << 16) | 0xFF000000;
+ }
+
+ /**
+ * Instantiates a new sRGB color with the specified
+ * RGB value consisting of the red component in bits 16-23,
+ * the green component in bits 8-15, and the blue component
+ * in bits 0-7. Alpha has default value - 255.
+ *
+ * @param rgb the RGB components.
+ */
+ public Color(int rgb) {
+ value = rgb | 0xFF000000;
+ }
+
+ /**
+ * Instantiates a new color with the specified red, green, blue and alpha
+ * components.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ * @param a the alpha component.
+ */
+ public Color(float r, float g, float b, float a) {
+ this((int)(r*255+0.5),
+ (int)(g*255+0.5),
+ (int)(b*255+0.5),
+ (int)(a*255+0.5));
+ falpha = a;
+ fvalue = new float[3];
+ fvalue[0] = r;
+ fvalue[1] = g;
+ fvalue[2] = b;
+ frgbvalue = fvalue;
+ }
+
+ /**
+ * Instantiates a new color with the specified red, green, and blue
+ * components and default alfa value - 1.0.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ */
+ public Color(float r, float g, float b) {
+ this(r, g, b, 1.0f);
+ }
+
+ public PaintContext createContext(
+ ColorModel cm,
+ Rectangle r,
+ Rectangle2D r2d,
+ AffineTransform xform,
+ RenderingHints rhs
+ ) {
+ if(currentPaintContext != null) {
+ return currentPaintContext;
+ }
+ currentPaintContext = new Color.ColorPaintContext(value);
+ return currentPaintContext;
+ }
+
+ /**
+ * Returns a string representation of the Color object.
+ *
+ * @return the string representation of the Color object.
+ */
+ @Override
+ public String toString() {
+ /*
+ The format of the string is based on 1.5 release behavior which
+ can be revealed using the following code:
+
+ Color c = new Color(1, 2, 3);
+ System.out.println(c);
+ */
+
+ return getClass().getName() +
+ "[r=" + getRed() + //$NON-NLS-1$
+ ",g=" + getGreen() + //$NON-NLS-1$
+ ",b=" + getBlue() + //$NON-NLS-1$
+ "]"; //$NON-NLS-1$
+ }
+
+ /**
+ * Compares the specified Object to the Color.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is a Color whose
+ * value is equal to this Color, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if(obj instanceof Color) {
+ return ((Color)obj).value == this.value;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a float array containing the color and alpha components of
+ * the Color in the specified ColorSpace.
+ *
+ * @param colorSpace the specified ColorSpace.
+ * @param components the results of this method will be written to
+ * this float array. If null, a float array will be created.
+ *
+ * @return the color and alpha components in a float array.
+ */
+ public float[] getComponents(ColorSpace colorSpace, float[] components) {
+ int nComps = colorSpace.getNumComponents();
+ if(components == null) {
+ components = new float[nComps+1];
+ }
+
+ getColorComponents(colorSpace, components);
+
+ if(frgbvalue != null) {
+ components[nComps] = falpha;
+ } else {
+ components[nComps] = getAlpha()/255f;
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns a float array containing the color components of
+ * the Color in the specified ColorSpace.
+ *
+ * @param colorSpace the specified ColorSpace.
+ * @param components the results of this method will be written to
+ * this float array. If null, a float array will be created.
+ *
+ * @return the color components in a float array.
+ */
+ public float[] getColorComponents(ColorSpace colorSpace, float[] components) {
+ float[] cieXYZComponents = getColorSpace().toCIEXYZ(getColorComponents(null));
+ float[] csComponents = colorSpace.fromCIEXYZ(cieXYZComponents);
+
+ if(components == null) {
+ return csComponents;
+ }
+
+ for(int i=0; i<csComponents.length; i++) {
+ components[i] = csComponents[i];
+ }
+
+ return components;
+ }
+
+ /**
+ * Gets the ColorSpace of this Color.
+ *
+ * @return the ColorSpace object.
+ */
+ public ColorSpace getColorSpace() {
+ if (cs == null) {
+ cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ }
+
+ return cs;
+ }
+
+ /**
+ * Creates a new Color which is a darker than this Color
+ * according to a fixed scale factor.
+ *
+ * @return the darker Color.
+ */
+ public Color darker() {
+ return new Color(
+ (int)(getRed()*SCALE_FACTOR),
+ (int)(getGreen()*SCALE_FACTOR),
+ (int)(getBlue()*SCALE_FACTOR));
+ }
+
+ /**
+ * Creates a new Color which is a brighter than this Color.
+ *
+ * @return the brighter Color.
+ */
+ public Color brighter() {
+
+ int r = getRed();
+ int b = getBlue();
+ int g = getGreen();
+
+ if(r == 0 && b == 0 && g == 0) {
+ return new Color(MIN_SCALABLE, MIN_SCALABLE, MIN_SCALABLE);
+ }
+
+ if(r < MIN_SCALABLE && r != 0) {
+ r = MIN_SCALABLE;
+ } else {
+ r = (int) (r/SCALE_FACTOR);
+ r = (r > 255) ? 255 : r;
+ }
+
+ if(b < MIN_SCALABLE && b != 0) {
+ b = MIN_SCALABLE;
+ } else {
+ b = (int) (b/SCALE_FACTOR);
+ b = (b > 255) ? 255 : b;
+ }
+
+ if(g < MIN_SCALABLE && g != 0) {
+ g = MIN_SCALABLE;
+ } else {
+ g = (int) (g/SCALE_FACTOR);
+ g = (g > 255) ? 255 : g;
+ }
+
+ return new Color(r, g, b);
+ }
+
+ /**
+ * Returns a float array containing the color and alpha components of
+ * the Color in the default sRGB color space.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the RGB color and alpha components in a float array.
+ */
+ public float[] getRGBComponents(float[] components) {
+ if(components == null) {
+ components = new float[4];
+ }
+
+ if(frgbvalue != null) {
+ components[3] = falpha;
+ } else {
+ components[3] = getAlpha()/255f;
+ }
+
+ getRGBColorComponents(components);
+
+ return components;
+ }
+
+ /**
+ * Returns a float array containing the color components of
+ * the Color in the default sRGB color space.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the RGB color components in a float array.
+ */
+ public float[] getRGBColorComponents(float[] components) {
+ if(components == null) {
+ components = new float[3];
+ }
+
+ if(frgbvalue != null) {
+ components[2] = frgbvalue[2];
+ components[1] = frgbvalue[1];
+ components[0] = frgbvalue[0];
+ } else {
+ components[2] = getBlue()/255f;
+ components[1] = getGreen()/255f;
+ components[0] = getRed()/255f;
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns a float array which contains the color and alpha components of
+ * the Color in the ColorSpace of the Color.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the color and alpha components in a float array.
+ */
+ public float[] getComponents(float[] components) {
+ if(fvalue == null) {
+ return getRGBComponents(components);
+ }
+
+ int nColorComps = fvalue.length;
+
+ if(components == null) {
+ components = new float[nColorComps+1];
+ }
+
+ getColorComponents(components);
+
+ components[nColorComps] = falpha;
+
+ return components;
+ }
+
+ /**
+ * Returns a float array which contains the color components of
+ * the Color in the ColorSpace of the Color.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the color components in a float array.
+ */
+ public float[] getColorComponents(float[] components) {
+ if(fvalue == null) {
+ return getRGBColorComponents(components);
+ }
+
+ if(components == null) {
+ components = new float[fvalue.length];
+ }
+
+ for(int i=0; i<fvalue.length; i++) {
+ components[i] = fvalue[i];
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns a hash code of this Color object.
+ *
+ * @return a hash code of this Color object.
+ */
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ public int getTransparency() {
+ switch(getAlpha()) {
+ case 0xff:
+ return Transparency.OPAQUE;
+ case 0:
+ return Transparency.BITMASK;
+ default:
+ return Transparency.TRANSLUCENT;
+ }
+ }
+
+ /**
+ * Gets the red component of the Color in the range 0-255.
+ *
+ * @return the red component of the Color.
+ */
+ public int getRed() {
+ return (value >> 16) & 0xFF;
+ }
+
+ /**
+ * Gets the RGB value that represents the color in the default sRGB ColorModel.
+ *
+ * @return the RGB color value in the default sRGB ColorModel.
+ */
+ public int getRGB() {
+ return value;
+ }
+
+ /**
+ * Gets the green component of the Color in the range 0-255.
+ *
+ * @return the green component of the Color.
+ */
+ public int getGreen() {
+ return (value >> 8) & 0xFF;
+ }
+
+ /**
+ * Gets the blue component of the Color in the range 0-255.
+ *
+ * @return the blue component of the Color.
+ */
+ public int getBlue() {
+ return value & 0xFF;
+ }
+
+ /**
+ * Gets the alpha component of the Color in the range 0-255.
+ *
+ * @return the alpha component of the Color.
+ */
+ public int getAlpha() {
+ return (value >> 24) & 0xFF;
+ }
+
+ /**
+ * Gets the Color from the specified string, or returns the Color
+ * specified by the second parameter.
+ *
+ * @param nm the specified string.
+ * @param def the default Color.
+ *
+ * @return the color from the specified string, or the Color
+ * specified by the second parameter.
+ */
+ public static Color getColor(String nm, Color def) {
+ Integer integer = Integer.getInteger(nm);
+
+ if (integer == null) {
+ return def;
+ }
+
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Gets the Color from the specified string, or returns the Color converted
+ * from the second parameter.
+ *
+ * @param nm the specified string.
+ * @param def the default Color.
+ *
+ * @return the color from the specified string, or the Color
+ * converted from the second parameter.
+ */
+ public static Color getColor(String nm, int def) {
+ Integer integer = Integer.getInteger(nm);
+
+ if (integer == null) {
+ return new Color(def);
+ }
+
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Gets the Color from the specified String.
+ *
+ * @param nm the specified string.
+ *
+ * @return the Color object, or null.
+ */
+ public static Color getColor(String nm) {
+ Integer integer = Integer.getInteger(nm);
+
+ if (integer == null) {
+ return null;
+ }
+
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Decodes a String to an integer and returns the specified opaque Color.
+ *
+ * @param nm a String which represents an opaque color as a 24-bit integer.
+ *
+ * @throws NumberFormatException if the specified string can not be
+ * converted to an integer.
+ */
+ public static Color decode(String nm) throws NumberFormatException {
+ Integer integer = Integer.decode(nm);
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Gets a Color object using the specified values of the HSB color model.
+ *
+ * @param h the hue component of the Color.
+ * @param s the saturation of the Color.
+ * @param b the brightness of the Color.
+ *
+ * @return a color object with the specified hue, saturation and
+ * brightness values.
+ */
+ public static Color getHSBColor(float h, float s, float b) {
+ return new Color(HSBtoRGB(h, s, b));
+ }
+
+ /**
+ * Converts the Color specified by the RGB model to an equivalent
+ * color in the HSB model.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ * @param hsbvals the array of result hue, saturation, brightness
+ * values or null.
+ *
+ * @return the float array of hue, saturation, brightness values.
+ */
+ public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) {
+ if(hsbvals == null) {
+ hsbvals = new float[3];
+ }
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float H, S, B;
+
+ B = V/255.f;
+
+ if(V == temp) {
+ H = S = 0;
+ } else {
+ S = (V - temp)/((float)V);
+
+ float Cr = (V - r) / (float)(V - temp);
+ float Cg = (V - g) / (float)(V - temp);
+ float Cb = (V - b) / (float)(V - temp);
+
+ if (r == V) {
+ H = Cb - Cg;
+ } else if (g == V) {
+ H = 2 + Cr - Cb;
+ } else {
+ H = 4 + Cg - Cr;
+ }
+
+ H /= 6.f;
+ if(H < 0) {
+ H++;
+ }
+ }
+
+ hsbvals[0] = H;
+ hsbvals[1] = S;
+ hsbvals[2] = B;
+
+ return hsbvals;
+ }
+
+ /**
+ * Converts the Color specified by the HSB model to an equivalent
+ * color in the default RGB model.
+ *
+ * @param hue the hue component of the Color.
+ * @param saturation the saturation of the Color.
+ * @param brightness the brightness of the Color.
+ *
+ * @return the RGB value of the color with the specified hue,
+ * saturation and brightness.
+ */
+ public static int HSBtoRGB(float hue, float saturation, float brightness) {
+ float fr, fg, fb;
+
+ if(saturation == 0) {
+ fr = fg = fb = brightness;
+ } else {
+ float H = (hue - (float)Math.floor(hue)) * 6;
+ int I = (int) Math.floor(H);
+ float F = H - I;
+ float M = brightness * (1 - saturation);
+ float N = brightness * (1 - saturation * F);
+ float K = brightness * (1 - saturation * (1 - F));
+
+ switch(I) {
+ case 0:
+ fr = brightness; fg = K; fb = M; break;
+ case 1:
+ fr = N; fg = brightness; fb = M; break;
+ case 2:
+ fr = M; fg = brightness; fb = K; break;
+ case 3:
+ fr = M; fg = N; fb = brightness; break;
+ case 4:
+ fr = K; fg = M; fb = brightness; break;
+ case 5:
+ fr = brightness; fg = M; fb = N; break;
+ default:
+ fr = fb = fg = 0; // impossible, to supress compiler error
+ }
+ }
+
+ int r = (int) (fr * 255. + 0.5);
+ int g = (int) (fg * 255. + 0.5);
+ int b = (int) (fb * 255. + 0.5);
+
+ return (r << 16) | (g << 8) | b | 0xFF000000;
+ }
+
+ /**
+ * The Class ColorPaintContext.
+ */
+ class ColorPaintContext implements PaintContext {
+
+ /** The rgb value. */
+ int rgbValue;
+
+ /** The saved raster. */
+ WritableRaster savedRaster = null;
+
+ /**
+ * Instantiates a new color paint context.
+ *
+ * @param rgb the rgb
+ */
+ protected ColorPaintContext(int rgb) {
+ rgbValue = rgb;
+ }
+
+ public void dispose() {
+ savedRaster = null;
+ }
+
+ public ColorModel getColorModel() {
+ return ColorModel.getRGBdefault();
+ }
+
+ public Raster getRaster(int x, int y, int w, int h) {
+ if (savedRaster == null ||
+ w != savedRaster.getWidth() ||
+ h != savedRaster.getHeight()) {
+ savedRaster =
+ getColorModel().createCompatibleWritableRaster(w, h);
+
+ // Suppose we have here simple INT/RGB color/sample model
+ DataBufferInt intBuffer =
+ (DataBufferInt) savedRaster.getDataBuffer();
+ int rgbValues[] = intBuffer.getData();
+ int rgbFillValue = rgbValue;
+ Arrays.fill(rgbValues, rgbFillValue);
+ }
+
+ return savedRaster;
+ }
+ }
+}
+
diff --git a/awt/java/awt/Component.java b/awt/java/awt/Component.java
new file mode 100644
index 0000000..f19d285
--- /dev/null
+++ b/awt/java/awt/Component.java
@@ -0,0 +1,6408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+//import java.awt.dnd.DropTarget;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InputMethodListener;
+import java.awt.event.InvocationEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.event.PaintEvent;
+import java.awt.event.WindowEvent;
+import java.awt.im.InputContext;
+import java.awt.im.InputMethodRequests;
+import java.awt.image.BufferStrategy;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.VolatileImage;
+import java.awt.image.WritableRaster;
+import java.awt.peer.ComponentPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+//???AWT
+//import javax.accessibility.Accessible;
+//import javax.accessibility.AccessibleComponent;
+//import javax.accessibility.AccessibleContext;
+//import javax.accessibility.AccessibleRole;
+//import javax.accessibility.AccessibleState;
+//import javax.accessibility.AccessibleStateSet;
+
+import org.apache.harmony.awt.ClipRegion;
+//import org.apache.harmony.awt.FieldsAccessor;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.state.State;
+//import org.apache.harmony.awt.text.TextFieldKit;
+//import org.apache.harmony.awt.text.TextKit;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+/**
+ * The abstract Component class specifies an object with a graphical
+ * representation that can be displayed on the screen and that can
+ * interact with the user (for example: scrollbars, buttons, checkboxes).
+ */
+public abstract class Component implements ImageObserver, MenuContainer, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -7644114512714619750L;
+
+ /** The Constant TOP_ALIGNMENT indicates the top alignment of the component. */
+ public static final float TOP_ALIGNMENT = 0.0f;
+
+ /** The Constant CENTER_ALIGNMENT indicates the center alignment of the component. */
+ public static final float CENTER_ALIGNMENT = 0.5f;
+
+ /** The Constant BOTTOM_ALIGNMENT indicates the bottom alignment of the component. */
+ public static final float BOTTOM_ALIGNMENT = 1.0f;
+
+ /** The Constant LEFT_ALIGNMENT indicates the left alignment of the component. */
+ public static final float LEFT_ALIGNMENT = 0.0f;
+
+ /** The Constant RIGHT_ALIGNMENT indicates the right alignment of the component. */
+ public static final float RIGHT_ALIGNMENT = 1.0f;
+
+ /** The Constant childClassesFlags. */
+ private static final Hashtable<Class<?>, Boolean> childClassesFlags = new Hashtable<Class<?>, Boolean>();
+
+ /** The Constant peer. */
+ private static final ComponentPeer peer = new ComponentPeer() {
+ };
+
+ /** The Constant incrementalImageUpdate. */
+ private static final boolean incrementalImageUpdate;
+
+ /** The toolkit. */
+ final transient Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+ //???AWT
+ /*
+ protected abstract class AccessibleAWTComponent extends AccessibleContext implements
+ Serializable, AccessibleComponent {
+ private static final long serialVersionUID = 642321655757800191L;
+
+ protected class AccessibleAWTComponentHandler implements ComponentListener {
+ protected AccessibleAWTComponentHandler() {
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+ AccessibleState.VISIBLE, null);
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ }
+
+ public void componentResized(ComponentEvent e) {
+ }
+
+ public void componentShown(ComponentEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null,
+ AccessibleState.VISIBLE);
+ }
+ }
+
+ protected class AccessibleAWTFocusHandler implements FocusListener {
+ public void focusGained(FocusEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null,
+ AccessibleState.FOCUSED);
+ }
+
+ public void focusLost(FocusEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+ AccessibleState.FOCUSED, null);
+ }
+ }
+
+ protected ComponentListener accessibleAWTComponentHandler;
+
+ protected FocusListener accessibleAWTFocusHandler;
+ */
+ /*
+ * Number of registered property change listeners.
+ */
+ /*
+ int listenersCount;
+
+ public void addFocusListener(FocusListener l) {
+ Component.this.addFocusListener(l);
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ toolkit.lockAWT();
+ try {
+ super.addPropertyChangeListener(listener);
+ listenersCount++;
+ if (accessibleAWTComponentHandler == null) {
+ accessibleAWTComponentHandler = new AccessibleAWTComponentHandler();
+ Component.this.addComponentListener(accessibleAWTComponentHandler);
+ }
+ if (accessibleAWTFocusHandler == null) {
+ accessibleAWTFocusHandler = new AccessibleAWTFocusHandler();
+ Component.this.addFocusListener(accessibleAWTFocusHandler);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean contains(Point p) {
+ toolkit.lockAWT();
+ try {
+ return Component.this.contains(p);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Accessible getAccessibleAt(Point arg0) {
+ toolkit.lockAWT();
+ try {
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Color getBackground() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getBackground();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Rectangle getBounds() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getBounds();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Cursor getCursor() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getCursor();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Font getFont() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getFont();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public FontMetrics getFontMetrics(Font f) {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getFontMetrics(f);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Color getForeground() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getForeground();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Point getLocation() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getLocation();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Point getLocationOnScreen() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getLocationOnScreen();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Dimension getSize() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getSize();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isEnabled() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isEnabled();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isFocusTraversable() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isFocusTraversable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isShowing() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isShowing();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isVisible() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isVisible();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void removeFocusListener(FocusListener l) {
+ Component.this.removeFocusListener(l);
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ toolkit.lockAWT();
+ try {
+ super.removePropertyChangeListener(listener);
+ listenersCount--;
+ if (listenersCount > 0) {
+ return;
+ }
+ // if there are no more listeners, remove handlers:
+ Component.this.removeFocusListener(accessibleAWTFocusHandler);
+ Component.this.removeComponentListener(accessibleAWTComponentHandler);
+ accessibleAWTComponentHandler = null;
+ accessibleAWTFocusHandler = null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void requestFocus() {
+ toolkit.lockAWT();
+ try {
+ Component.this.requestFocus();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setBackground(Color color) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setBackground(color);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setBounds(Rectangle r) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setBounds(r);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setCursor(Cursor cursor) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setCursor(cursor);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setEnabled(boolean enabled) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setEnabled(enabled);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setFont(Font f) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setFont(f);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setForeground(Color color) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setForeground(color);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setLocation(Point p) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setLocation(p);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setSize(Dimension size) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setSize(size);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setVisible(boolean visible) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setVisible(visible);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public Accessible getAccessibleParent() {
+ toolkit.lockAWT();
+ try {
+ Accessible aParent = super.getAccessibleParent();
+ if (aParent != null) {
+ return aParent;
+ }
+ Container parent = getParent();
+ return (parent instanceof Accessible ? (Accessible) parent : null);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public Accessible getAccessibleChild(int i) {
+ toolkit.lockAWT();
+ try {
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public int getAccessibleChildrenCount() {
+ toolkit.lockAWT();
+ try {
+ return 0;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleComponent getAccessibleComponent() {
+ return this;
+ }
+
+ @Override
+ public String getAccessibleDescription() {
+ return super.getAccessibleDescription(); // why override?
+ }
+
+ @Override
+ public int getAccessibleIndexInParent() {
+ toolkit.lockAWT();
+ try {
+ if (getAccessibleParent() == null) {
+ return -1;
+ }
+ int count = 0;
+ Container parent = getParent();
+ for (int i = 0; i < parent.getComponentCount(); i++) {
+ Component aComp = parent.getComponent(i);
+ if (aComp instanceof Accessible) {
+ if (aComp == Component.this) {
+ return count;
+ }
+ ++count;
+ }
+ }
+ return -1;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleRole getAccessibleRole() {
+ toolkit.lockAWT();
+ try {
+ return AccessibleRole.AWT_COMPONENT;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleStateSet getAccessibleStateSet() {
+ toolkit.lockAWT();
+ try {
+ AccessibleStateSet set = new AccessibleStateSet();
+ if (isEnabled()) {
+ set.add(AccessibleState.ENABLED);
+ }
+ if (isFocusable()) {
+ set.add(AccessibleState.FOCUSABLE);
+ }
+ if (hasFocus()) {
+ set.add(AccessibleState.FOCUSED);
+ }
+ if (isOpaque()) {
+ set.add(AccessibleState.OPAQUE);
+ }
+ if (isShowing()) {
+ set.add(AccessibleState.SHOWING);
+ }
+ if (isVisible()) {
+ set.add(AccessibleState.VISIBLE);
+ }
+ return set;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public Locale getLocale() throws IllegalComponentStateException {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getLocale();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ }
+ */
+ /**
+ * The BltBufferStrategy class provides opportunity of blitting
+ * offscreen surfaces to a component. For more information on
+ * blitting, see <a href="http://en.wikipedia.org/wiki/Bit_blit">Bit blit</a>.
+ */
+ protected class BltBufferStrategy extends BufferStrategy {
+
+ /** The back buffers. */
+ protected VolatileImage[] backBuffers;
+
+ /** The caps. */
+ protected BufferCapabilities caps;
+
+ /** The width. */
+ protected int width;
+
+ /** The height. */
+ protected int height;
+
+ /** The validated contents. */
+ protected boolean validatedContents;
+
+ /**
+ * Instantiates a new BltBufferStrategy buffer strategy.
+ *
+ * @param numBuffers the number of buffers.
+ * @param caps the BufferCapabilities.
+ *
+ * @throws NotImplementedException the not implemented exception.
+ */
+ protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) throws org.apache.harmony.luni.util.NotImplementedException {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics.
+ *
+ * @return true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics, false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsLost()
+ */
+ @Override
+ public boolean contentsLost() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color.
+ *
+ * @return true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color,
+ * false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsRestored()
+ */
+ @Override
+ public boolean contentsRestored() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Creates the back buffers.
+ *
+ * @param numBuffers the number of buffers.
+ */
+ protected void createBackBuffers(int numBuffers) {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the BufferCapabilities of the buffer strategy.
+ *
+ * @return the BufferCapabilities.
+ *
+ * @see java.awt.image.BufferStrategy#getCapabilities()
+ */
+ @Override
+ public BufferCapabilities getCapabilities() {
+ return (BufferCapabilities) caps.clone();
+ }
+
+ /**
+ * Gets Graphics of current buffer strategy.
+ *
+ * @return the Graphics of current buffer strategy.
+ *
+ * @see java.awt.image.BufferStrategy#getDrawGraphics()
+ */
+ @Override
+ public Graphics getDrawGraphics() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Revalidates the lost drawing buffer.
+ */
+ protected void revalidate() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Shows the next available buffer.
+ *
+ * @see java.awt.image.BufferStrategy#show()
+ */
+ @Override
+ public void show() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * The FlipBufferStrategy class is for flipping buffers on a component.
+ */
+ protected class FlipBufferStrategy extends BufferStrategy {
+
+ /** The Buffer Capabilities. */
+ protected BufferCapabilities caps;
+
+ /** The drawing buffer. */
+ protected Image drawBuffer;
+
+ /** The drawing VolatileImage buffer. */
+ protected VolatileImage drawVBuffer;
+
+ /** The number of buffers. */
+ protected int numBuffers;
+
+ /** The validated contents indicates if the drawing buffer is restored from
+ * lost state. */
+ protected boolean validatedContents;
+
+ /**
+ * Instantiates a new flip buffer strategy.
+ *
+ * @param numBuffers the number of buffers.
+ * @param caps the BufferCapabilities.
+ *
+ * @throws AWTException if the capabilities supplied could not
+ * be supported or met.
+ */
+ protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps)
+ throws AWTException {
+ //???AWT
+ /*
+ if (!(Component.this instanceof Window) && !(Component.this instanceof Canvas)) {
+ // awt.14B=Only Canvas or Window is allowed
+ throw new ClassCastException(Messages.getString("awt.14B")); //$NON-NLS-1$
+ }
+ */
+ // TODO: throw new AWTException("Capabilities are not supported");
+ this.numBuffers = numBuffers;
+ this.caps = (BufferCapabilities) caps.clone();
+ }
+
+ /**
+ * Returns true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics.
+ *
+ * @return true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics, false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsLost()
+ */
+ @Override
+ public boolean contentsLost() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color.
+ *
+ * @return true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color,
+ * false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsRestored()
+ */
+ @Override
+ public boolean contentsRestored() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Creates flipping buffers with the specified buffer capabilities.
+ *
+ * @param numBuffers the number of buffers.
+ * @param caps the BufferCapabilities.
+ *
+ * @throws AWTException if the capabilities could not be
+ * supported or met.
+ */
+ protected void createBuffers(int numBuffers, BufferCapabilities caps)
+ throws AWTException {
+ if (numBuffers < 2) {
+ // awt.14C=Number of buffers must be greater than one
+ throw new IllegalArgumentException(Messages.getString("awt.14C")); //$NON-NLS-1$
+ }
+ if (!caps.isPageFlipping()) {
+ // awt.14D=Buffer capabilities should support flipping
+ throw new IllegalArgumentException(Messages.getString("awt.14D")); //$NON-NLS-1$
+ }
+ if (!Component.this.behaviour.isDisplayable()) {
+ // awt.14E=Component should be displayable
+ throw new IllegalStateException(Messages.getString("awt.14E")); //$NON-NLS-1$
+ }
+ // TODO: throw new AWTException("Capabilities are not supported");
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Destroy buffers.
+ */
+ protected void destroyBuffers() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Flips the contents of the back buffer to the front buffer.
+ *
+ * @param flipAction the flip action.
+ */
+ protected void flip(BufferCapabilities.FlipContents flipAction) {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Gets the back buffer as Image.
+ *
+ * @return the back buffer as Image.
+ */
+ protected Image getBackBuffer() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Returns the BufferCapabilities of the buffer strategy.
+ *
+ * @return the BufferCapabilities.
+ *
+ * @see java.awt.image.BufferStrategy#getCapabilities()
+ */
+ @Override
+ public BufferCapabilities getCapabilities() {
+ return (BufferCapabilities) caps.clone();
+ }
+
+ /**
+ * Gets Graphics of current buffer strategy.
+ *
+ * @return the Graphics of current buffer strategy.
+ *
+ * @see java.awt.image.BufferStrategy#getDrawGraphics()
+ */
+ @Override
+ public Graphics getDrawGraphics() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Revalidates the lost drawing buffer.
+ */
+ protected void revalidate() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Shows the next available buffer.
+ *
+ * @see java.awt.image.BufferStrategy#show()
+ */
+ @Override
+ public void show() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * The internal component's state utilized by the visual theme.
+ */
+ class ComponentState implements State {
+
+ /** The default minimum size. */
+ private Dimension defaultMinimumSize = new Dimension();
+
+ /**
+ * Checks if the component is enabled.
+ *
+ * @return true, if the component is enabled
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Checks if the component is visible.
+ *
+ * @return true, if the component is visible
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Checks if is focused.
+ *
+ * @return true, if is focused
+ */
+ public boolean isFocused() {
+ //???AWT: return isFocusOwner();
+ return false;
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font
+ */
+ public Font getFont() {
+ return Component.this.getFont();
+ }
+
+ /**
+ * Checks if the font has been set.
+ *
+ * @return true, if the font has been set
+ */
+ public boolean isFontSet() {
+ return font != null;
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @return the background color
+ */
+ public Color getBackground() {
+ Color c = Component.this.getBackground();
+ return (c != null) ? c : getDefaultBackground();
+ }
+
+ /**
+ * Checks if the background is set.
+ *
+ * @return true, if the background is set
+ */
+ public boolean isBackgroundSet() {
+ return backColor != null;
+ }
+
+ /**
+ * Gets the text color.
+ *
+ * @return the text color
+ */
+ public Color getTextColor() {
+ Color c = getForeground();
+ return (c != null) ? c : getDefaultForeground();
+ }
+
+ /**
+ * Checks if the text color is set.
+ *
+ * @return true, if the text color is set
+ */
+ public boolean isTextColorSet() {
+ return foreColor != null;
+ }
+
+ /**
+ * Gets the font metrics.
+ *
+ * @return the font metrics
+ */
+ @SuppressWarnings("deprecation")
+ public FontMetrics getFontMetrics() {
+ return toolkit.getFontMetrics(Component.this.getFont());
+ }
+
+ /**
+ * Gets the bounding rectangle.
+ *
+ * @return the bounding rectangle
+ */
+ public Rectangle getBounds() {
+ return new Rectangle(x, y, w, h);
+ }
+
+ /**
+ * Gets the size of the bounding rectangle.
+ *
+ * @return the size of the bounding rectangle
+ */
+ public Dimension getSize() {
+ return new Dimension(w, h);
+ }
+
+ /**
+ * Gets the window id.
+ *
+ * @return the window id
+ */
+ public long getWindowId() {
+ NativeWindow win = getNativeWindow();
+ return (win != null) ? win.getId() : 0;
+ }
+
+ /**
+ * Gets the default minimum size.
+ *
+ * @return the default minimum size
+ */
+ public Dimension getDefaultMinimumSize() {
+ if (defaultMinimumSize == null) {
+ calculate();
+ }
+ return defaultMinimumSize;
+ }
+
+ /**
+ * Sets the default minimum size.
+ *
+ * @param size the new default minimum size
+ */
+ public void setDefaultMinimumSize(Dimension size) {
+ defaultMinimumSize = size;
+ }
+
+ /**
+ * Reset the default minimum size to null.
+ */
+ public void reset() {
+ defaultMinimumSize = null;
+ }
+
+ /**
+ * Calculate the default minimum size: to be overridden.
+ */
+ public void calculate() {
+ // to be overridden
+ }
+ }
+
+ //???AWT: private transient AccessibleContext accessibleContext;
+
+ /** The behaviour. */
+ final transient ComponentBehavior behaviour;
+
+ //???AWT: Container parent;
+
+ /** The name. */
+ private String name;
+
+ /** The auto name. */
+ private boolean autoName = true;
+
+ /** The font. */
+ private Font font;
+
+ /** The back color. */
+ private Color backColor;
+
+ /** The fore color. */
+ private Color foreColor;
+
+ /** The deprecated event handler. */
+ boolean deprecatedEventHandler = true;
+
+ /** The enabled events. */
+ private long enabledEvents;
+
+ /** The enabled awt events. */
+ private long enabledAWTEvents;
+
+ /** The component listeners. */
+ private final AWTListenerList<ComponentListener> componentListeners = new AWTListenerList<ComponentListener>(
+ this);
+
+ /** The focus listeners. */
+ private final AWTListenerList<FocusListener> focusListeners = new AWTListenerList<FocusListener>(
+ this);
+
+ /** The hierarchy listeners. */
+ private final AWTListenerList<HierarchyListener> hierarchyListeners = new AWTListenerList<HierarchyListener>(
+ this);
+
+ /** The hierarchy bounds listeners. */
+ private final AWTListenerList<HierarchyBoundsListener> hierarchyBoundsListeners = new AWTListenerList<HierarchyBoundsListener>(
+ this);
+
+ /** The key listeners. */
+ private final AWTListenerList<KeyListener> keyListeners = new AWTListenerList<KeyListener>(
+ this);
+
+ /** The mouse listeners. */
+ private final AWTListenerList<MouseListener> mouseListeners = new AWTListenerList<MouseListener>(
+ this);
+
+ /** The mouse motion listeners. */
+ private final AWTListenerList<MouseMotionListener> mouseMotionListeners = new AWTListenerList<MouseMotionListener>(
+ this);
+
+ /** The mouse wheel listeners. */
+ private final AWTListenerList<MouseWheelListener> mouseWheelListeners = new AWTListenerList<MouseWheelListener>(
+ this);
+
+ /** The input method listeners. */
+ private final AWTListenerList<InputMethodListener> inputMethodListeners = new AWTListenerList<InputMethodListener>(
+ this);
+
+ /** The x. */
+ int x;
+
+ /** The y. */
+ int y;
+
+ /** The w. */
+ int w;
+
+ /** The h. */
+ int h;
+
+ /** The maximum size. */
+ private Dimension maximumSize;
+
+ /** The minimum size. */
+ private Dimension minimumSize;
+
+ /** The preferred size. */
+ private Dimension preferredSize;
+
+ /** The bounds mask param. */
+ private int boundsMaskParam;
+
+ /** The ignore repaint. */
+ private boolean ignoreRepaint;
+
+ /** The enabled. */
+ private boolean enabled = true;
+
+ /** The input methods enabled. */
+ private boolean inputMethodsEnabled = true;
+
+ /** The dispatch to im. */
+ transient boolean dispatchToIM = true;
+
+ /** The focusable. */
+ private boolean focusable = true; // By default, all Components return
+
+ // true from isFocusable() method
+ /** The visible. */
+ boolean visible = true;
+
+ /** The called set focusable. */
+ private boolean calledSetFocusable;
+
+ /** The overriden is focusable. */
+ private boolean overridenIsFocusable = true;
+
+ /** The focus traversal keys enabled. */
+ private boolean focusTraversalKeysEnabled = true;
+
+ /** Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, UP_CYCLE_TRAVERSAL_KEYS. */
+ private final Map<Integer, Set<? extends AWTKeyStroke>> traversalKeys = new HashMap<Integer, Set<? extends AWTKeyStroke>>();
+
+ /** The traversal i ds. */
+ int[] traversalIDs;
+
+ /** The locale. */
+ private Locale locale;
+
+ /** The orientation. */
+ private ComponentOrientation orientation;
+
+ /** The property change support. */
+ private PropertyChangeSupport propertyChangeSupport;
+
+ //???AWT: private ArrayList<PopupMenu> popups;
+
+ /** The coalescer. */
+ private boolean coalescer;
+
+ /** The events table. */
+ private Hashtable<Integer, LinkedList<AWTEvent>> eventsTable;
+
+ /** Cashed reference used during EventQueue.postEvent() */
+ private LinkedList<AWTEvent> eventsList;
+
+ /** The hierarchy changing counter. */
+ private int hierarchyChangingCounter;
+
+ /** The was showing. */
+ private boolean wasShowing;
+
+ /** The was displayable. */
+ private boolean wasDisplayable;
+
+ /** The cursor. */
+ Cursor cursor;
+
+ //???AWT: DropTarget dropTarget;
+
+ /** The mouse exited expected. */
+ private boolean mouseExitedExpected;
+
+ /** The repaint region. */
+ transient MultiRectArea repaintRegion;
+
+ //???AWT: transient RedrawManager redrawManager;
+ /** The redraw manager. */
+ transient Object redrawManager;
+
+ /** The valid. */
+ private boolean valid;
+
+ /** The updated images. */
+ private HashMap<Image, ImageParameters> updatedImages;
+
+ /**
+ * The lock object for private component's data which don't affect the
+ * component hierarchy.
+ */
+ private class ComponentLock {
+ }
+
+ /** The component lock. */
+ private final transient Object componentLock = new ComponentLock();
+ static {
+ PrivilegedAction<String[]> action = new PrivilegedAction<String[]>() {
+ public String[] run() {
+ String properties[] = new String[2];
+ properties[0] = System.getProperty("awt.image.redrawrate", "100"); //$NON-NLS-1$ //$NON-NLS-2$
+ properties[1] = System.getProperty("awt.image.incrementaldraw", "true"); //$NON-NLS-1$ //$NON-NLS-2$
+ return properties;
+ }
+ };
+ String properties[] = AccessController.doPrivileged(action);
+ // FIXME: rate is never used, can this code and the get property above
+ // be removed?
+ // int rate;
+ //
+ // try {
+ // rate = Integer.decode(properties[0]).intValue();
+ // } catch (NumberFormatException e) {
+ // rate = 100;
+ // }
+ incrementalImageUpdate = properties[1].equals("true"); //$NON-NLS-1$
+ }
+
+ /**
+ * Instantiates a new component.
+ */
+ protected Component() {
+ toolkit.lockAWT();
+ try {
+ orientation = ComponentOrientation.UNKNOWN;
+ redrawManager = null;
+ //???AWT
+ /*
+ traversalIDs = this instanceof Container ? KeyboardFocusManager.contTraversalIDs
+ : KeyboardFocusManager.compTraversalIDs;
+ for (int element : traversalIDs) {
+ traversalKeys.put(new Integer(element), null);
+ }
+ behaviour = createBehavior();
+ */
+ behaviour = null;
+
+ deriveCoalescerFlag();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Determine that the class inherited from Component declares the method
+ * coalesceEvents(), and put the results to the childClassesFlags map.
+ */
+ private void deriveCoalescerFlag() {
+ Class<?> thisClass = getClass();
+ boolean flag = true;
+ synchronized (childClassesFlags) {
+ Boolean flagWrapper = childClassesFlags.get(thisClass);
+ if (flagWrapper == null) {
+ Method coalesceMethod = null;
+ for (Class<?> c = thisClass; c != Component.class; c = c.getSuperclass()) {
+ try {
+ coalesceMethod = c.getDeclaredMethod("coalesceEvents", new Class[] { //$NON-NLS-1$
+ Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$
+ Class.forName("java.awt.AWTEvent") }); //$NON-NLS-1$
+ } catch (Exception e) {
+ }
+ if (coalesceMethod != null) {
+ break;
+ }
+ }
+ flag = (coalesceMethod != null);
+ childClassesFlags.put(thisClass, Boolean.valueOf(flag));
+ } else {
+ flag = flagWrapper.booleanValue();
+ }
+ }
+ coalescer = flag;
+ if (flag) {
+ eventsTable = new Hashtable<Integer, LinkedList<AWTEvent>>();
+ } else {
+ eventsTable = null;
+ }
+ }
+
+ /**
+ * Sets the name of the Component.
+ *
+ * @param name the new name of the Component.
+ */
+ public void setName(String name) {
+ String oldName;
+ toolkit.lockAWT();
+ try {
+ autoName = false;
+ oldName = this.name;
+ this.name = name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("name", oldName, name); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the name of this Component.
+ *
+ * @return the name of this Component.
+ */
+ public String getName() {
+ toolkit.lockAWT();
+ try {
+ if ((name == null) && autoName) {
+ name = autoName();
+ }
+ return name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Auto name.
+ *
+ * @return the string
+ */
+ String autoName() {
+ String name = getClass().getName();
+ if (name.indexOf("$") != -1) { //$NON-NLS-1$
+ return null;
+ }
+ //???AWT
+ //int number = toolkit.autoNumber.nextComponent++;
+ int number = 0;
+ name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$
+ return name;
+ }
+
+ /**
+ * Returns the string representation of the Component.
+ *
+ * @return the string representation of the Component.
+ */
+ @Override
+ public String toString() {
+ /*
+ * The format is based on 1.5 release behavior which can be revealed by
+ * the following code:
+ *
+ * Component c = new Component(){}; c.setVisible(false);
+ * System.out.println(c);
+ */
+ toolkit.lockAWT();
+ try {
+ return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public void add(PopupMenu popup) {
+ toolkit.lockAWT();
+ try {
+ if (popup.getParent() == this) {
+ return;
+ }
+ if (popups == null) {
+ popups = new ArrayList<PopupMenu>();
+ }
+ popup.setParent(this);
+ popups.add(popup);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Returns true, if the component contains the specified Point.
+ *
+ * @param p the Point.
+ *
+ * @return true, if the component contains the specified Point,
+ * false otherwise.
+ */
+ public boolean contains(Point p) {
+ toolkit.lockAWT();
+ try {
+ return contains(p.x, p.y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns true, if the component contains the point with
+ * the specified coordinates.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if the component contains the point with
+ * the specified coordinates, false otherwise.
+ */
+ public boolean contains(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ return inside(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by replaced by getSize() method.
+ *
+ * @return the dimension.
+ *
+ * @deprecated Replaced by getSize() method.
+ */
+ @Deprecated
+ public Dimension size() {
+ toolkit.lockAWT();
+ try {
+ return new Dimension(w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public Container getParent() {
+ toolkit.lockAWT();
+ try {
+ return parent;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * List.
+ *
+ * @param out the out
+ * @param indent the indent
+ *
+ * @return the nearest heavyweight ancestor in hierarchy or
+ * <code>null</code> if not found
+ */
+ //???AWT
+ /*
+ Component getHWAncestor() {
+ return (parent != null ? parent.getHWSurface() : null);
+ }
+ */
+
+ /**
+ * @return heavyweight component that is equal to or is a nearest
+ * heavyweight container of the current component, or
+ * <code>null</code> if not found
+ */
+ //???AWT
+ /*
+ Component getHWSurface() {
+ Component parent;
+ for (parent = this; (parent != null) && (parent.isLightweight()); parent = parent
+ .getParent()) {
+ ;
+ }
+ return parent;
+ }
+
+ Window getWindowAncestor() {
+ Component par;
+ for (par = this; par != null && !(par instanceof Window); par = par.getParent()) {
+ ;
+ }
+ return (Window) par;
+ }
+ */
+
+ /** To be called by container */
+ //???AWT
+ /*
+ void setParent(Container parent) {
+ this.parent = parent;
+ setRedrawManager();
+ }
+
+ void setRedrawManager() {
+ redrawManager = getRedrawManager();
+ }
+
+ public void remove(MenuComponent menu) {
+ toolkit.lockAWT();
+ try {
+ if (menu.getParent() == this) {
+ menu.setParent(null);
+ popups.remove(menu);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+ /**
+ * Prints a list of this component with the specified number of
+ * leading whitespace characters to the specified PrintStream.
+ *
+ * @param out the output PrintStream object.
+ * @param indent how many leading whitespace characters to prepend
+ */
+ public void list(PrintStream out, int indent) {
+ toolkit.lockAWT();
+ try {
+ out.println(getIndentStr(indent) + this);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints a list of this component to the specified PrintWriter.
+ *
+ * @param out the output PrintWriter object.
+ */
+ public void list(PrintWriter out) {
+ toolkit.lockAWT();
+ try {
+ list(out, 1);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints a list of this component with the specified number of
+ * leading whitespace characters to the specified PrintWriter.
+ *
+ * @param out the output PrintWriter object.
+ * @param indent how many leading whitespace characters to prepend
+ */
+ public void list(PrintWriter out, int indent) {
+ toolkit.lockAWT();
+ try {
+ out.println(getIndentStr(indent) + this);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets a string composed of the desired number of
+ * whitespace characters.
+ *
+ * @param indent the length of the String to return
+ *
+ * @return the string composed of the desired number of
+ * whitespace characters
+ */
+ String getIndentStr(int indent) {
+ char[] ind = new char[indent];
+ for (int i = 0; i < indent; ind[i++] = ' ') {
+ ;
+ }
+ return new String(ind);
+ }
+
+ /**
+ * Prints a list of this component to the specified PrintStream
+ *
+ * @param out the output PrintStream object.
+ */
+ public void list(PrintStream out) {
+ toolkit.lockAWT();
+ try {
+ // default indent = 1
+ list(out, 1);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints a list of this component to the standard system
+ * output stream.
+ */
+ public void list() {
+ toolkit.lockAWT();
+ try {
+ list(System.out);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints this component.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void print(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ paint(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints the component and all of its subcomponents.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void printAll(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ paintAll(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the size of the Component specified by width and height
+ * parameters.
+ *
+ * @param width the width of the Component.
+ * @param height the height of the Component.
+ */
+ public void setSize(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ resize(width, height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the size of the Component specified by Dimension object.
+ *
+ * @param d the new size of the Component.
+ */
+ public void setSize(Dimension d) {
+ toolkit.lockAWT();
+ try {
+ resize(d);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by setSize(int, int) method.
+ *
+ * @param width the width.
+ * @param height the height.
+ *
+ * @deprecated Replaced by setSize(int, int) method.
+ */
+ @Deprecated
+ public void resize(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ boundsMaskParam = NativeWindow.BOUNDS_NOMOVE;
+ setBounds(x, y, width, height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by setSize(int, int) method.
+ *
+ * @param size the size.
+ *
+ * @deprecated Replaced by setSize(int, int) method.
+ */
+ @Deprecated
+ public void resize(Dimension size) {
+ toolkit.lockAWT();
+ try {
+ setSize(size.width, size.height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this component is completely opaque.
+ *
+ * @return true, if this component is completely opaque,
+ * false by default.
+ */
+ public boolean isOpaque() {
+ toolkit.lockAWT();
+ try {
+ return behaviour.isOpaque();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Disables.
+ *
+ * @deprecated Replaced by setEnabled(boolean) method.
+ */
+ @Deprecated
+ public void disable() {
+ toolkit.lockAWT();
+ try {
+ setEnabledImpl(false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ //???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false);
+ }
+
+ /**
+ * Enables this component.
+ *
+ * @deprecated Replaced by setEnabled(boolean) method.
+ */
+ @Deprecated
+ public void enable() {
+ toolkit.lockAWT();
+ try {
+ setEnabledImpl(true);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ //???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true);
+ }
+
+ /**
+ * Enables or disable this component.
+ *
+ * @param b the boolean parameter.
+ *
+ * @deprecated Replaced by setEnabled(boolean) method.
+ */
+ @Deprecated
+ public void enable(boolean b) {
+ toolkit.lockAWT();
+ try {
+ if (b) {
+ enable();
+ } else {
+ disable();
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Stores the location of this component to the specified Point object;
+ * returns the point of the component's top-left corner.
+ *
+ * @param rv the Point object where the component's top-left corner
+ * position will be stored.
+ *
+ * @return the Point which specifies the component's top-left corner.
+ */
+ public Point getLocation(Point rv) {
+ toolkit.lockAWT();
+ try {
+ if (rv == null) {
+ rv = new Point();
+ }
+ rv.setLocation(getX(), getY());
+ return rv;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the location of this component on the form;
+ * returns the point of the component's top-left corner.
+ *
+ * @return the Point which specifies the component's top-left corner.
+ */
+ public Point getLocation() {
+ toolkit.lockAWT();
+ try {
+ return location();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the size of this Component.
+ *
+ * @return the size of this Component.
+ */
+ public Dimension getSize() {
+ toolkit.lockAWT();
+ try {
+ return size();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Stores the size of this Component to the specified Dimension
+ * object.
+ *
+ * @param rv the Dimension object where the size of the Component
+ * will be stored.
+ *
+ * @return the Dimension of this Component.
+ */
+ public Dimension getSize(Dimension rv) {
+ toolkit.lockAWT();
+ try {
+ if (rv == null) {
+ rv = new Dimension();
+ }
+ rv.setSize(getWidth(), getHeight());
+ return rv;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this Component is valid. A component is valid
+ * if it is correctly sized and positioned within its parent container
+ * and all its children are also valid.
+ *
+ * @return true, if the Component is valid, false otherwise.
+ */
+ public boolean isValid() {
+ toolkit.lockAWT();
+ try {
+ return valid && behaviour.isDisplayable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getComponentAt(int, int) method.
+ *
+ * @return the Point.
+ *
+ * @deprecated Replaced by getComponentAt(int, int) method.
+ */
+ @Deprecated
+ public Point location() {
+ toolkit.lockAWT();
+ try {
+ return new Point(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Connects this Component to a native screen resource and makes it
+ * displayable. This method not be called directly by user applications.
+ */
+ public void addNotify() {
+ toolkit.lockAWT();
+ try {
+ prepare4HierarchyChange();
+ behaviour.addNotify();
+ //???AWT
+// finishHierarchyChange(this, parent, 0);
+// if (dropTarget != null) {
+// dropTarget.addNotify(peer);
+// }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Map to display.
+ *
+ * @param b the b
+ */
+ void mapToDisplay(boolean b) {
+ //???AWT
+ /*
+ if (b && !isDisplayable()) {
+ if ((this instanceof Window) || ((parent != null) && parent.isDisplayable())) {
+ addNotify();
+ }
+ } else if (!b && isDisplayable()) {
+ removeNotify();
+ }
+ */
+ }
+
+ /**
+ * Gets the toolkit.
+ *
+ * @return accessible context specific for particular component
+ */
+ //???AWT
+ /*
+ AccessibleContext createAccessibleContext() {
+ return null;
+ }
+
+ public AccessibleContext getAccessibleContext() {
+ toolkit.lockAWT();
+ try {
+ if (accessibleContext == null) {
+ accessibleContext = createAccessibleContext();
+ }
+ return accessibleContext;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Gets Toolkit for the current Component.
+ *
+ * @return the Toolkit of this Component.
+ */
+ public Toolkit getToolkit() {
+ return toolkit;
+ }
+
+ /**
+ * Gets this component's locking object for AWT component tree
+ * and layout operations.
+ *
+ * @return the tree locking object.
+ */
+ public final Object getTreeLock() {
+ return toolkit.awtTreeLock;
+ }
+
+ /**
+ * @param evt the Event.
+ * @param what the event's key.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Use ActionListener class for registering event listener.
+ */
+ @Deprecated
+ public boolean action(Event evt, Object what) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+
+ /**
+ * Gets the property change support.
+ *
+ * @return the property change support
+ */
+ private PropertyChangeSupport getPropertyChangeSupport() {
+ synchronized (componentLock) {
+ if (propertyChangeSupport == null) {
+ propertyChangeSupport = new PropertyChangeSupport(this);
+ }
+ return propertyChangeSupport;
+ }
+ }
+
+ //???AWT
+ /*
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ getPropertyChangeSupport().addPropertyChangeListener(listener);
+ }
+
+ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ getPropertyChangeSupport().addPropertyChangeListener(propertyName, listener);
+ }
+
+ public void applyComponentOrientation(ComponentOrientation orientation) {
+ toolkit.lockAWT();
+ try {
+ setComponentOrientation(orientation);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Returns true if the set of focus traversal keys for the given focus
+ * traversal operation has been explicitly defined for this Component.
+ *
+ * @param id the ID of traversal key.
+ *
+ * @return true, if the set of focus traversal keys for the given focus
+ * traversal operation has been explicitly defined for this Component,
+ * false otherwise.
+ */
+ public boolean areFocusTraversalKeysSet(int id) {
+ toolkit.lockAWT();
+ try {
+ Integer Id = new Integer(id);
+ if (traversalKeys.containsKey(Id)) {
+ return traversalKeys.get(Id) != null;
+ }
+ // awt.14F=invalid focus traversal key identifier
+ throw new IllegalArgumentException(Messages.getString("awt.14F")); //$NON-NLS-1$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the bounds of the Component.
+ *
+ * @return the rectangle bounds of the Component.
+ *
+ * @deprecated Use getBounds() methood.
+ */
+ @Deprecated
+ public Rectangle bounds() {
+ toolkit.lockAWT();
+ try {
+ return new Rectangle(x, y, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the construction status of a specified image
+ * with the specified width and height that is being created.
+ *
+ *
+ * @param image the image to be checked.
+ * @param width the width of scaled image which status is being checked, or -1.
+ * @param height the height of scaled image which status is being checked, or -1.
+ * @param observer the ImageObserver object to be notified while
+ * the image is being prepared.
+ *
+ * @return the ImageObserver flags of the current state of the image data.
+ */
+ public int checkImage(Image image, int width, int height, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.checkImage(image, width, height, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the construction status of a specified image that is being created.
+ *
+ *
+ * @param image the image to be checked.
+ * @param observer the ImageObserver object to be notified while
+ * the image is being prepared.
+ *
+ * @return the ImageObserver flags of the current state of the image data.
+ */
+ public int checkImage(Image image, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.checkImage(image, -1, -1, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Coalesces the existed event with new event.
+ *
+ * @param existingEvent the existing event in the EventQueue.
+ * @param newEvent the new event to be posted to the EventQueue.
+ *
+ * @return the coalesced AWTEvent, or null if there is no coalescing done.
+ */
+ protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) {
+ toolkit.lockAWT();
+ try {
+ // Nothing to do:
+ // 1. Mouse events coalesced at WTK level
+ // 2. Paint events handled by RedrawManager
+ // This method is for overriding only
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if this Component is a coalescer.
+ *
+ * @return true, if is coalescer
+ */
+ boolean isCoalescer() {
+ return coalescer;
+ }
+
+ /**
+ * Gets the relative event.
+ *
+ * @param id the id
+ *
+ * @return the relative event
+ */
+ AWTEvent getRelativeEvent(int id) {
+ Integer idWrapper = new Integer(id);
+ eventsList = eventsTable.get(idWrapper);
+ if (eventsList == null) {
+ eventsList = new LinkedList<AWTEvent>();
+ eventsTable.put(idWrapper, eventsList);
+ return null;
+ }
+ if (eventsList.isEmpty()) {
+ return null;
+ }
+ return eventsList.getLast();
+ }
+
+ /**
+ * Adds the new event.
+ *
+ * @param event the event
+ */
+ void addNewEvent(AWTEvent event) {
+ eventsList.addLast(event);
+ }
+
+ /**
+ * Removes the relative event.
+ */
+ void removeRelativeEvent() {
+ eventsList.removeLast();
+ }
+
+ /**
+ * Removes the next event.
+ *
+ * @param id the id
+ */
+ void removeNextEvent(int id) {
+ eventsTable.get(new Integer(id)).removeFirst();
+ }
+
+ /**
+ * Creates the image with the specified ImageProducer.
+ *
+ * @param producer the ImageProducer to be used for image creation.
+ *
+ * @return the image with the specified ImageProducer.
+ */
+ public Image createImage(ImageProducer producer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.createImage(producer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Creates an off-screen drawable image to be used for double buffering.
+ *
+ * @param width the width of the image.
+ * @param height the height of the image.
+ *
+ * @return the off-screen drawable image or null if the component is not
+ * displayable or GraphicsEnvironment.isHeadless() method returns true.
+ */
+ public Image createImage(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc == null) {
+ return null;
+ }
+ ColorModel cm = gc.getColorModel(Transparency.OPAQUE);
+ WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
+ Image image = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null);
+ fillImageBackground(image, width, height);
+ return image;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Creates an off-screen drawable image with the specified width,
+ * height and ImageCapabilities.
+ *
+ * @param width the width
+ * @param height the height
+ * @param caps the ImageCapabilities.
+ *
+ * @return the volatile image
+ *
+ * @throws AWTException if an image with the specified capabilities
+ * cannot be created.
+ */
+ public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps)
+ throws AWTException {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc == null) {
+ return null;
+ }
+ VolatileImage image = gc.createCompatibleVolatileImage(width, height, caps);
+ fillImageBackground(image, width, height);
+ return image;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Creates a volatile off-screen drawable image which is used
+ * for double buffering.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ *
+ * @return the volatile image a volatile off-screen drawable image
+ * which is used for double buffering or null if the component
+ * is not displayable, or GraphicsEnvironment.isHeadless() method
+ * returns true.
+ */
+ public VolatileImage createVolatileImage(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc == null) {
+ return null;
+ }
+ VolatileImage image = gc.createCompatibleVolatileImage(width, height);
+ fillImageBackground(image, width, height);
+ return image;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Fill the image being created by createImage() or createVolatileImage()
+ * with the component's background color to prepare it for double-buffered
+ * painting.
+ *
+ * @param image the image
+ * @param width the width
+ * @param height the height
+ */
+ private void fillImageBackground(Image image, int width, int height) {
+ Graphics gr = image.getGraphics();
+ gr.setColor(getBackground());
+ gr.fillRect(0, 0, width, height);
+ gr.dispose();
+ }
+
+ /**
+ * Delivers event.
+ *
+ * @param evt the event.
+ *
+ * @deprecated Replaced by dispatchEvent(AWTEvent e) method.
+ */
+ @Deprecated
+ public void deliverEvent(Event evt) {
+ postEvent(evt);
+ }
+
+ /**
+ * Prompts the layout manager to lay out this component.
+ */
+ public void doLayout() {
+ toolkit.lockAWT();
+ try {
+ layout();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ // Implemented in Container
+ }
+
+ /**
+ * Fire property change impl.
+ *
+ * @param propertyName the property name
+ * @param oldValue the old value
+ * @param newValue the new value
+ */
+ private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) {
+ PropertyChangeSupport pcs;
+ synchronized (componentLock) {
+ if (propertyChangeSupport == null) {
+ return;
+ }
+ pcs = propertyChangeSupport;
+ }
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ /**
+ * Reports a bound property changes for int properties.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ protected void firePropertyChange(String propertyName, int oldValue, int newValue) {
+ firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue));
+ }
+
+ /**
+ * Report a bound property change for a boolean-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the property's old value.
+ * @param newValue the property's new value.
+ */
+ protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
+ firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean
+ .valueOf(newValue));
+ }
+
+ /**
+ * Reports a bound property change for an Object-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the property's old value
+ * @param newValue the property's new value
+ */
+ protected void firePropertyChange(final String propertyName, final Object oldValue,
+ final Object newValue) {
+ firePropertyChangeImpl(propertyName, oldValue, newValue);
+ }
+
+ /**
+ * Report a bound property change for a byte-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the property's old value.
+ * @param newValue the property's new value.
+ */
+ public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {
+ firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue));
+ }
+
+ /**
+ * Report a bound property change for a char-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, char oldValue, char newValue) {
+ firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue));
+ }
+
+ /**
+ * Report a bound property change for a short-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, short oldValue, short newValue) {
+ firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue));
+ }
+
+ /**
+ * Report a bound property change for a long-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, long oldValue, long newValue) {
+ firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue));
+ }
+
+ /**
+ * Report a bound property change for a float-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, float oldValue, float newValue) {
+ firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue));
+ }
+
+ /**
+ * Report a bound property change for a double-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, double oldValue, double newValue) {
+ firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue));
+ }
+
+ /**
+ * Gets the alignment along the x axis.
+ *
+ * @return the alignment along the x axis.
+ */
+ public float getAlignmentX() {
+ toolkit.lockAWT();
+ try {
+ return CENTER_ALIGNMENT;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the alignment along the y axis.
+ *
+ * @return the alignment along y axis.
+ */
+ public float getAlignmentY() {
+ toolkit.lockAWT();
+ try {
+ return CENTER_ALIGNMENT;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the background color for this component.
+ *
+ * @return the background color for this component.
+ */
+ public Color getBackground() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if ((backColor == null) && (parent != null)) {
+ return parent.getBackground();
+ }
+ */
+ return backColor;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the bounding rectangle of this component.
+ *
+ * @return the bounding rectangle of this component.
+ */
+ public Rectangle getBounds() {
+ toolkit.lockAWT();
+ try {
+ return bounds();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Writes the data of the bounding rectangle to the specified
+ * Rectangle object.
+ *
+ * @param rv the Rectangle object where the bounding rectangle's data is stored.
+ *
+ * @return the bounding rectangle.
+ */
+ public Rectangle getBounds(Rectangle rv) {
+ toolkit.lockAWT();
+ try {
+ if (rv == null) {
+ rv = new Rectangle();
+ }
+ rv.setBounds(x, y, w, h);
+ return rv;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the color model of the Component.
+ *
+ * @return the color model of the Component.
+ */
+ public ColorModel getColorModel() {
+ toolkit.lockAWT();
+ try {
+ return getToolkit().getColorModel();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Component which contains the specified Point.
+ *
+ * @param p the Point.
+ *
+ * @return the Component which contains the specified Point.
+ */
+ public Component getComponentAt(Point p) {
+ toolkit.lockAWT();
+ try {
+ return getComponentAt(p.x, p.y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Component which contains the point with the
+ * specified coordinates.
+ *
+ * @param x the x coordinate of the point.
+ * @param y the y coordinate of the point.
+ *
+ * @return the Component which contains the point with the
+ * specified coordinates.
+ */
+ public Component getComponentAt(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ return locate(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the component's orientation.
+ *
+ * @return the component's orientation.
+ */
+ public ComponentOrientation getComponentOrientation() {
+ toolkit.lockAWT();
+ try {
+ return orientation;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the cursor of the Component.
+ *
+ * @return the Cursor.
+ */
+ public Cursor getCursor() {
+ toolkit.lockAWT();
+ try {
+ if (cursor != null) {
+ return cursor;
+ //???AWT
+ /*
+ } else if (parent != null) {
+ return parent.getCursor();
+ */
+ }
+ return Cursor.getDefaultCursor();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public DropTarget getDropTarget() {
+ toolkit.lockAWT();
+ try {
+ return dropTarget;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Container getFocusCycleRootAncestor() {
+ toolkit.lockAWT();
+ try {
+ for (Container c = parent; c != null; c = c.getParent()) {
+ if (c.isFocusCycleRoot()) {
+ return c;
+ }
+ }
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
+ toolkit.lockAWT();
+ try {
+ Integer kId = new Integer(id);
+ KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId);
+ Set<? extends AWTKeyStroke> keys = traversalKeys.get(kId);
+ if (keys == null && parent != null) {
+ keys = parent.getFocusTraversalKeys(id);
+ }
+ if (keys == null) {
+ keys = KeyboardFocusManager.getCurrentKeyboardFocusManager()
+ .getDefaultFocusTraversalKeys(id);
+ }
+ return (Set<AWTKeyStroke>) keys;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Checks if the the focus traversal keys are enabled for this component.
+ *
+ * @return true, if the the focus traversal keys are enabled for
+ * this component, false otherwise.
+ */
+ public boolean getFocusTraversalKeysEnabled() {
+ toolkit.lockAWT();
+ try {
+ return focusTraversalKeysEnabled;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the font metrics of the specified Font.
+ *
+ * @param f the Font.
+ *
+ * @return the FontMetrics of the specified Font.
+ */
+ @SuppressWarnings("deprecation")
+ public FontMetrics getFontMetrics(Font f) {
+ return toolkit.getFontMetrics(f);
+ }
+
+ /**
+ * Gets the foreground color of the Component.
+ *
+ * @return the foreground color of the Component.
+ */
+ public Color getForeground() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if (foreColor == null && parent != null) {
+ return parent.getForeground();
+ }
+ */
+ return foreColor;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Graphics of the Component or null if this Component
+ * is not displayable.
+ *
+ * @return the Graphics of the Component or null if this Component
+ * is not displayable.
+ */
+ public Graphics getGraphics() {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ Graphics g = behaviour.getGraphics(0, 0, w, h);
+ g.setColor(foreColor);
+ g.setFont(font);
+ return g;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+
+ /**
+ * Gets the GraphicsConfiguration associated with this Component.
+ *
+ * @return the GraphicsConfiguration associated with this Component.
+ */
+ public GraphicsConfiguration getGraphicsConfiguration() {
+ //???AWT
+ /*
+ toolkit.lockAWT();
+ try {
+ Window win = getWindowAncestor();
+ if (win == null) {
+ return null;
+ }
+ return win.getGraphicsConfiguration();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ */
+ return null;
+ }
+
+ /**
+ * Gets the height of the Component.
+ *
+ * @return the height of the Component.
+ */
+ public int getHeight() {
+ toolkit.lockAWT();
+ try {
+ return h;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns true if paint messages received from the operating system
+ * should be ignored.
+ *
+ * @return true if paint messages received from the operating system
+ * should be ignored, false otherwise.
+ */
+ public boolean getIgnoreRepaint() {
+ toolkit.lockAWT();
+ try {
+ return ignoreRepaint;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the input context of this component for handling
+ * the communication with input methods when text is entered
+ * in this component.
+ *
+ * @return the InputContext used by this Component or
+ * null if no context is specifined.
+ */
+ public InputContext getInputContext() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ Container parent = getParent();
+ if (parent != null) {
+ return parent.getInputContext();
+ }
+ */
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the input method request handler which supports requests
+ * from input methods for this component, or null for default.
+ *
+ * @return the input method request handler which supports requests
+ * from input methods for this component, or null for default.
+ */
+ public InputMethodRequests getInputMethodRequests() {
+ return null;
+ }
+
+ /**
+ * Gets the locale of this Component.
+ *
+ * @return the locale of this Component.
+ */
+ public Locale getLocale() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if (locale == null) {
+ if (parent == null) {
+ if (this instanceof Window) {
+ return Locale.getDefault();
+ }
+ // awt.150=no parent
+ throw new IllegalComponentStateException(Messages.getString("awt.150")); //$NON-NLS-1$
+ }
+ return getParent().getLocale();
+ }
+ */
+ return locale;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the location of this component in the form of a point
+ * specifying the component's top-left corner in the
+ * screen's coordinate space.
+ *
+ * @return the Point giving the component's location in the
+ * screen's coordinate space.
+ *
+ * @throws IllegalComponentStateException if the component is
+ * not shown on the screen.
+ */
+ public Point getLocationOnScreen() throws IllegalComponentStateException {
+ toolkit.lockAWT();
+ try {
+ Point p = new Point();
+ if (isShowing()) {
+ //???AWT
+ /*
+ Component comp;
+ for (comp = this; comp != null && !(comp instanceof Window); comp = comp
+ .getParent()) {
+ p.translate(comp.getX(), comp.getY());
+ }
+ if (comp instanceof Window) {
+ p.translate(comp.getX(), comp.getY());
+ }
+ */
+ return p;
+ }
+ // awt.151=component must be showing on the screen to determine its location
+ throw new IllegalComponentStateException(Messages.getString("awt.151")); //$NON-NLS-1$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the peer. This method should not be called directly by
+ * user applications.
+ *
+ * @return the ComponentPeer.
+ *
+ * @deprecated Replaced by isDisplayable().
+ */
+ @Deprecated
+ public ComponentPeer getPeer() {
+ toolkit.lockAWT();
+ try {
+ if (behaviour.isDisplayable()) {
+ return peer;
+ }
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets an array of the property change listeners registered to
+ * this Component.
+ *
+ * @return an array of the PropertyChangeListeners registered to
+ * this Component.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners() {
+ return getPropertyChangeSupport().getPropertyChangeListeners();
+ }
+
+ /**
+ * Gets an array of PropertyChangeListener objects registered
+ * to this Component for the specified property.
+ *
+ * @param propertyName the property name.
+ *
+ * @return an array of PropertyChangeListener objects registered
+ * to this Component for the specified property.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
+ return getPropertyChangeSupport().getPropertyChangeListeners(propertyName);
+ }
+
+ /**
+ * Gets the width of the Component.
+ *
+ * @return the width of the Component.
+ */
+ public int getWidth() {
+ toolkit.lockAWT();
+ try {
+ return w;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the x coordinate of the component's top-left corner.
+ *
+ * @return the x coordinate of the component's top-left corner.
+ */
+ public int getX() {
+ toolkit.lockAWT();
+ try {
+ return x;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the y coordinate of the component's top-left corner.
+ *
+ * @return the y coordinate of the component's top-left corner.
+ */
+ public int getY() {
+ toolkit.lockAWT();
+ try {
+ return y;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Got the focus.
+ *
+ * @param evt the Event.
+ * @param what the Object.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processFocusEvent(FocusEvent) method.
+ */
+ @Deprecated
+ public boolean gotFocus(Event evt, Object what) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Handles event.
+ *
+ * @param evt the Event.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processEvent(AWTEvent) method.
+ */
+ @Deprecated
+ public boolean handleEvent(Event evt) {
+ switch (evt.id) {
+ case Event.ACTION_EVENT:
+ return action(evt, evt.arg);
+ case Event.GOT_FOCUS:
+ return gotFocus(evt, null);
+ case Event.LOST_FOCUS:
+ return lostFocus(evt, null);
+ case Event.MOUSE_DOWN:
+ return mouseDown(evt, evt.x, evt.y);
+ case Event.MOUSE_DRAG:
+ return mouseDrag(evt, evt.x, evt.y);
+ case Event.MOUSE_ENTER:
+ return mouseEnter(evt, evt.x, evt.y);
+ case Event.MOUSE_EXIT:
+ return mouseExit(evt, evt.x, evt.y);
+ case Event.MOUSE_MOVE:
+ return mouseMove(evt, evt.x, evt.y);
+ case Event.MOUSE_UP:
+ return mouseUp(evt, evt.x, evt.y);
+ case Event.KEY_ACTION:
+ case Event.KEY_PRESS:
+ return keyDown(evt, evt.key);
+ case Event.KEY_ACTION_RELEASE:
+ case Event.KEY_RELEASE:
+ return keyUp(evt, evt.key);
+ }
+ return false;// event not handled
+ }
+
+ /**
+ * Checks whether the Component is the focus owner or not.
+ *
+ * @return true, if the Component is the focus owner, false otherwise.
+ */
+ public boolean hasFocus() {
+ toolkit.lockAWT();
+ try {
+ //???AWT: return isFocusOwner();
+ return false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Hides the Component.
+ *
+ * @deprecated Replaced by setVisible(boolean) method.
+ */
+ @Deprecated
+ public void hide() {
+ toolkit.lockAWT();
+ try {
+ if (!visible) {
+ return;
+ }
+ prepare4HierarchyChange();
+ visible = false;
+ moveFocusOnHide();
+ behaviour.setVisible(false);
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN));
+ //???AWT: finishHierarchyChange(this, parent, 0);
+ notifyInputMethod(null);
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the point with the specified coordinates
+ * belongs to the Commponent.
+ *
+ * @param x the x coordinate of the Point.
+ * @param y the y coordinate of the Point.
+ *
+ * @return true, if the point with the specified coordinates
+ * belongs to the Commponent, false otherwise.
+ *
+ * @deprecated Replaced by contains(int, int) method.
+ */
+ @Deprecated
+ public boolean inside(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Invalidates the component, this component and all parents
+ * above it are marked as needing to be laid out.
+ */
+ public void invalidate() {
+ toolkit.lockAWT();
+ try {
+ valid = false;
+ resetDefaultSize();
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the background color is set to this Component.
+ *
+ * @return true, if the background color is set to this Component,
+ * false otherwise.
+ */
+ public boolean isBackgroundSet() {
+ toolkit.lockAWT();
+ try {
+ return backColor != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not a cursor is set for the Component.
+ *
+ * @return true, if a cursor is set for the Component,
+ * false otherwise.
+ */
+ public boolean isCursorSet() {
+ toolkit.lockAWT();
+ try {
+ return cursor != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this Component is displayable.
+ *
+ * @return true, if this Component is displayable, false otherwise.
+ */
+ public boolean isDisplayable() {
+ toolkit.lockAWT();
+ try {
+ return behaviour.isDisplayable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this component is painted to an buffer
+ * which is copied to the screen later.
+ *
+ * @return true, if this component is painted to an buffer
+ * which is copied to the screen later, false otherwise.
+ */
+ public boolean isDoubleBuffered() {
+ toolkit.lockAWT();
+ try {
+ // false by default
+ return false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this Component is enabled.
+ *
+ * @return true, if this Component is enabled, false otherwise.
+ */
+ public boolean isEnabled() {
+ toolkit.lockAWT();
+ try {
+ return enabled;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * "Recursive" isEnabled().
+ *
+ * @return true if not only component itself is enabled but its heavyweight
+ * parent is also "indirectly" enabled
+ */
+ boolean isIndirectlyEnabled() {
+ Component comp = this;
+ while (comp != null) {
+ if (!comp.isLightweight() && !comp.isEnabled()) {
+ return false;
+ }
+ //???AWT: comp = comp.getRealParent();
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the component is key enabled.
+ *
+ * @return true, if the component is enabled and indirectly enabled
+ */
+ boolean isKeyEnabled() {
+ if (!isEnabled()) {
+ return false;
+ }
+ return isIndirectlyEnabled();
+ }
+
+ /**
+ * Gets only parent of a child component, but not owner of a window.
+ *
+ * @return parent of child component, null if component is a top-level
+ * (Window instance)
+ */
+ //???AWT
+ /*
+ Container getRealParent() {
+ return (!(this instanceof Window) ? getParent() : null);
+ }
+
+ public boolean isFocusCycleRoot(Container container) {
+ toolkit.lockAWT();
+ try {
+ return getFocusCycleRootAncestor() == container;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isFocusOwner() {
+ toolkit.lockAWT();
+ try {
+ return KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == this;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Checks whether or not this Component can be focusable.
+ *
+ * @return true, if this Component can be focusable, false otherwise.
+ *
+ * @deprecated Replaced by isFocusable().
+ */
+ @Deprecated
+ public boolean isFocusTraversable() {
+ toolkit.lockAWT();
+ try {
+ overridenIsFocusable = false;
+ return focusable; // a Component must either be both focusable and
+ // focus traversable, or neither
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if this Component can be focusable or not.
+ *
+ * @return true, if this Component can be focusable, false otherwise.
+ */
+ public boolean isFocusable() {
+ toolkit.lockAWT();
+ try {
+ return isFocusTraversable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if the Font is set for this Component or not.
+ *
+ * @return true, if the Font is set, false otherwise.
+ */
+ public boolean isFontSet() {
+ toolkit.lockAWT();
+ try {
+ return font != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if foreground color is set for the Component or not.
+ *
+ * @return true, if is foreground color is set for the Component,
+ * false otherwise.
+ */
+ public boolean isForegroundSet() {
+ toolkit.lockAWT();
+ try {
+ return foreColor != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns true if this component has a lightweight peer.
+ *
+ * @return true, if this component has a lightweight peer,
+ * false if it has a native peer or no peer.
+ */
+ public boolean isLightweight() {
+ toolkit.lockAWT();
+ try {
+ return behaviour.isLightweight();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+
+ /**
+ * Checks whether or not this Component is shown.
+ *
+ * @return true, if this Component is shown, false otherwise.
+ */
+ public boolean isShowing() {
+ //???AWT
+ /*
+ toolkit.lockAWT();
+ try {
+ return (isVisible() && isDisplayable() && (parent != null) && parent.isShowing());
+ } finally {
+ toolkit.unlockAWT();
+ }
+ */
+ return false;
+ }
+
+ /**
+ * Checks whether or not this Component is visible.
+ *
+ * @return true, if the Component is visible, false otherwise.
+ */
+ public boolean isVisible() {
+ toolkit.lockAWT();
+ try {
+ return visible;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by processKeyEvent(KeyEvent) method.
+ *
+ * @param evt the Event.
+ * @param key the key code.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by replaced by processKeyEvent(KeyEvent) method.
+ */
+ @Deprecated
+ public boolean keyDown(Event evt, int key) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by processKeyEvent(KeyEvent) method.
+ *
+ * @param evt the Event.
+ * @param key the key code.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processKeyEvent(KeyEvent) method.
+ */
+ @Deprecated
+ public boolean keyUp(Event evt, int key) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: Replaced by doLayout() method.
+ *
+ * @deprecated Replaced by doLayout() method.
+ */
+ @Deprecated
+ public void layout() {
+ toolkit.lockAWT();
+ try {
+ // Implemented in Container
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getComponentAt(int, int) method.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return The component.
+ *
+ * @deprecated Replaced by getComponentAt(int, int) method.
+ */
+ @Deprecated
+ public Component locate(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ if (contains(x, y)) {
+ return this;
+ }
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by processFocusEvent(FocusEvent).
+ *
+ * @param evt the Event.
+ * @param what the Object.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processFocusEvent(FocusEvent).
+ */
+ @Deprecated
+ public boolean lostFocus(Event evt, Object what) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the MouseEvent.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseDown(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by getMinimumSize() method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by getMinimumSize() method.
+ */
+ @Deprecated
+ public boolean mouseDrag(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseEnter(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseExit(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @return true, if successful.
+ */
+ @Deprecated
+ public boolean mouseMove(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseUp(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by setLocation(int, int) method.
+ *
+ * @param x the x coordinates.
+ * @param y the y coordinates.
+ *
+ * @deprecated Replaced by setLocation(int, int) method.
+ */
+ @Deprecated
+ public void move(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ boundsMaskParam = NativeWindow.BOUNDS_NOSIZE;
+ setBounds(x, y, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ @Deprecated
+ public void nextFocus() {
+ toolkit.lockAWT();
+ try {
+ transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Returns a string representation of the component's state.
+ *
+ * @return the string representation of the component's state.
+ */
+ protected String paramString() {
+ /*
+ * The format is based on 1.5 release behavior which can be revealed by
+ * the following code:
+ *
+ * Component c = new Component(){}; c.setVisible(false);
+ * System.out.println(c);
+ */
+ toolkit.lockAWT();
+ try {
+ return getName() + "," + getX() + "," + getY() + "," + getWidth() + "x" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ + getHeight() + (!isVisible() ? ",hidden" : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public boolean postEvent(Event evt) {
+ boolean handled = handleEvent(evt);
+ if (handled) {
+ return true;
+ }
+ //???AWT
+ /*
+
+ // propagate non-handled events up to parent
+ Component par = parent;
+ // try to call postEvent only on components which
+ // override any of deprecated method handlers
+ // while (par != null && !par.deprecatedEventHandler) {
+ // par = par.parent;
+ // }
+ // translate event coordinates before posting it to parent
+ if (par != null) {
+ evt.translate(x, y);
+ par.postEvent(evt);
+ }
+
+ */
+ return false;
+ }
+
+ /**
+ * Prepares an image for rendering on the Component.
+ *
+ * @param image the Image to be prepared.
+ * @param observer the ImageObserver object to be notified as soon as
+ * the image is prepared.
+ *
+ * @return true if the image has been fully prepared,
+ * false otherwise.
+ */
+ public boolean prepareImage(Image image, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.prepareImage(image, -1, -1, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prepares an image for rendering on the Component with the
+ * specified width, height, and ImageObserver.
+ *
+ * @param image the Image to be prepared.
+ * @param width the width of scaled image.
+ * @param height the height of scaled height.
+ * @param observer the ImageObserver object to be notified as soon as
+ * the image is prepared.
+ *
+ * @return true if the image is been fully prepared,
+ * false otherwise.
+ */
+ public boolean prepareImage(Image image, int width, int height, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.prepareImage(image, width, height, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Makes this Component undisplayable.
+ */
+ public void removeNotify() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if (dropTarget != null) {
+ dropTarget.removeNotify(peer);
+ }
+ */
+ prepare4HierarchyChange();
+ ///???AWT: moveFocus();
+ behaviour.removeNotify();
+ //???AWT: finishHierarchyChange(this, parent, 0);
+ removeNotifyInputContext();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Calls InputContext.removeNotify
+ */
+ private void removeNotifyInputContext() {
+ if (!inputMethodsEnabled) {
+ return;
+ }
+ InputContext ic = getInputContext();
+ if (ic != null) {
+ //???AWT: ic.removeNotify(this);
+ }
+ }
+
+ /**
+ * This method is called when some property of a component changes, making
+ * it unfocusable, e. g. hide(), removeNotify(), setEnabled(false),
+ * setFocusable(false) is called, and therefore automatic forward focus
+ * traversal is necessary
+ */
+ //???AWT
+ /*
+ void moveFocus() {
+ // don't use transferFocus(), but query focus traversal policy directly
+ // and if it returns null, transfer focus up cycle
+ // and find next focusable component there
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Container root = kfm.getCurrentFocusCycleRoot();
+ Component nextComp = this;
+ boolean success = !isFocusOwner();
+ while (!success) {
+ if (root != nextComp.getFocusCycleRootAncestor()) {
+ // component was probably removed from container
+ // so focus will be lost in some time
+ return;
+ }
+ nextComp = root.getFocusTraversalPolicy().getComponentAfter(root, nextComp);
+ if (nextComp == this) {
+ nextComp = null; // avoid looping
+ }
+ if (nextComp != null) {
+ success = nextComp.requestFocusInWindow();
+ } else {
+ nextComp = root;
+ root = root.getFocusCycleRootAncestor();
+ // if no acceptable component is found at all - clear global
+ // focus owner
+ if (root == null) {
+ if (nextComp instanceof Window) {
+ Window wnd = (Window) nextComp;
+ wnd.setFocusOwner(null);
+ wnd.setRequestedFocus(null);
+ }
+ kfm.clearGlobalFocusOwner();
+ return;
+ }
+ }
+ }
+ }
+ */
+
+ /**
+ * For Container there's a difference between moving focus when being made
+ * invisible or made unfocusable in some other way, because when container
+ * is made invisible, component still remains visible, i. e. its hide() or
+ * setVisible() is not called.
+ */
+ void moveFocusOnHide() {
+ //???AWT: moveFocus();
+ }
+
+ /**
+ * Removes the property change listener registered for this component.
+ *
+ * @param listener the PropertyChangeListener.
+ */
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ getPropertyChangeSupport().removePropertyChangeListener(listener);
+ }
+
+ /**
+ * Removes the property change listener registered fot this component
+ * for the specified propertyy.
+ *
+ * @param propertyName the property name.
+ * @param listener the PropertyChangeListener.
+ */
+ public void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ getPropertyChangeSupport().removePropertyChangeListener(propertyName, listener);
+ }
+
+
+ /**
+ * Repaints the specified rectangle of this component within
+ * tm milliseconds.
+ *
+ * @param tm the time in milliseconds before updating.
+ * @param x the x coordinate of Rectangle.
+ * @param y the y coordinate of Rectangle.
+ * @param width the width of Rectangle.
+ * @param height the height of Rectangle.
+ */
+ public void repaint(long tm, int x, int y, int width, int height) {
+ //???AWT
+ /*
+ toolkit.lockAWT();
+ try {
+ if (width <= 0 || height <= 0 || (redrawManager == null) || !isShowing()) {
+ return;
+ }
+ if (behaviour instanceof LWBehavior) {
+ if (parent == null || !parent.visible || !parent.behaviour.isDisplayable()) {
+ return;
+ }
+ if (repaintRegion == null) {
+ repaintRegion = new MultiRectArea(new Rectangle(x, y, width, height));
+ }
+ repaintRegion.intersect(new Rectangle(0, 0, this.w, this.h));
+ repaintRegion.translate(this.x, this.y);
+ parent.repaintRegion = repaintRegion;
+ repaintRegion = null;
+ parent.repaint(tm, x + this.x, y + this.y, width, height);
+ } else {
+ if (repaintRegion != null) {
+ redrawManager.addUpdateRegion(this, repaintRegion);
+ repaintRegion = null;
+ } else {
+ redrawManager.addUpdateRegion(this, new Rectangle(x, y, width, height));
+ }
+ toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ */
+ }
+
+ /**
+ * Post event.
+ *
+ * @param e the e
+ */
+ void postEvent(AWTEvent e) {
+ getToolkit().getSystemEventQueueImpl().postEvent(e);
+ }
+
+ /**
+ * Repaints the specified Rectangle of this Component.
+ *
+ * @param x the x coordinate of Rectangle.
+ * @param y the y coordinate of Rectangle.
+ * @param width the width of Rectangle.
+ * @param height the height of Rectangle.
+ */
+ public void repaint(int x, int y, int width, int height) {
+ toolkit.lockAWT();
+ try {
+ repaint(0, x, y, width, height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Repaints this component.
+ */
+ public void repaint() {
+ toolkit.lockAWT();
+ try {
+ if (w > 0 && h > 0) {
+ repaint(0, 0, 0, w, h);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Repaints the component within tm milliseconds.
+ *
+ * @param tm the time in milliseconds before updating.
+ */
+ public void repaint(long tm) {
+ toolkit.lockAWT();
+ try {
+ repaint(tm, 0, 0, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Requests that this Component get the input focus temporarily.
+ * This component must be displayable, visible, and focusable.
+ *
+ * @param temporary this parameter is true if the focus change
+ * is temporary, when the window loses the focus.
+ *
+ * @return true if the focus change request is succeeded,
+ * false otherwise.
+ */
+ protected boolean requestFocus(boolean temporary) {
+ toolkit.lockAWT();
+ try {
+ //???AWT: return requestFocusImpl(temporary, true, false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ //???AWT
+ return false;
+ }
+
+ /**
+ * Requests that this Component get the input focus.
+ * This component must be displayable, visible, and focusable.
+ */
+ public void requestFocus() {
+ toolkit.lockAWT();
+ try {
+ requestFocus(false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ protected boolean requestFocusInWindow(boolean temporary) {
+ toolkit.lockAWT();
+ try {
+ Window wnd = getWindowAncestor();
+ if ((wnd == null) || !wnd.isFocused()) {
+ return false;
+ }
+ return requestFocusImpl(temporary, false, false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ boolean requestFocusImpl(boolean temporary, boolean crossWindow, boolean rejectionRecovery) {
+ if (!rejectionRecovery && isFocusOwner()) {
+ return true;
+ }
+ Window wnd = getWindowAncestor();
+ Container par = getRealParent();
+ if ((par != null) && par.isRemoved) {
+ return false;
+ }
+ if (!isShowing() || !isFocusable() || !wnd.isFocusableWindow()) {
+ return false;
+ }
+ return KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this,
+ temporary, crossWindow, true);
+ }
+
+ public boolean requestFocusInWindow() {
+ toolkit.lockAWT();
+ try {
+ return requestFocusInWindow(false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Deprecated: replaced by setBounds(int, int, int, int) method.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param w the width.
+ * @param h the height.
+ *
+ * @deprecated Replaced by setBounds(int, int, int, int) method.
+ */
+ @Deprecated
+ public void reshape(int x, int y, int w, int h) {
+ toolkit.lockAWT();
+ try {
+ setBounds(x, y, w, h, boundsMaskParam, true);
+ boundsMaskParam = 0;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets rectangle for this Component to be the rectangle with the specified
+ * x,y coordinates of the top-left corner and the width and height.
+ *
+ * @param x the x coordinate of the rectangle's top-left corner.
+ * @param y the y coordinate of the rectangle's top-left corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ */
+ public void setBounds(int x, int y, int w, int h) {
+ toolkit.lockAWT();
+ try {
+ reshape(x, y, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets rectangle for this Component to be the rectangle with the specified
+ * x,y coordinates of the top-left corner and the width and height
+ * and posts the appropriate events.
+ *
+ * @param x the x coordinate of the rectangle's top-left corner.
+ * @param y the y coordinate of the rectangle's top-left corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ * @param bMask the bitmask of bounds options
+ * @param updateBehavior the whether to update the behavoir's bounds as well
+ */
+ void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) {
+ int oldX = this.x;
+ int oldY = this.y;
+ int oldW = this.w;
+ int oldH = this.h;
+ setBoundsFields(x, y, w, h, bMask);
+ // Moved
+ if ((oldX != this.x) || (oldY != this.y)) {
+ //???AWT: invalidateRealParent();
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED));
+ spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED);
+ }
+ // Resized
+ if ((oldW != this.w) || (oldH != this.h)) {
+ invalidate();
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED));
+ spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_RESIZED);
+ }
+ if (updateBehavior) {
+ behaviour.setBounds(this.x, this.y, this.w, this.h, bMask);
+ }
+ notifyInputMethod(new Rectangle(x, y, w, h));
+ }
+
+ /**
+ * Calls InputContextImpl.notifyClientWindowChanged.
+ *
+ * @param bounds the bounds
+ */
+ void notifyInputMethod(Rectangle bounds) {
+ // only Window actually notifies IM of bounds change
+ }
+
+ /**
+ * Sets the bounds fields.
+ *
+ * @param x the x
+ * @param y the y
+ * @param w the w
+ * @param h the h
+ * @param bMask the b mask
+ */
+ private void setBoundsFields(int x, int y, int w, int h, int bMask) {
+ if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) {
+ this.w = w;
+ this.h = h;
+ }
+ if ((bMask & NativeWindow.BOUNDS_NOMOVE) == 0) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ /**
+ * Gets the native insets.
+ *
+ * @return the native insets
+ */
+ Insets getNativeInsets() {
+ return new Insets(0, 0, 0, 0);
+ }
+
+ /**
+ * Gets the insets.
+ *
+ * @return the insets
+ */
+ Insets getInsets() {
+ return new Insets(0, 0, 0, 0);
+ }
+
+ /**
+ * Checks if is mouse exited expected.
+ *
+ * @return true, if is mouse exited expected
+ */
+ boolean isMouseExitedExpected() {
+ return mouseExitedExpected;
+ }
+
+ /**
+ * Sets the mouse exited expected.
+ *
+ * @param expected the new mouse exited expected
+ */
+ void setMouseExitedExpected(boolean expected) {
+ mouseExitedExpected = expected;
+ }
+
+ /**
+ * Sets the new bounding rectangle for this Component.
+ *
+ * @param r the new bounding rectangle.
+ */
+ public void setBounds(Rectangle r) {
+ toolkit.lockAWT();
+ try {
+ setBounds(r.x, r.y, r.width, r.height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the component orientation which affects the component's
+ * elements and text within this component.
+ *
+ * @param o the ComponentOrientation object.
+ */
+ public void setComponentOrientation(ComponentOrientation o) {
+ ComponentOrientation oldOrientation;
+ toolkit.lockAWT();
+ try {
+ oldOrientation = orientation;
+ orientation = o;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("componentOrientation", oldOrientation, orientation); //$NON-NLS-1$
+ invalidate();
+ }
+
+ /**
+ * Sets the specified cursor for this Component.
+ *
+ * @param cursor the new Cursor.
+ */
+ public void setCursor(Cursor cursor) {
+ toolkit.lockAWT();
+ try {
+ this.cursor = cursor;
+ setCursor();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Set current cursor shape to Component's Cursor.
+ */
+ void setCursor() {
+ if (isDisplayable() && isShowing()) {
+ Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize());
+ Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos();
+ //???AWT
+ /*
+ if (absRect.contains(absPointerPos)) {
+ // set Cursor only on top-level Windows(on X11)
+ Window topLevelWnd = getWindowAncestor();
+ if (topLevelWnd != null) {
+ Point pointerPos = MouseDispatcher.convertPoint(null, absPointerPos,
+ topLevelWnd);
+ Component compUnderCursor = topLevelWnd.findComponentAt(pointerPos);
+ // if (compUnderCursor == this ||
+ // compUnderCursor.getCursorAncestor() == this) {
+ NativeWindow wnd = topLevelWnd.getNativeWindow();
+ if (compUnderCursor != null && wnd != null) {
+ compUnderCursor.getRealCursor().getNativeCursor()
+ .setCursor(wnd.getId());
+ }
+ // }
+ }
+ }
+ */
+ }
+ }
+
+ /**
+ * Gets the ancestor Cursor if Component is disabled (directly or via an
+ * ancestor) even if Cursor is explicitly set.
+ *
+ * @param value the value
+ *
+ * @return actual Cursor to be displayed
+ */
+ //???AWT
+ /*
+ Cursor getRealCursor() {
+ Component cursorAncestor = getCursorAncestor();
+ return cursorAncestor != null ? cursorAncestor.getCursor() : Cursor.getDefaultCursor();
+ }
+ */
+
+ /**
+ * Gets the ancestor(or component itself) whose cursor is set when pointer
+ * is inside component
+ *
+ * @return actual Cursor to be displayed
+ */
+ //???AWT
+ /*
+ Component getCursorAncestor() {
+ Component comp;
+ for (comp = this; comp != null; comp = comp.getParent()) {
+ if (comp instanceof Window || comp.isCursorSet() && comp.isKeyEnabled()) {
+ return comp;
+ }
+ }
+ return null;
+ }
+
+ public void setDropTarget(DropTarget dt) {
+ toolkit.lockAWT();
+ try {
+ if (dropTarget == dt) {
+ return;
+ }
+ DropTarget oldDropTarget = dropTarget;
+ dropTarget = dt;
+ if (oldDropTarget != null) {
+ if (behaviour.isDisplayable()) {
+ oldDropTarget.removeNotify(peer);
+ }
+ oldDropTarget.setComponent(null);
+ }
+ if (dt != null) {
+ dt.setComponent(this);
+ if (behaviour.isDisplayable()) {
+ dt.addNotify(peer);
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Sets this component to the "enabled" or "disabled" state depending
+ * on the specified boolean parameter.
+ *
+ * @param value true if this component should be enabled; false
+ * if this component should be disabled.
+ */
+ public void setEnabled(boolean value) {
+ toolkit.lockAWT();
+ try {
+ enable(value);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the enabled impl.
+ *
+ * @param value the new enabled impl
+ */
+ void setEnabledImpl(boolean value) {
+ if (enabled != value) {
+ enabled = value;
+ setCursor();
+ if (!enabled) {
+ moveFocusOnHide();
+ }
+ behaviour.setEnabled(value);
+ }
+ }
+
+ //???AWT
+ /*
+ private void fireAccessibleStateChange(AccessibleState state, boolean value) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ AccessibleContext ac = getAccessibleContext();
+ if (ac != null) {
+ AccessibleState oldValue = null;
+ AccessibleState newValue = null;
+ if (value) {
+ newValue = state;
+ } else {
+ oldValue = state;
+ }
+ ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, oldValue,
+ newValue);
+ }
+ }
+ */
+
+ //???AWT
+ /*
+ public void setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> keystrokes) {
+ Set<? extends AWTKeyStroke> oldTraversalKeys;
+ String propName = "FocusTraversalKeys"; //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ Integer kId = new Integer(id);
+ KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId);
+ Map<Integer, Set<? extends AWTKeyStroke>> keys = new HashMap<Integer, Set<? extends AWTKeyStroke>>();
+ for (int kid : traversalIDs) {
+ Integer key = new Integer(kid);
+ keys.put(key, getFocusTraversalKeys(kid));
+ }
+ KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId, keystrokes);
+ oldTraversalKeys = traversalKeys.get(new Integer(id));
+ // put a copy of keystrokes object into map:
+ Set<? extends AWTKeyStroke> newKeys = keystrokes;
+ if (keystrokes != null) {
+ newKeys = new HashSet<AWTKeyStroke>(keystrokes);
+ }
+ traversalKeys.put(kId, newKeys);
+ String direction = ""; //$NON-NLS-1$
+ switch (id) {
+ case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
+ direction = "forward"; //$NON-NLS-1$
+ break;
+ case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+ direction = "backward"; //$NON-NLS-1$
+ break;
+ case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS:
+ direction = "upCycle"; //$NON-NLS-1$
+ break;
+ case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
+ direction = "downCycle"; //$NON-NLS-1$
+ break;
+ }
+ propName = direction + propName;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange(propName, oldTraversalKeys, keystrokes);
+ }
+ */
+
+ /**
+ * Sets the focus traversal keys state for this component.
+ *
+ * @param value true if the focus traversal keys state is enabled,
+ * false if the focus traversal keys state is disabled.
+ */
+ public void setFocusTraversalKeysEnabled(boolean value) {
+ boolean oldFocusTraversalKeysEnabled;
+ toolkit.lockAWT();
+ try {
+ oldFocusTraversalKeysEnabled = focusTraversalKeysEnabled;
+ focusTraversalKeysEnabled = value;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("focusTraversalKeysEnabled", oldFocusTraversalKeysEnabled, //$NON-NLS-1$
+ focusTraversalKeysEnabled);
+ }
+
+ //???AWT
+ /*
+ public void setFocusable(boolean focusable) {
+ boolean oldFocusable;
+ toolkit.lockAWT();
+ try {
+ calledSetFocusable = true;
+ oldFocusable = this.focusable;
+ this.focusable = focusable;
+ if (!focusable) {
+ moveFocus();
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$
+ }
+
+ public Font getFont() {
+ toolkit.lockAWT();
+ try {
+ return (font == null) && (parent != null) ? parent.getFont() : font;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Sets the font for this Component.
+ *
+ * @param f the new font of the Component.
+ */
+ public void setFont(Font f) {
+ Font oldFont;
+ toolkit.lockAWT();
+ try {
+ oldFont = font;
+ setFontImpl(f);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("font", oldFont, font); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the font impl.
+ *
+ * @param f the new font impl
+ */
+ void setFontImpl(Font f) {
+ font = f;
+ invalidate();
+ if (isShowing()) {
+ repaint();
+ }
+ }
+
+
+ /**
+ * Invalidate the component if it inherits the font from the parent. This
+ * method is overridden in Container.
+ *
+ * @return true if the component was invalidated, false otherwise
+ */
+ boolean propagateFont() {
+ if (font == null) {
+ invalidate();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the foreground color for this Component.
+ *
+ * @param c the new foreground color.
+ */
+ public void setForeground(Color c) {
+ Color oldFgColor;
+ toolkit.lockAWT();
+ try {
+ oldFgColor = foreColor;
+ foreColor = c;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("foreground", oldFgColor, foreColor); //$NON-NLS-1$
+ repaint();
+ }
+
+ /**
+ * Sets the background color for the Component.
+ *
+ * @param c the new background color for this component.
+ */
+ public void setBackground(Color c) {
+ Color oldBkColor;
+ toolkit.lockAWT();
+ try {
+ oldBkColor = backColor;
+ backColor = c;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("background", oldBkColor, backColor); //$NON-NLS-1$
+ repaint();
+ }
+
+ /**
+ * Sets the flag for whether paint messages received from the operating
+ * system should be ignored or not.
+ *
+ * @param value true if paint messages received from the operating
+ * system should be ignored, false otherwise.
+ */
+ public void setIgnoreRepaint(boolean value) {
+ toolkit.lockAWT();
+ try {
+ ignoreRepaint = value;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the locale of the component.
+ *
+ * @param locale the new Locale.
+ */
+ public void setLocale(Locale locale) {
+ Locale oldLocale;
+ toolkit.lockAWT();
+ try {
+ oldLocale = this.locale;
+ this.locale = locale;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("locale", oldLocale, locale); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the location of the Component to the specified point.
+ *
+ * @param p the new location of the Component
+ */
+ public void setLocation(Point p) {
+ toolkit.lockAWT();
+ try {
+ setLocation(p.x, p.y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the location of the Component to the specified x, y coordinates.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ */
+ public void setLocation(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ move(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the visibility state of the component.
+ *
+ * @param b true if the component is visible, false if the component
+ * is not shown.
+ */
+ public void setVisible(boolean b) {
+ // show() & hide() are not deprecated for Window,
+ // so have to call them from setVisible()
+ show(b);
+ }
+
+ /**
+ * Deprecated: replaced by setVisible(boolean) method.
+ *
+ * @deprecated Replaced by setVisible(boolean) method.
+ */
+ @Deprecated
+ public void show() {
+ toolkit.lockAWT();
+ try {
+ if (visible) {
+ return;
+ }
+ prepare4HierarchyChange();
+ mapToDisplay(true);
+ validate();
+ visible = true;
+ behaviour.setVisible(true);
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN));
+ //???AWT: finishHierarchyChange(this, parent, 0);
+ notifyInputMethod(new Rectangle(x, y, w, h));
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by setVisible(boolean) method.
+ *
+ * @param b the visibility's state.
+ *
+ * @deprecated Replaced by setVisible(boolean) method.
+ */
+ @Deprecated
+ public void show(boolean b) {
+ if (b) {
+ show();
+ } else {
+ hide();
+ }
+ }
+
+ //???AWT
+ /*
+ void transferFocus(int dir) {
+ Container root = null;
+ if (this instanceof Container) {
+ Container cont = (Container) this;
+ if (cont.isFocusCycleRoot()) {
+ root = cont.getFocusTraversalRoot();
+ }
+ }
+ if (root == null) {
+ root = getFocusCycleRootAncestor();
+ }
+ // transfer focus up cycle if root is unreachable
+ Component comp = this;
+ while ((root != null)
+ && !(root.isFocusCycleRoot() && root.isShowing() && root.isEnabled() && root
+ .isFocusable())) {
+ comp = root;
+ root = root.getFocusCycleRootAncestor();
+ }
+ if (root == null) {
+ return;
+ }
+ FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
+ Component nextComp = null;
+ switch (dir) {
+ case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
+ nextComp = policy.getComponentAfter(root, comp);
+ break;
+ case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+ nextComp = policy.getComponentBefore(root, comp);
+ break;
+ }
+ if (nextComp != null) {
+ nextComp.requestFocus(false);
+ }
+ }
+
+ public void transferFocus() {
+ toolkit.lockAWT();
+ try {
+ nextFocus();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void transferFocusBackward() {
+ toolkit.lockAWT();
+ try {
+ transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void transferFocusUpCycle() {
+ toolkit.lockAWT();
+ try {
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Container root = kfm.getCurrentFocusCycleRoot();
+
+ if(root == null) {
+ return;
+ }
+
+ boolean success = false;
+ Component nextComp = null;
+ Container newRoot = root;
+ do {
+ nextComp = newRoot instanceof Window ? newRoot.getFocusTraversalPolicy()
+ .getDefaultComponent(newRoot) : newRoot;
+ newRoot = newRoot.getFocusCycleRootAncestor();
+ if (nextComp == null) {
+ break;
+ }
+ success = nextComp.requestFocusInWindow();
+ if (newRoot == null) {
+ break;
+ }
+ kfm.setGlobalCurrentFocusCycleRoot(newRoot);
+ } while (!success);
+ if (!success && root != newRoot) {
+ kfm.setGlobalCurrentFocusCycleRoot(root);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Validates that this component has a valid layout.
+ */
+ public void validate() {
+ toolkit.lockAWT();
+ try {
+ if (!behaviour.isDisplayable()) {
+ return;
+ }
+ validateImpl();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Validate impl.
+ */
+ void validateImpl() {
+ valid = true;
+ }
+
+ /**
+ * Gets the native window.
+ *
+ * @return the native window
+ */
+ NativeWindow getNativeWindow() {
+ return behaviour.getNativeWindow();
+ }
+
+ /**
+ * Checks whether or not a maximum size is set for the Component.
+ *
+ * @return true, if the maximum size is set for the Component,
+ * false otherwise.
+ */
+ public boolean isMaximumSizeSet() {
+ toolkit.lockAWT();
+ try {
+ return maximumSize != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the minimum size is set for the component.
+ *
+ * @return true, if the minimum size is set for the component,
+ * false otherwise.
+ */
+ public boolean isMinimumSizeSet() {
+ toolkit.lockAWT();
+ try {
+ return minimumSize != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the preferred size is set for the Component.
+ *
+ * @return true, if the preferred size is set for the Component,
+ * false otherwise.
+ */
+ public boolean isPreferredSizeSet() {
+ toolkit.lockAWT();
+ try {
+ return preferredSize != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the maximum size of the Component.
+ *
+ * @return the maximum size of the Component.
+ */
+ public Dimension getMaximumSize() {
+ toolkit.lockAWT();
+ try {
+ return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(
+ Short.MAX_VALUE, Short.MAX_VALUE);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the minimum size of the Component.
+ *
+ * @return the minimum size of the Component.
+ */
+ public Dimension getMinimumSize() {
+ toolkit.lockAWT();
+ try {
+ return minimumSize();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getMinimumSize() method.
+ *
+ * @return the Dimension.
+ *
+ * @deprecated Replaced by getMinimumSize() method.
+ */
+ @Deprecated
+ public Dimension minimumSize() {
+ toolkit.lockAWT();
+ try {
+ if (isMinimumSizeSet()) {
+ return (Dimension)minimumSize.clone();
+ }
+ Dimension defSize = getDefaultMinimumSize();
+ if (defSize != null) {
+ return (Dimension)defSize.clone();
+ }
+ return isDisplayable()? new Dimension(1, 1) : new Dimension(w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the preferred size of the Component.
+ *
+ * @return the preferred size of the Component.
+ */
+ public Dimension getPreferredSize() {
+ toolkit.lockAWT();
+ try {
+ return preferredSize();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getPreferredSize() method.
+ *
+ * @return the Dimension.
+ *
+ * @deprecated Replaced by getPreferredSize() method.
+ */
+ @Deprecated
+ public Dimension preferredSize() {
+ toolkit.lockAWT();
+ try {
+ if (isPreferredSizeSet()) {
+ return new Dimension(preferredSize);
+ }
+ Dimension defSize = getDefaultPreferredSize();
+ if (defSize != null) {
+ return new Dimension(defSize);
+ }
+ return new Dimension(getMinimumSize());
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the maximum size of the Component.
+ *
+ * @param maximumSize the new maximum size of the Component.
+ */
+ public void setMaximumSize(Dimension maximumSize) {
+ Dimension oldMaximumSize;
+ toolkit.lockAWT();
+ try {
+ oldMaximumSize = this.maximumSize;
+ if (oldMaximumSize != null) {
+ oldMaximumSize = oldMaximumSize.getSize();
+ }
+ if (this.maximumSize == null) {
+ if (maximumSize != null) {
+ this.maximumSize = new Dimension(maximumSize);
+ }
+ } else {
+ if (maximumSize != null) {
+ this.maximumSize.setSize(maximumSize);
+ } else {
+ this.maximumSize = null;
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the minimum size of the Component.
+ *
+ * @param minimumSize the new minimum size of the Component.
+ */
+ public void setMinimumSize(Dimension minimumSize) {
+ Dimension oldMinimumSize;
+ toolkit.lockAWT();
+ try {
+ oldMinimumSize = this.minimumSize;
+ if (oldMinimumSize != null) {
+ oldMinimumSize = oldMinimumSize.getSize();
+ }
+ if (this.minimumSize == null) {
+ if (minimumSize != null) {
+ this.minimumSize = new Dimension(minimumSize);
+ }
+ } else {
+ if (minimumSize != null) {
+ this.minimumSize.setSize(minimumSize);
+ } else {
+ this.minimumSize = null;
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the preferred size of the Component.
+ *
+ * @param preferredSize the new preferred size of the Component.
+ */
+ public void setPreferredSize(Dimension preferredSize) {
+ Dimension oldPreferredSize;
+ toolkit.lockAWT();
+ try {
+ oldPreferredSize = this.preferredSize;
+ if (oldPreferredSize != null) {
+ oldPreferredSize = oldPreferredSize.getSize();
+ }
+ if (this.preferredSize == null) {
+ if (preferredSize != null) {
+ this.preferredSize = new Dimension(preferredSize);
+ }
+ } else {
+ if (preferredSize != null) {
+ this.preferredSize.setSize(preferredSize);
+ } else {
+ this.preferredSize = null;
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ RedrawManager getRedrawManager() {
+ if (parent == null) {
+ return null;
+ }
+ return parent.getRedrawManager();
+ }
+ */
+
+ /**
+ * Checks if is focusability explicitly set.
+ *
+ * @return true if component has a focusable peer
+ */
+ //???AWT
+ /*
+ boolean isPeerFocusable() {
+ // The recommendations for Windows and Unix are that
+ // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows,
+ // and lightweight Components have non-focusable peers,
+ // and all other Components have focusable peers.
+ if (this instanceof Canvas || this instanceof Label || this instanceof Panel
+ || this instanceof Scrollbar || this instanceof ScrollPane
+ || this instanceof Window || isLightweight()) {
+ return false;
+ }
+ return true;
+ }
+ */
+
+ /**
+ * @return true if focusability was explicitly set via a call to
+ * setFocusable() or via overriding isFocusable() or
+ * isFocusTraversable()
+ */
+ boolean isFocusabilityExplicitlySet() {
+ return calledSetFocusable || overridenIsFocusable;
+ }
+
+ /**
+ * Paints the component and all of its subcomponents.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void paintAll(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ paint(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Updates this Component.
+ *
+ * @param g the Graphics to be used for updating.
+ */
+ public void update(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ if (!isLightweight() && !isPrepainter()) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, w, h);
+ g.setColor(getForeground());
+ }
+ paint(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Paints this component.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void paint(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ // Just to nothing
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prepares the component to be painted.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ void prepaint(Graphics g) {
+ // Just to nothing. For overriding.
+ }
+
+ /**
+ * Checks if is prepainter.
+ *
+ * @return true, if is prepainter
+ */
+ boolean isPrepainter() {
+ return false;
+ }
+
+ /**
+ * Prepare4 hierarchy change.
+ */
+ void prepare4HierarchyChange() {
+ if (hierarchyChangingCounter++ == 0) {
+ wasShowing = isShowing();
+ wasDisplayable = isDisplayable();
+ prepareChildren4HierarchyChange();
+ }
+ }
+
+ /**
+ * Prepare children4 hierarchy change.
+ */
+ void prepareChildren4HierarchyChange() {
+ // To be inherited by Container
+ }
+
+ //???AWT
+ /*
+ void finishHierarchyChange(Component changed, Container changedParent, int ancestorFlags) {
+ if (--hierarchyChangingCounter == 0) {
+ int changeFlags = ancestorFlags;
+ if (wasShowing != isShowing()) {
+ changeFlags |= HierarchyEvent.SHOWING_CHANGED;
+ }
+ if (wasDisplayable != isDisplayable()) {
+ changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED;
+ }
+ if (changeFlags > 0) {
+ postEvent(new HierarchyEvent(this, HierarchyEvent.HIERARCHY_CHANGED, changed,
+ changedParent, changeFlags));
+ }
+ finishChildrenHierarchyChange(changed, changedParent, ancestorFlags);
+ }
+ }
+
+
+ void finishChildrenHierarchyChange(Component changed, Container changedParent,
+ int ancestorFlags) {
+ // To be inherited by Container
+ }
+
+ void postHierarchyBoundsEvents(Component changed, int id) {
+ postEvent(new HierarchyEvent(this, id, changed, null, 0));
+ }
+ */
+
+ /**
+ * Spread hierarchy bounds events.
+ *
+ * @param changed the changed
+ * @param id the id
+ */
+ void spreadHierarchyBoundsEvents(Component changed, int id) {
+ // To be inherited by Container
+ }
+
+ /**
+ * Dispatches an event to this component.
+ *
+ * @param e the Event.
+ */
+ public final void dispatchEvent(AWTEvent e) {
+ //???AWT
+ /*
+ if (e.isConsumed()) {
+ return;
+ }
+ if (e instanceof PaintEvent) {
+ toolkit.dispatchAWTEvent(e);
+ processPaintEvent((PaintEvent) e);
+ return;
+ }
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ if (!e.dispatchedByKFM && kfm.dispatchEvent(e)) {
+ return;
+ }
+ if (e instanceof KeyEvent) {
+ KeyEvent ke = (KeyEvent) e;
+ // consumes KeyEvent which represents a focus traversal key
+ if (getFocusTraversalKeysEnabled()) {
+ kfm.processKeyEvent(this, ke);
+ if (ke.isConsumed()) {
+ return;
+ }
+ }
+ }
+ if (inputMethodsEnabled && dispatchToIM && e.isPosted && dispatchEventToIM(e)) {
+ return;
+ }
+ if (e.getID() == WindowEvent.WINDOW_ICONIFIED) {
+ notifyInputMethod(null);
+ }
+ AWTEvent.EventDescriptor descriptor = toolkit.eventTypeLookup.getEventDescriptor(e);
+ toolkit.dispatchAWTEvent(e);
+ if (descriptor != null) {
+ if (isEventEnabled(descriptor.eventMask)
+ || (getListeners(descriptor.listenerType).length > 0)) {
+ processEvent(e);
+ }
+ // input events can be consumed by user listeners:
+ if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) != 0)) {
+ postprocessEvent(e, descriptor.eventMask);
+ }
+ }
+ postDeprecatedEvent(e);
+ */
+ }
+
+ /**
+ * Post deprecated event.
+ *
+ * @param e the e
+ */
+ private void postDeprecatedEvent(AWTEvent e) {
+ if (deprecatedEventHandler) {
+ Event evt = e.getEvent();
+ if (evt != null) {
+ postEvent(evt);
+ }
+ }
+ }
+
+ /**
+ * Postprocess event.
+ *
+ * @param e the e
+ * @param eventMask the event mask
+ */
+ void postprocessEvent(AWTEvent e, long eventMask) {
+ toolkit.lockAWT();
+ try {
+ // call system listeners under AWT lock
+ if (eventMask == AWTEvent.FOCUS_EVENT_MASK) {
+ preprocessFocusEvent((FocusEvent) e);
+ } else if (eventMask == AWTEvent.KEY_EVENT_MASK) {
+ preprocessKeyEvent((KeyEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) {
+ preprocessMouseEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) {
+ preprocessMouseMotionEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) {
+ preprocessComponentEvent((ComponentEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) {
+ preprocessMouseWheelEvent((MouseWheelEvent) e);
+ } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) {
+ preprocessInputMethodEvent((InputMethodEvent) e);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Preprocess input method event.
+ *
+ * @param e the e
+ */
+ private void preprocessInputMethodEvent(InputMethodEvent e) {
+ processInputMethodEventImpl(e, inputMethodListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess mouse wheel event.
+ *
+ * @param e the e
+ */
+ private void preprocessMouseWheelEvent(MouseWheelEvent e) {
+ processMouseWheelEventImpl(e, mouseWheelListeners.getSystemListeners());
+ }
+
+ /**
+ * Process mouse wheel event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processMouseWheelEventImpl(MouseWheelEvent e, Collection<MouseWheelListener> c) {
+ for (MouseWheelListener listener : c) {
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_WHEEL:
+ listener.mouseWheelMoved(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Preprocess component event.
+ *
+ * @param e the e
+ */
+ private void preprocessComponentEvent(ComponentEvent e) {
+ processComponentEventImpl(e, componentListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess mouse motion event.
+ *
+ * @param e the e
+ */
+ void preprocessMouseMotionEvent(MouseEvent e) {
+ processMouseMotionEventImpl(e, mouseMotionListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess mouse event.
+ *
+ * @param e the e
+ */
+ void preprocessMouseEvent(MouseEvent e) {
+ processMouseEventImpl(e, mouseListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess key event.
+ *
+ * @param e the e
+ */
+ void preprocessKeyEvent(KeyEvent e) {
+ processKeyEventImpl(e, keyListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess focus event.
+ *
+ * @param e the e
+ */
+ void preprocessFocusEvent(FocusEvent e) {
+ processFocusEventImpl(e, focusListeners.getSystemListeners());
+ }
+
+ /**
+ * Processes AWTEvent occurred on this component.
+ *
+ * @param e the AWTEvent.
+ */
+ protected void processEvent(AWTEvent e) {
+ long eventMask = toolkit.eventTypeLookup.getEventMask(e);
+ if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) {
+ processComponentEvent((ComponentEvent) e);
+ } else if (eventMask == AWTEvent.FOCUS_EVENT_MASK) {
+ processFocusEvent((FocusEvent) e);
+ } else if (eventMask == AWTEvent.KEY_EVENT_MASK) {
+ processKeyEvent((KeyEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) {
+ processMouseEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) {
+ processMouseWheelEvent((MouseWheelEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) {
+ processMouseMotionEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.HIERARCHY_EVENT_MASK) {
+ processHierarchyEvent((HierarchyEvent) e);
+ } else if (eventMask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
+ processHierarchyBoundsEvent((HierarchyEvent) e);
+ } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) {
+ processInputMethodEvent((InputMethodEvent) e);
+ }
+ }
+
+ /**
+ * Gets an array of all listener's objects based on the specified
+ * listener type and registered to this Component.
+ *
+ * @param listenerType the listener type.
+ *
+ * @return an array of all listener's objects based on the specified
+ * listener type and registered to this Component.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
+ if (ComponentListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getComponentListeners();
+ } else if (FocusListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getFocusListeners();
+ } else if (HierarchyBoundsListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getHierarchyBoundsListeners();
+ } else if (HierarchyListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getHierarchyListeners();
+ } else if (InputMethodListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getInputMethodListeners();
+ } else if (KeyListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getKeyListeners();
+ } else if (MouseWheelListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getMouseWheelListeners();
+ } else if (MouseMotionListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getMouseMotionListeners();
+ } else if (MouseListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getMouseListeners();
+ } else if (PropertyChangeListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getPropertyChangeListeners();
+ }
+ return (T[]) Array.newInstance(listenerType, 0);
+ }
+
+ /**
+ * Process paint event.
+ *
+ * @param event the event
+ */
+ private void processPaintEvent(PaintEvent event) {
+ if (redrawManager == null) {
+ return;
+ }
+ Rectangle clipRect = event.getUpdateRect();
+ if ((clipRect.width <= 0) || (clipRect.height <= 0)) {
+ return;
+ }
+ Graphics g = getGraphics();
+ if (g == null) {
+ return;
+ }
+ initGraphics(g, event);
+ if (!getIgnoreRepaint()) {
+ if (event.getID() == PaintEvent.PAINT) {
+ paint(g);
+ } else {
+ update(g);
+ }
+ }
+ g.dispose();
+ }
+
+ /**
+ * Inits the graphics.
+ *
+ * @param g the g
+ * @param e the e
+ */
+ void initGraphics(Graphics g, PaintEvent e) {
+ Rectangle clip = e.getUpdateRect();
+ if (clip instanceof ClipRegion) {
+ g.setClip(((ClipRegion) clip).getClip());
+ } else {
+ g.setClip(clip);
+ }
+ if (isPrepainter()) {
+ prepaint(g);
+ } else if (!isLightweight() && (e.getID() == PaintEvent.PAINT)) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, w, h);
+ }
+ g.setFont(getFont());
+ g.setColor(getForeground());
+ }
+
+ /**
+ * Enables the events with the specified event mask to be delivered to
+ * this component.
+ *
+ * @param eventsToEnable the events mask which specifies the types
+ * of events to enable.
+ */
+ protected final void enableEvents(long eventsToEnable) {
+ toolkit.lockAWT();
+ try {
+ enabledEvents |= eventsToEnable;
+ deprecatedEventHandler = false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Enable awt events.
+ *
+ * @param eventsToEnable the events to enable
+ */
+ private void enableAWTEvents(long eventsToEnable) {
+ enabledAWTEvents |= eventsToEnable;
+ }
+
+ /**
+ * Disables the events with types specified by the specified event mask
+ * from being delivered to this component.
+ *
+ * @param eventsToDisable the event mask specifying the event types.
+ */
+ protected final void disableEvents(long eventsToDisable) {
+ toolkit.lockAWT();
+ try {
+ enabledEvents &= ~eventsToDisable;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /*
+ * For use in MouseDispatcher only. Really it checks not only mouse events.
+ */
+ /**
+ * Checks if is mouse event enabled.
+ *
+ * @param eventMask the event mask
+ *
+ * @return true, if is mouse event enabled
+ */
+ boolean isMouseEventEnabled(long eventMask) {
+ return (isEventEnabled(eventMask) || (enabledAWTEvents & eventMask) != 0);
+ }
+
+ /**
+ * Checks if is event enabled.
+ *
+ * @param eventMask the event mask
+ *
+ * @return true, if is event enabled
+ */
+ boolean isEventEnabled(long eventMask) {
+ return ((enabledEvents & eventMask) != 0);
+ }
+
+ /**
+ * Enables or disables input method support for this component.
+ *
+ * @param enable true to enable input method support, false to disable it.
+ */
+ public void enableInputMethods(boolean enable) {
+ toolkit.lockAWT();
+ try {
+ if (!enable) {
+ removeNotifyInputContext();
+ }
+ inputMethodsEnabled = enable;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets an array of all component's listeners registered for this
+ * component.
+ *
+ * @return an array of all component's listeners registered for this
+ * component.
+ */
+ public ComponentListener[] getComponentListeners() {
+ return componentListeners.getUserListeners(new ComponentListener[0]);
+ }
+
+ /**
+ * Adds the specified component listener to the Component for receiving
+ * component's event.
+ *
+ * @param l the ComponentListener.
+ */
+ public void addComponentListener(ComponentListener l) {
+ componentListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the component listener registered for this Component.
+ *
+ * @param l the ComponentListener.
+ */
+ public void removeComponentListener(ComponentListener l) {
+ componentListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a component event that has occurred on this component
+ * by dispatching them to any registered ComponentListener objects.
+ *
+ * @param e the ComponentEvent.
+ */
+ protected void processComponentEvent(ComponentEvent e) {
+ processComponentEventImpl(e, componentListeners.getUserListeners());
+ }
+
+ /**
+ * Process component event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processComponentEventImpl(ComponentEvent e, Collection<ComponentListener> c) {
+ for (ComponentListener listener : c) {
+ switch (e.getID()) {
+ case ComponentEvent.COMPONENT_HIDDEN:
+ listener.componentHidden(e);
+ break;
+ case ComponentEvent.COMPONENT_MOVED:
+ listener.componentMoved(e);
+ break;
+ case ComponentEvent.COMPONENT_RESIZED:
+ listener.componentResized(e);
+ break;
+ case ComponentEvent.COMPONENT_SHOWN:
+ listener.componentShown(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of focus listeners registered for this Component.
+ *
+ * @return the array of focus listeners registered for this Component.
+ */
+ public FocusListener[] getFocusListeners() {
+ return focusListeners.getUserListeners(new FocusListener[0]);
+ }
+
+ /**
+ * Adds the specified focus listener to the Component for receiving
+ * focus events.
+ *
+ * @param l the FocusListener.
+ */
+ public void addFocusListener(FocusListener l) {
+ focusListeners.addUserListener(l);
+ }
+
+ /**
+ * Adds the awt focus listener.
+ *
+ * @param l the l
+ */
+ void addAWTFocusListener(FocusListener l) {
+ enableAWTEvents(AWTEvent.FOCUS_EVENT_MASK);
+ focusListeners.addSystemListener(l);
+ }
+
+ /**
+ * Removes the focus listener registered for this Component.
+ *
+ * @param l the FocusListener.
+ */
+ public void removeFocusListener(FocusListener l) {
+ focusListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a FocusEvent that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the FocusEvent.
+ */
+ protected void processFocusEvent(FocusEvent e) {
+ processFocusEventImpl(e, focusListeners.getUserListeners());
+ }
+
+ /**
+ * Process focus event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processFocusEventImpl(FocusEvent e, Collection<FocusListener> c) {
+ for (FocusListener listener : c) {
+ switch (e.getID()) {
+ case FocusEvent.FOCUS_GAINED:
+ listener.focusGained(e);
+ break;
+ case FocusEvent.FOCUS_LOST:
+ listener.focusLost(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of registered HierarchyListeners for
+ * this Component.
+ *
+ * @return an array of registered HierarchyListeners for
+ * this Component.
+ */
+ public HierarchyListener[] getHierarchyListeners() {
+ return hierarchyListeners.getUserListeners(new HierarchyListener[0]);
+ }
+
+ /**
+ * Adds the specified hierarchy listener.
+ *
+ * @param l the HierarchyListener.
+ */
+ public void addHierarchyListener(HierarchyListener l) {
+ hierarchyListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the hierarchy listener registered for this component.
+ *
+ * @param l the HierarchyListener.
+ */
+ public void removeHierarchyListener(HierarchyListener l) {
+ hierarchyListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a hierarchy event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the HierarchyEvent.
+ */
+ protected void processHierarchyEvent(HierarchyEvent e) {
+ for (HierarchyListener listener : hierarchyListeners.getUserListeners()) {
+ switch (e.getID()) {
+ case HierarchyEvent.HIERARCHY_CHANGED:
+ listener.hierarchyChanged(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of HierarchyBoundsListener objects registered
+ * to this Component.
+ *
+ * @return an array of HierarchyBoundsListener objects.
+ */
+ public HierarchyBoundsListener[] getHierarchyBoundsListeners() {
+ return hierarchyBoundsListeners.getUserListeners(new HierarchyBoundsListener[0]);
+ }
+
+ /**
+ * Adds the specified hierarchy bounds listener.
+ *
+ * @param l the HierarchyBoundsListener.
+ */
+ public void addHierarchyBoundsListener(HierarchyBoundsListener l) {
+ hierarchyBoundsListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the hierarchy bounds listener registered for this Component.
+ *
+ * @param l the HierarchyBoundsListener.
+ */
+ public void removeHierarchyBoundsListener(HierarchyBoundsListener l) {
+ hierarchyBoundsListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a hierarchy bounds event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the HierarchyBoundsEvent.
+ */
+ protected void processHierarchyBoundsEvent(HierarchyEvent e) {
+ for (HierarchyBoundsListener listener : hierarchyBoundsListeners.getUserListeners()) {
+ switch (e.getID()) {
+ case HierarchyEvent.ANCESTOR_MOVED:
+ listener.ancestorMoved(e);
+ break;
+ case HierarchyEvent.ANCESTOR_RESIZED:
+ listener.ancestorResized(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of the key listeners registered to the Component.
+ *
+ * @return an array of the key listeners registered to the Component.
+ */
+ public KeyListener[] getKeyListeners() {
+ return keyListeners.getUserListeners(new KeyListener[0]);
+ }
+
+ /**
+ * Adds the specified key listener.
+ *
+ * @param l the KeyListener.
+ */
+ public void addKeyListener(KeyListener l) {
+ keyListeners.addUserListener(l);
+ }
+
+ /**
+ * Adds the awt key listener.
+ *
+ * @param l the l
+ */
+ void addAWTKeyListener(KeyListener l) {
+ enableAWTEvents(AWTEvent.KEY_EVENT_MASK);
+ keyListeners.addSystemListener(l);
+ }
+
+ /**
+ * Removes the key listener registered for this Component.
+ *
+ * @param l the KeyListener.
+ */
+ public void removeKeyListener(KeyListener l) {
+ keyListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a key event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the KeyEvent.
+ */
+ protected void processKeyEvent(KeyEvent e) {
+ processKeyEventImpl(e, keyListeners.getUserListeners());
+ }
+
+ /**
+ * Process key event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processKeyEventImpl(KeyEvent e, Collection<KeyListener> c) {
+ for (KeyListener listener : c) {
+ switch (e.getID()) {
+ case KeyEvent.KEY_PRESSED:
+ listener.keyPressed(e);
+ break;
+ case KeyEvent.KEY_RELEASED:
+ listener.keyReleased(e);
+ break;
+ case KeyEvent.KEY_TYPED:
+ listener.keyTyped(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of the mouse listeners registered to the Component.
+ *
+ * @return an array of the mouse listeners registered to the Component.
+ */
+ public MouseListener[] getMouseListeners() {
+ return mouseListeners.getUserListeners(new MouseListener[0]);
+ }
+
+ /**
+ * Adds the specified mouse listener.
+ *
+ * @param l the MouseListener.
+ */
+ public void addMouseListener(MouseListener l) {
+ mouseListeners.addUserListener(l);
+ }
+
+ /**
+ * Adds the awt mouse listener.
+ *
+ * @param l the l
+ */
+ void addAWTMouseListener(MouseListener l) {
+ enableAWTEvents(AWTEvent.MOUSE_EVENT_MASK);
+ mouseListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt mouse motion listener.
+ *
+ * @param l the l
+ */
+ void addAWTMouseMotionListener(MouseMotionListener l) {
+ enableAWTEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
+ mouseMotionListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt component listener.
+ *
+ * @param l the l
+ */
+ void addAWTComponentListener(ComponentListener l) {
+ enableAWTEvents(AWTEvent.COMPONENT_EVENT_MASK);
+ componentListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt input method listener.
+ *
+ * @param l the l
+ */
+ void addAWTInputMethodListener(InputMethodListener l) {
+ enableAWTEvents(AWTEvent.INPUT_METHOD_EVENT_MASK);
+ inputMethodListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt mouse wheel listener.
+ *
+ * @param l the l
+ */
+ void addAWTMouseWheelListener(MouseWheelListener l) {
+ enableAWTEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
+ mouseWheelListeners.addSystemListener(l);
+ }
+
+ /**
+ * Removes the mouse listener registered for this Component.
+ *
+ * @param l the MouseListener.
+ */
+ public void removeMouseListener(MouseListener l) {
+ mouseListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a mouse event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the MouseEvent.
+ */
+ protected void processMouseEvent(MouseEvent e) {
+ processMouseEventImpl(e, mouseListeners.getUserListeners());
+ }
+
+ /**
+ * Process mouse event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processMouseEventImpl(MouseEvent e, Collection<MouseListener> c) {
+ for (MouseListener listener : c) {
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_CLICKED:
+ listener.mouseClicked(e);
+ break;
+ case MouseEvent.MOUSE_ENTERED:
+ listener.mouseEntered(e);
+ break;
+ case MouseEvent.MOUSE_EXITED:
+ listener.mouseExited(e);
+ break;
+ case MouseEvent.MOUSE_PRESSED:
+ listener.mousePressed(e);
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ listener.mouseReleased(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Process mouse motion event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processMouseMotionEventImpl(MouseEvent e, Collection<MouseMotionListener> c) {
+ for (MouseMotionListener listener : c) {
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_DRAGGED:
+ listener.mouseDragged(e);
+ break;
+ case MouseEvent.MOUSE_MOVED:
+ listener.mouseMoved(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of the mouse motion listeners registered to
+ * the Component.
+ *
+ * @return an array of the MouseMotionListeners registered to
+ * the Component.
+ */
+ public MouseMotionListener[] getMouseMotionListeners() {
+ return mouseMotionListeners.getUserListeners(new MouseMotionListener[0]);
+ }
+
+ /**
+ * Adds the specified mouse motion listener.
+ *
+ * @param l the MouseMotionListener.
+ */
+ public void addMouseMotionListener(MouseMotionListener l) {
+ mouseMotionListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the mouse motion listener registered for this component.
+ *
+ * @param l the MouseMotionListener.
+ */
+ public void removeMouseMotionListener(MouseMotionListener l) {
+ mouseMotionListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a mouse motion event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the MouseEvent.
+ */
+ protected void processMouseMotionEvent(MouseEvent e) {
+ processMouseMotionEventImpl(e, mouseMotionListeners.getUserListeners());
+ }
+
+ /**
+ * Gets an array of the mouse wheel listeners registered to
+ * the Component.
+ *
+ * @return an array of the MouseWheelListeners registered to
+ * the Component.
+ */
+ public MouseWheelListener[] getMouseWheelListeners() {
+ return mouseWheelListeners.getUserListeners(new MouseWheelListener[0]);
+ }
+
+ /**
+ * Adds the specified mouse wheel listener.
+ *
+ * @param l the MouseWheelListener.
+ */
+ public void addMouseWheelListener(MouseWheelListener l) {
+ mouseWheelListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the mouse wheel listener registered for this component.
+ *
+ * @param l the MouseWheelListener.
+ */
+ public void removeMouseWheelListener(MouseWheelListener l) {
+ mouseWheelListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a mouse wheel event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the MouseWheelEvent.
+ */
+ protected void processMouseWheelEvent(MouseWheelEvent e) {
+ processMouseWheelEventImpl(e, mouseWheelListeners.getUserListeners());
+ }
+
+ /**
+ * Gets an array of the InputMethodListener listeners
+ * registered to the Component.
+ *
+ * @return an array of the InputMethodListener listeners
+ * registered to the Component.
+ */
+ public InputMethodListener[] getInputMethodListeners() {
+ return inputMethodListeners.getUserListeners(new InputMethodListener[0]);
+ }
+
+ /**
+ * Adds the specified input method listener.
+ *
+ * @param l the InputMethodListener.
+ */
+ public void addInputMethodListener(InputMethodListener l) {
+ inputMethodListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the input method listener registered for this component.
+ *
+ * @param l the InputMethodListener.
+ */
+ public void removeInputMethodListener(InputMethodListener l) {
+ inputMethodListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes an input method event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the InputMethodEvent.
+ */
+ protected void processInputMethodEvent(InputMethodEvent e) {
+ processInputMethodEventImpl(e, inputMethodListeners.getUserListeners());
+ }
+
+ /**
+ * Process input method event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processInputMethodEventImpl(InputMethodEvent e,
+ Collection<InputMethodListener> c) {
+ for (InputMethodListener listener : c) {
+ switch (e.getID()) {
+ case InputMethodEvent.CARET_POSITION_CHANGED:
+ listener.caretPositionChanged(e);
+ break;
+ case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
+ listener.inputMethodTextChanged(e);
+ break;
+ }
+ }
+ }
+
+ //???AWT
+ /*
+ public Point getMousePosition() throws HeadlessException {
+ Point absPointerPos = MouseInfo.getPointerInfo().getLocation();
+ Window winUnderPtr = toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos);
+ Point pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, winUnderPtr);
+ boolean isUnderPointer = false;
+ if (winUnderPtr == null) {
+ return null;
+ }
+ isUnderPointer = winUnderPtr.isComponentAt(this, pointerPos);
+ if (isUnderPointer) {
+ return MouseDispatcher.convertPoint(null, absPointerPos, this);
+ }
+ return null;
+ }
+ */
+
+ /**
+ * Set native caret at the given position <br>
+ * Note: this method takes AWT lock inside because it walks through the
+ * component hierarchy.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void setCaretPos(final int x, final int y) {
+ Runnable r = new Runnable() {
+ public void run() {
+ toolkit.lockAWT();
+ try {
+ setCaretPosImpl(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ };
+ if (Thread.currentThread() instanceof EventDispatchThread) {
+ r.run();
+ } else {
+ toolkit.getSystemEventQueueImpl().postEvent(new InvocationEvent(this, r));
+ }
+ }
+
+ /**
+ * This method should be called only at event dispatch thread.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void setCaretPosImpl(int x, int y) {
+ Component c = this;
+ while ((c != null) && c.behaviour.isLightweight()) {
+ x += c.x;
+ y += c.y;
+ //???AWT: c = c.getParent();
+ }
+ if (c == null) {
+ return;
+ }
+ //???AWT
+ /*
+ if (c instanceof Window) {
+ Insets insets = c.getNativeInsets();
+ x -= insets.left;
+ y -= insets.top;
+ }
+ toolkit.getWindowFactory().setCaretPosition(x, y);
+ */
+ }
+
+ // to be overridden in standard components such as Button and List
+ /**
+ * Gets the default minimum size.
+ *
+ * @return the default minimum size
+ */
+ Dimension getDefaultMinimumSize() {
+ return null;
+ }
+
+ // to be overridden in standard components such as Button and List
+ /**
+ * Gets the default preferred size.
+ *
+ * @return the default preferred size
+ */
+ Dimension getDefaultPreferredSize() {
+ return null;
+ }
+
+ // to be overridden in standard components such as Button and List
+ /**
+ * Reset default size.
+ */
+ void resetDefaultSize() {
+ }
+
+ //???AWT
+ /*
+ ComponentBehavior createBehavior() {
+ return new LWBehavior(this);
+ }
+ */
+
+ /**
+ * Gets the default background.
+ *
+ * @return the default background
+ */
+ Color getDefaultBackground() {
+ //???AWT: return getWindowAncestor().getDefaultBackground();
+ return getBackground();
+ }
+
+ /**
+ * Gets the default foreground.
+ *
+ * @return the default foreground
+ */
+ Color getDefaultForeground() {
+ //???AWT return getWindowAncestor().getDefaultForeground();
+ return getForeground();
+ }
+
+ /**
+ * Called when native resource for this component is created (for
+ * heavyweights only).
+ *
+ * @param win the win
+ */
+ void nativeWindowCreated(NativeWindow win) {
+ // to be overridden
+ }
+
+ /**
+ * Determine the component's area hidden behind the windows that have higher
+ * Z-order, including windows of other applications.
+ *
+ * @param image the image
+ * @param destLocation the dest location
+ * @param destSize the dest size
+ * @param source the source
+ *
+ * @return the calculated region, or null if it cannot be determined
+ */
+ //???AWT
+ /*
+ MultiRectArea getObscuredRegion(Rectangle part) {
+ if (!visible || parent == null || !parent.visible) {
+ return null;
+ }
+ Rectangle r = new Rectangle(0, 0, w, h);
+ if (part != null) {
+ r = r.intersection(part);
+ }
+ if (r.isEmpty()) {
+ return null;
+ }
+ r.translate(x, y);
+ MultiRectArea ret = parent.getObscuredRegion(r);
+ if (ret != null) {
+ parent.addObscuredRegions(ret, this);
+ ret.translate(-x, -y);
+ ret.intersect(new Rectangle(0, 0, w, h));
+ }
+ return ret;
+ }
+ */
+
+ //???AWT
+ /*
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ stream.defaultReadObject();
+ FieldsAccessor accessor = new FieldsAccessor(Component.class, this);
+ accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$
+ accessor.set("behaviour", createBehavior()); //$NON-NLS-1$
+ accessor.set("componentLock", new Object()); // $NON-LOCK-1$ //$NON-NLS-1$
+ }
+ */
+
+ final void onDrawImage(Image image, Point destLocation, Dimension destSize, Rectangle source) {
+ ImageParameters imageParams;
+ if (updatedImages == null) {
+ updatedImages = new HashMap<Image, ImageParameters>();
+ }
+ imageParams = updatedImages.get(image);
+ if (imageParams == null) {
+ imageParams = new ImageParameters();
+ updatedImages.put(image, imageParams);
+ }
+ imageParams.addDrawing(destLocation, destSize, source);
+ }
+
+ public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
+ toolkit.lockAWT();
+ try {
+ boolean done = false;
+ if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
+ done = true;
+ } else if ((infoflags & SOMEBITS) != 0 && incrementalImageUpdate) {
+ done = true;
+ }
+ if (done) {
+ repaint();
+ }
+ return (infoflags & (ABORT | ALLBITS)) == 0;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ private void invalidateRealParent() {
+ Container realParent = getRealParent();
+ if ((realParent != null) && realParent.isValid()) {
+ realParent.invalidate();
+ }
+ }
+ */
+
+ /**
+ * The Class ImageParameters.
+ */
+ private class ImageParameters {
+
+ /** The drawing params. */
+ private final LinkedList<DrawingParameters> drawingParams = new LinkedList<DrawingParameters>();
+
+ /** The size. */
+ Dimension size = new Dimension(Component.this.w, Component.this.h);
+
+ /**
+ * Adds the drawing.
+ *
+ * @param destLocation the dest location
+ * @param destSize the dest size
+ * @param source the source
+ */
+ void addDrawing(Point destLocation, Dimension destSize, Rectangle source) {
+ drawingParams.add(new DrawingParameters(destLocation, destSize, source));
+ }
+
+ /**
+ * Drawing parameters iterator.
+ *
+ * @return the iterator< drawing parameters>
+ */
+ Iterator<DrawingParameters> drawingParametersIterator() {
+ return drawingParams.iterator();
+ }
+
+ /**
+ * The Class DrawingParameters.
+ */
+ class DrawingParameters {
+
+ /** The dest location. */
+ Point destLocation;
+
+ /** The dest size. */
+ Dimension destSize;
+
+ /** The source. */
+ Rectangle source;
+
+ /**
+ * Instantiates a new drawing parameters.
+ *
+ * @param destLocation the dest location
+ * @param destSize the dest size
+ * @param source the source
+ */
+ DrawingParameters(Point destLocation, Dimension destSize, Rectangle source) {
+ this.destLocation = new Point(destLocation);
+ if (destSize != null) {
+ this.destSize = new Dimension(destSize);
+ } else {
+ this.destSize = null;
+ }
+ if (source != null) {
+ this.source = new Rectangle(source);
+ } else {
+ this.source = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * TextComponent support.
+ *
+ * @param e the e
+ *
+ * @return true, if dispatch event to im
+ */
+ //???AWT
+ /*
+ private TextKit textKit = null;
+
+ TextKit getTextKit() {
+ return textKit;
+ }
+
+ void setTextKit(TextKit kit) {
+ textKit = kit;
+ }
+ */
+
+ /**
+ * TextField support
+ */
+ //???AWT
+ /*
+ private TextFieldKit textFieldKit = null;
+
+ TextFieldKit getTextFieldKit() {
+ return textFieldKit;
+ }
+
+ void setTextFieldKit(TextFieldKit kit) {
+ textFieldKit = kit;
+ }
+ */
+
+ /**
+ * Dispatches input & focus events to input method
+ * context.
+ * @param e event to pass to InputContext.dispatchEvent()
+ * @return true if event was consumed by IM, false otherwise
+ */
+ private boolean dispatchEventToIM(AWTEvent e) {
+ InputContext ic = getInputContext();
+ if (ic == null) {
+ return false;
+ }
+ int id = e.getID();
+ boolean isInputEvent = ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST))
+ || ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST));
+ if (((id >= FocusEvent.FOCUS_FIRST) && (id <= FocusEvent.FOCUS_LAST)) || isInputEvent) {
+ ic.dispatchEvent(e);
+ }
+ return e.isConsumed();
+ }
+}
diff --git a/awt/java/awt/ComponentBehavior.java b/awt/java/awt/ComponentBehavior.java
new file mode 100644
index 0000000..89c9999
--- /dev/null
+++ b/awt/java/awt/ComponentBehavior.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+/**
+ * The interface of the helper object that encapsulates the difference
+ * between lightweight and heavyweight components.
+ */
+interface ComponentBehavior {
+
+ void addNotify();
+
+ void setBounds(int x, int y, int w, int h, int bMask);
+
+ void setVisible(boolean b);
+
+ Graphics getGraphics(int translationX, int translationY, int width, int height);
+
+ NativeWindow getNativeWindow();
+
+ boolean isLightweight();
+
+ void onMove(int x, int y);
+
+ boolean isOpaque();
+
+ boolean isDisplayable();
+
+ void setEnabled(boolean value);
+
+ void removeNotify();
+
+ void setZOrder(int newIndex, int oldIndex);
+
+ boolean setFocus(boolean focus, Component opposite);
+}
diff --git a/awt/java/awt/ComponentOrientation.java b/awt/java/awt/ComponentOrientation.java
new file mode 100644
index 0000000..ddb118d
--- /dev/null
+++ b/awt/java/awt/ComponentOrientation.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * The ComponentOrientation class specifies the language-sensitive orientation
+ * of component's elements or text. It is used to reflect the differences in this
+ * ordering between different writting systems. The ComponentOrientation class
+ * indicates the orientation of the elements/text in the horizontal direction
+ * ("left to right" or "right to left") and in the vertical direction
+ * ("top to bottom" or "bottom to top").
+ */
+public final class ComponentOrientation implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4113291392143563828L;
+
+ /**
+ * The Constant LEFT_TO_RIGHT indicates that items run left to right.
+ */
+ public static final ComponentOrientation LEFT_TO_RIGHT = new ComponentOrientation(true, true);
+
+ /**
+ * The Constant RIGHT_TO_LEFT indicates that items run right to left.
+ */
+ public static final ComponentOrientation RIGHT_TO_LEFT = new ComponentOrientation(true, false);
+
+ /** The Constant UNKNOWN indicates that a component's orientation is not set. */
+ public static final ComponentOrientation UNKNOWN = new ComponentOrientation(true, true);
+
+ /** The Constant rlLangs. */
+ private static final Set<String> rlLangs = new HashSet<String>(); //RIGHT_TO_LEFT languages
+
+ /** The horizontal. */
+ private final boolean horizontal;
+
+ /** The left2right. */
+ private final boolean left2right;
+
+ static {
+ rlLangs.add("ar"); //$NON-NLS-1$
+ rlLangs.add("fa"); //$NON-NLS-1$
+ rlLangs.add("iw"); //$NON-NLS-1$
+ rlLangs.add("ur"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the orientation for the given ResourceBundle's localization.
+ *
+ * @param bdl the ResourceBundle.
+ *
+ * @return the ComponentOrientation.
+ *
+ * @deprecated Use getOrientation(java.util.Locale) method.
+ */
+ @Deprecated
+ public static ComponentOrientation getOrientation(ResourceBundle bdl) {
+ Object obj = null;
+ try {
+ obj = bdl.getObject("Orientation"); //$NON-NLS-1$
+ }
+ catch (MissingResourceException mre) {
+ obj = null;
+ }
+ if (obj instanceof ComponentOrientation) {
+ return (ComponentOrientation) obj;
+ }
+ Locale locale = bdl.getLocale();
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ return getOrientation(locale);
+ }
+
+ /**
+ * Gets the orientation for the specified locale.
+ *
+ * @param locale the specified Locale.
+ *
+ * @return the ComponentOrientation.
+ */
+ public static ComponentOrientation getOrientation(Locale locale) {
+ String lang = locale.getLanguage();
+ return rlLangs.contains(lang) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
+ }
+
+ /**
+ * Instantiates a new component orientation.
+ *
+ * @param hor whether the items should be arranged horizontally
+ * @param l2r whether this orientation specifies a left-to-right flow
+ */
+ private ComponentOrientation(boolean hor, boolean l2r) {
+ horizontal = hor;
+ left2right = l2r;
+ }
+
+ /**
+ * Returns true if the text of the of writing systems arranged
+ * horizontally.
+ *
+ * @return true, if the text is written horizontally, false
+ * for a vertical arrangement.
+ */
+ public boolean isHorizontal() {
+ return horizontal;
+ }
+
+ /**
+ * Returns true if the text is arranged from left to right.
+ *
+ * @return true, for writing systems written from left to right;
+ * false for right-to-left.
+ */
+ public boolean isLeftToRight() {
+ return left2right;
+ }
+
+}
diff --git a/awt/java/awt/Composite.java b/awt/java/awt/Composite.java
new file mode 100644
index 0000000..8e5b90a
--- /dev/null
+++ b/awt/java/awt/Composite.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.ColorModel;
+
+/**
+ * The Composite interface allows the methods to compose a draw primitive
+ * on the graphics area. The classes implementing this interface provides
+ * the rules and a method to create the context for a particular operation.
+ */
+public interface Composite {
+
+ /**
+ * Creates a CompositeContext which defines the encapsulated and
+ * optimized environment for a compositing operation. Several contexts
+ * can exist for a single Composite object.
+ *
+ * @param srcColorModel the source's ColorModel.
+ * @param dstColorModel the destination's ColorModel.
+ * @param hints the RenderingHints.
+ *
+ * @return the CompositeContext object.
+ */
+ public CompositeContext createContext(ColorModel srcColorModel,
+ ColorModel dstColorModel, RenderingHints hints);
+
+}
+
diff --git a/awt/java/awt/CompositeContext.java b/awt/java/awt/CompositeContext.java
new file mode 100644
index 0000000..c676032
--- /dev/null
+++ b/awt/java/awt/CompositeContext.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * The CompositeContext interface specifies the encapsulated and optimized
+ * environment for a compositing operation.
+ */
+public interface CompositeContext {
+
+ /**
+ * Composes the two source Raster objects and places the result in the
+ * destination WritableRaster.
+ *
+ * @param src the source Raster.
+ * @param dstIn the destination Raster.
+ * @param dstOut the WritableRaster object where the result of
+ * composing operation is stored.
+ */
+ public void compose(Raster src, Raster dstIn, WritableRaster dstOut);
+
+ /**
+ * Releases resources allocated for a context.
+ */
+ public void dispose();
+
+}
+
diff --git a/awt/java/awt/Cursor.java b/awt/java/awt/Cursor.java
new file mode 100644
index 0000000..625686c
--- /dev/null
+++ b/awt/java/awt/Cursor.java
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.NativeCursor;
+
+/**
+ * The Cursor class represents the bitmap of the mouse cursor.
+ */
+public class Cursor implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8028237497568985504L;
+
+ /** The Constant DEFAULT_CURSOR indicates the default cursor type. */
+ public static final int DEFAULT_CURSOR = 0;
+
+ /** The Constant CROSSHAIR_CURSOR cursor type. */
+ public static final int CROSSHAIR_CURSOR = 1;
+
+ /** The Constant TEXT_CURSOR cursor type. */
+ public static final int TEXT_CURSOR = 2;
+
+ /** The Constant WAIT_CURSOR cursor type. */
+ public static final int WAIT_CURSOR = 3;
+
+ /** The Constant SW_RESIZE_CURSOR cursor type. */
+ public static final int SW_RESIZE_CURSOR = 4;
+
+ /** The Constant SE_RESIZE_CURSOR cursor type. */
+ public static final int SE_RESIZE_CURSOR = 5;
+
+ /** The Constant NW_RESIZE_CURSOR cursor type. */
+ public static final int NW_RESIZE_CURSOR = 6;
+
+ /** The Constant NE_RESIZE_CURSOR cursor type. */
+ public static final int NE_RESIZE_CURSOR = 7;
+
+ /** The Constant N_RESIZE_CURSOR cursor type. */
+ public static final int N_RESIZE_CURSOR = 8;
+
+ /** The Constant S_RESIZE_CURSOR cursor type. */
+ public static final int S_RESIZE_CURSOR = 9;
+
+ /** The Constant W_RESIZE_CURSOR cursor type. */
+ public static final int W_RESIZE_CURSOR = 10;
+
+ /** The Constant E_RESIZE_CURSOR cursor type. */
+ public static final int E_RESIZE_CURSOR = 11;
+
+ /** The Constant HAND_CURSOR cursor type. */
+ public static final int HAND_CURSOR = 12;
+
+ /** The Constant MOVE_CURSOR cursor type. */
+ public static final int MOVE_CURSOR = 13;
+
+ /** A mapping from names to system custom cursors. */
+ static Map<String, Cursor> systemCustomCursors;
+
+ /** The cursor props. */
+ static Properties cursorProps;
+
+ /** The Constant predefinedNames. */
+ static final String[] predefinedNames = {
+ "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$
+ "Northwest Resize", "Northeast Resize", //$NON-NLS-1$ //$NON-NLS-2$
+ "North Resize", "South Resize", "West Resize", "East Resize", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "Hand", "Move" //$NON-NLS-1$ //$NON-NLS-2$
+
+ };
+
+ /** The predefined set of cursors. */
+ protected static Cursor[] predefined = {
+ new Cursor(DEFAULT_CURSOR), null, null, null,
+ null, null, null, null,
+ null, null, null, null,
+ null, null
+ };
+
+ /** The Constant CUSTOM_CURSOR is associated with all custom cursor types.
+ * (Those which are not predefined)
+ */
+ public static final int CUSTOM_CURSOR = -1;
+
+ /** The name of the cursor. */
+ protected String name;
+
+ /** The type of the cursor, chosen from the list of cursor type constants. */
+ private final int type;
+
+ /** The native cursor. */
+ private transient NativeCursor nativeCursor;
+
+ /** The exact point on the cursor image that indicates which point
+ * the cursor is selecting (pointing to). The coordinates are given
+ * with respect the origin of the Image (its upper left corner).
+ */
+ private Point hotSpot;
+
+ /** The image to draw on the screen representing the cursor. */
+ private Image image;
+
+ /**
+ * Instantiates a new cursor with the specified name.
+ *
+ * @param name the name of cursor.
+ */
+ protected Cursor(String name) {
+ this(name, null, new Point());
+ }
+
+ /**
+ * Instantiates a new cursor of the specified type.
+ *
+ * @param type the type of cursor.
+ */
+ public Cursor(int type) {
+ checkType(type);
+ this.type = type;
+ if ((type >= 0) && (type < predefinedNames.length)) {
+ name = predefinedNames[type] + " Cursor"; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Instantiates a new cursor.
+ *
+ * @param name the name
+ * @param img the img
+ * @param hotSpot the hot spot
+ */
+ Cursor(String name, Image img, Point hotSpot) {
+ this.name = name;
+ type = CUSTOM_CURSOR;
+ this.hotSpot = hotSpot;
+ image = img;
+ }
+
+ /**
+ * Finalize method overrided finalize method from Object class.
+ *
+ * @throws Throwable if the native cursor is not null and throws
+ * a throwable when destroyed.
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ if (nativeCursor != null) {
+ nativeCursor.destroyCursor();
+ }
+ }
+
+ /**
+ * Gets the name of the cursor.
+ *
+ * @return the name of the cursor.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the String representation of the cursor.
+ *
+ * @return the String representation of the cursor.
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[" + name + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Gets the cursor type.
+ *
+ * @return the cursor type
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Gets the predefined cursor with the specified type.
+ *
+ * @param type the type of cursor.
+ *
+ * @return the predefined cursor with the specified type.
+ */
+ public static Cursor getPredefinedCursor(int type) {
+ checkType(type);
+ Cursor cursor = predefined[type];
+ if (cursor == null) {
+ cursor = new Cursor(type);
+ predefined[type] = cursor;
+ }
+ return cursor;
+ }
+
+ /**
+ * Gets the default cursor.
+ *
+ * @return the default cursor.
+ */
+ public static Cursor getDefaultCursor() {
+ return getPredefinedCursor(DEFAULT_CURSOR);
+ }
+
+ /**
+ * Gets the specified system custom cursor.
+ *
+ * @param name the name of the desired system cursor.
+ *
+ * @return the specific system cursor with the specified name.
+ *
+ * @throws AWTException if the desired cursor has malformed data
+ * such as an incorrectly defined hot spot.
+ * @throws HeadlessException if the isHeadless method of the GraphicsEnvironment
+ * returns true.
+ */
+ public static Cursor getSystemCustomCursor(String name)
+ throws AWTException, HeadlessException {
+ Toolkit.checkHeadless();
+ return getSystemCustomCursorFromMap(name);
+ }
+
+ /**
+ * Gets the specified system custom cursor from the map of system custom cursors.
+ *
+ * @param name the name of the desired cursor.
+ *
+ * @return the desired system custom cursor from the
+ * map of system custom cursors.
+ *
+ * @throws AWTException the AWT exception
+ */
+ private static Cursor getSystemCustomCursorFromMap (String name)
+ throws AWTException {
+ loadCursorProps();
+ if (systemCustomCursors == null) {
+ systemCustomCursors = new HashMap<String, Cursor>();
+ }
+ Cursor cursor = systemCustomCursors.get(name);
+ if (cursor != null) {
+ return cursor;
+ }
+ // awt.141=failed to parse hotspot property for cursor:
+ String exMsg = Messages.getString("awt.141") + name; //$NON-NLS-1$
+ String nm = "Cursor." + name; //$NON-NLS-1$
+ String nameStr = cursorProps.getProperty(nm + ".Name"); //$NON-NLS-1$
+ String hotSpotStr = cursorProps.getProperty(nm + ".HotSpot"); //$NON-NLS-1$
+ String fileStr = cursorProps.getProperty(nm + ".File"); //$NON-NLS-1$
+ int idx = hotSpotStr.indexOf(',');
+ if (idx < 0) {
+ throw new AWTException(exMsg);
+ }
+ int x, y;
+ try {
+ x = new Integer(hotSpotStr.substring(0, idx)).intValue();
+ y = new Integer(hotSpotStr.substring(idx + 1,
+ hotSpotStr.length())).intValue();
+ } catch (NumberFormatException nfe) {
+ throw new AWTException(exMsg);
+ }
+ Image img = Toolkit.getDefaultToolkit().createImage(fileStr);
+ cursor = new Cursor(nameStr, img, new Point(x, y));
+ systemCustomCursors.put(name, cursor);
+
+ return cursor;
+ }
+
+ /**
+ * Load cursor props.
+ *
+ * @throws AWTException the AWT exception
+ */
+ private static void loadCursorProps() throws AWTException {
+ if (cursorProps != null) {
+ return;
+ }
+ String sep = File.separator;
+ String cursorsDir = "lib" + sep + "images" + sep + "cursors"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ String cursorsAbsDir = System.getProperty("java.home") + sep + //$NON-NLS-1$
+ cursorsDir;
+ String cursorPropsFileName = "cursors.properties"; //$NON-NLS-1$
+ String cursorPropsFullFileName = (cursorsAbsDir + sep +
+ cursorPropsFileName);
+ cursorProps = new Properties();
+ try {
+ cursorProps.load(new FileInputStream(new File(
+ cursorPropsFullFileName)));
+ } catch (FileNotFoundException e) {
+ // awt.142=Exception: class {0} {1} occurred while loading: {2}
+ throw new AWTException(Messages.getString("awt.142",//$NON-NLS-1$
+ new Object[]{e.getClass(), e.getMessage(), cursorPropsFullFileName}));
+ } catch (IOException e) {
+ throw new AWTException(e.getMessage());
+ }
+
+ }
+
+ /**
+ * Check type.
+ *
+ * @param type the type
+ */
+ static void checkType(int type) {
+ // can't use predefined array here because it may not have been
+ // initialized yet
+ if ((type < 0) || (type >= predefinedNames.length)) {
+ // awt.143=illegal cursor type
+ throw new IllegalArgumentException(Messages.getString("awt.143")); //$NON-NLS-1$
+ }
+ }
+
+ // "lazily" create native cursors:
+ /**
+ * Gets the native cursor.
+ *
+ * @return the native cursor
+ */
+ NativeCursor getNativeCursor() {
+ if (nativeCursor != null) {
+ return nativeCursor;
+ }
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ if (type != CUSTOM_CURSOR) {
+ nativeCursor = toolkit.createNativeCursor(type);
+ } else {
+ nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot,
+ name);
+ }
+ return nativeCursor;
+ }
+
+ /**
+ * Sets the native cursor.
+ *
+ * @param nativeCursor the new native cursor
+ */
+ void setNativeCursor(NativeCursor nativeCursor) {
+ this.nativeCursor = nativeCursor;
+ }
+}
+
diff --git a/awt/java/awt/Dimension.java b/awt/java/awt/Dimension.java
new file mode 100644
index 0000000..8137846
--- /dev/null
+++ b/awt/java/awt/Dimension.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.Dimension2D;
+import java.io.Serializable;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Dimension represents the size (width and height) of a component.
+ * The width and height values can be negative, but in that case the
+ * behavior of some methods is unexpected.
+ */
+public class Dimension extends Dimension2D implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 4723952579491349524L;
+
+ /** The width dimension. */
+ public int width;
+
+ /** The height dimension. */
+ public int height;
+
+ /**
+ * Instantiates a new Dimension with the same data as the specified Dimension.
+ *
+ * @param d the Dimension to copy the data from when creating the
+ * new Dimension object.
+ */
+ public Dimension(Dimension d) {
+ this(d.width, d.height);
+ }
+
+ /**
+ * Instantiates a new Dimension with zero width and height.
+ */
+ public Dimension() {
+ this(0, 0);
+ }
+
+ /**
+ * Instantiates a new Dimension with the specified width and height.
+ *
+ * @param width the width of the new Dimension.
+ * @param height the height of the new Dimension.
+ */
+ public Dimension(int width, int height) {
+ setSize(width, height);
+ }
+
+ /**
+ * Returns the hash code of the Dimension.
+ *
+ * @return the hash code of the Dimension.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(width);
+ hash.append(height);
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares this Dimension object with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is a Dimension with
+ * the same width and height data as this Dimension.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Dimension) {
+ Dimension d = (Dimension)obj;
+ return (d.width == width && d.height == height);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the String associated to this Dimension object.
+ *
+ * @return the String associated to this Dimension object.
+ */
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Dimension().toString())
+ return getClass().getName() + "[width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Sets the size of this Dimension object with the specified width and height.
+ *
+ * @param width the width of the Dimension.
+ * @param height the height of the Dimension.
+ */
+ public void setSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the size of this Dimension object by copying the
+ * data from the specified Dimension object.
+ *
+ * @param d the Dimension that gives the new size values.
+ */
+ public void setSize(Dimension d) {
+ setSize(d.width, d.height);
+ }
+
+ /**
+ * Sets the size of this Dimension object with the specified double width
+ * and height.
+ *
+ * @param width the width of the Dimension.
+ * @param height the height of the Dimension.
+ *
+ * @see java.awt.geom.Dimension2D#setSize(double, double)
+ */
+ @Override
+ public void setSize(double width, double height) {
+ setSize((int)Math.ceil(width), (int)Math.ceil(height));
+ }
+
+ /**
+ * Gets the size of the Dimension.
+ *
+ * @return the size of the Dimension.
+ */
+ public Dimension getSize() {
+ return new Dimension(width, height);
+ }
+
+ /**
+ * Gets the height of the Dimension.
+ *
+ * @return the height of the Dimension.
+ *
+ * @see java.awt.geom.Dimension2D#getHeight()
+ */
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the width of the Dimension.
+ *
+ * @return the width of the Dimension.
+ *
+ * @see java.awt.geom.Dimension2D#getWidth()
+ */
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+}
+
diff --git a/awt/java/awt/Dispatcher.java b/awt/java/awt/Dispatcher.java
new file mode 100644
index 0000000..d457af4
--- /dev/null
+++ b/awt/java/awt/Dispatcher.java
@@ -0,0 +1,723 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ComponentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.PaintEvent;
+import java.awt.event.WindowEvent;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+
+/**
+ * Helper package-private class for managing lightweight components &
+ * dispatching events from heavyweight source
+ */
+class Dispatcher {
+
+ //???AWT: final PopupDispatcher popupDispatcher = new PopupDispatcher();
+
+ //???AWT: final FocusDispatcher focusDispatcher;
+
+ final MouseGrabManager mouseGrabManager = new MouseGrabManager();
+
+ final MouseDispatcher mouseDispatcher;
+
+ private final ComponentDispatcher componentDispatcher = new ComponentDispatcher();
+
+ private final KeyDispatcher keyDispatcher = new KeyDispatcher();
+
+ private final Toolkit toolkit;
+
+ int clickInterval = 250;
+
+ /**
+ * @param toolkit - AWT toolkit
+ */
+ Dispatcher(Toolkit toolkit) {
+ this.toolkit = toolkit;
+
+ //???AWT: focusDispatcher = new FocusDispatcher(toolkit);
+ mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit);
+ }
+
+ /**
+ * Dispatch native event: produce appropriate AWT events,
+ * update component's fields when needed
+ * @param event - native event to dispatch
+ * @return - true means default processing by OS is not needed
+ */
+ public boolean onEvent(NativeEvent event) {
+ int eventId = event.getEventId();
+
+ if (eventId == NativeEvent.ID_CREATED) {
+ return toolkit.onWindowCreated(event.getWindowId());
+ } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) {
+ return mouseGrabManager.onGrabCanceled();
+ //???AWT
+// } else if (popupDispatcher.onEvent(event)) {
+// return false;
+ } else {
+ Component src = toolkit.getComponentById(event.getWindowId());
+
+ if (src != null) {
+ if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST))
+ || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST))
+ || (eventId == NativeEvent.ID_INSETS_CHANGED)
+ || (eventId == NativeEvent.ID_BOUNDS_CHANGED)
+ || (eventId == NativeEvent.ID_THEME_CHANGED)) {
+ return componentDispatcher.dispatch(src, event);
+ } else if ((eventId >= MouseEvent.MOUSE_FIRST)
+ && (eventId <= MouseEvent.MOUSE_LAST)) {
+ return mouseDispatcher.dispatch(src, event);
+ } else if (eventId == PaintEvent.PAINT) {
+ //???AWT: src.redrawManager.addPaintRegion(src, event.getClipRects());
+ return true;
+ }
+ }
+ if ((eventId >= FocusEvent.FOCUS_FIRST)
+ && (eventId <= FocusEvent.FOCUS_LAST)) {
+
+ //???AWT: return focusDispatcher.dispatch(src, event);
+ return false;
+ } else if ((eventId >= KeyEvent.KEY_FIRST)
+ && (eventId <= KeyEvent.KEY_LAST)) {
+ return keyDispatcher.dispatch(src, event);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * The dispatcher of native events that affect
+ * component's state or bounds
+ */
+ final class ComponentDispatcher {
+
+ /**
+ * Handle native event that affects component's state or bounds
+ * @param src - the component updated by the event
+ * @param event - the native event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatch(Component src, NativeEvent event) {
+ int id = event.getEventId();
+
+ if ((id == NativeEvent.ID_INSETS_CHANGED)
+ || (id == NativeEvent.ID_THEME_CHANGED)) {
+ return dispatchInsets(event, src);
+ } else if ((id >= WindowEvent.WINDOW_FIRST)
+ && (id <= WindowEvent.WINDOW_LAST)) {
+ return dispatchWindow(event, src);
+ } else {
+ return dispatchPureComponent(event, src);
+ }
+ }
+
+ /**
+ * Handle the change of top-level window's native decorations
+ * @param event - the native event
+ * @param src - the component updated by the event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatchInsets(NativeEvent event, Component src) {
+ //???AWT
+ /*
+ if (src instanceof Window) {
+ ((Window) src).setNativeInsets(event.getInsets());
+ }
+ */
+ return false;
+ }
+
+ /**
+ * Handle the change of top-level window's state
+ * @param event - the native event
+ * @param src - the component updated by the event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatchWindow(NativeEvent event, Component src) {
+ //???AWT
+ /*
+ Window window = (Window) src;
+ int id = event.getEventId();
+
+ if (id == WindowEvent.WINDOW_CLOSING) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
+
+ return true;
+ } else if (id == WindowEvent.WINDOW_STATE_CHANGED) {
+ if (window instanceof Frame) {
+ ((Frame) window)
+ .updateExtendedState(event.getWindowState());
+ }
+ }
+ */
+
+ return false;
+ }
+
+ /**
+ * Handle the change of component's size and/or position
+ * @param event - the native event
+ * @param src - the component updated by the event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ private boolean dispatchPureComponent(NativeEvent event, Component src) {
+ Rectangle rect = event.getWindowRect();
+ Point loc = rect.getLocation();
+ int mask;
+
+ switch (event.getEventId()) {
+ case NativeEvent.ID_BOUNDS_CHANGED:
+ mask = 0;
+ break;
+ case ComponentEvent.COMPONENT_MOVED:
+ mask = NativeWindow.BOUNDS_NOSIZE;
+ break;
+ case ComponentEvent.COMPONENT_RESIZED:
+ mask = NativeWindow.BOUNDS_NOMOVE;
+ break;
+ default:
+ // awt.12E=Unknown component event id.
+ throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$
+ }
+
+ //???AWT
+ /*
+ if (!(src instanceof Window)) {
+ Component compTo = src.getParent();
+ Component compFrom = src.getHWAncestor();
+
+ if ((compTo != null) && (compFrom != null)) {
+ loc = MouseDispatcher.convertPoint(compFrom, loc, compTo);
+ }
+ } else {
+ int windowState = event.getWindowState();
+
+ if ((windowState >= 0) && (src instanceof Frame)) {
+ ((Frame) src).updateExtendedState(windowState);
+ }
+ }
+ src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false);
+ */
+
+ return false;
+ }
+
+ }
+
+ /**
+ * The dispatcher of the keyboard events
+ */
+ final class KeyDispatcher {
+
+ /**
+ * Handle the keyboard event using the KeyboardFocusManager
+ * @param src - the component receiving the event
+ * @param event - the native event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatch(Component src, NativeEvent event) {
+ int id = event.getEventId();
+ int modifiers = event.getInputModifiers();
+ int location = event.getKeyLocation();
+ int code = event.getVKey();
+ StringBuffer chars = event.getKeyChars();
+ int charsLength = chars.length();
+ long time = event.getTime();
+ char keyChar = event.getLastChar();
+
+ //???AWT
+ /*
+ if (src == null) {
+ //retarget focus proxy key events to focusOwner:
+ Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event
+ .getWindowId());
+ if (focusProxyOwner == null) {
+ return false;
+ }
+ src = KeyboardFocusManager.actualFocusOwner;
+ }
+ */
+
+ EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+
+ if (src != null) {
+ eventQueue.postEvent(new KeyEvent(src, id, time, modifiers,
+ code, keyChar, location));
+ // KEY_TYPED goes after KEY_PRESSED
+ if (id == KeyEvent.KEY_PRESSED) {
+ for (int i = 0; i < charsLength; i++) {
+ keyChar = chars.charAt(i);
+ if (keyChar != KeyEvent.CHAR_UNDEFINED) {
+ eventQueue.postEvent(new KeyEvent(src,
+ KeyEvent.KEY_TYPED, time, modifiers,
+ KeyEvent.VK_UNDEFINED, keyChar,
+ KeyEvent.KEY_LOCATION_UNKNOWN));
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ }
+
+ /**
+ * Retargets the mouse events to the grab owner when mouse is grabbed,
+ * grab and ungrab mouse when mouse buttons are pressed and released
+ */
+
+ static final class MouseGrabManager {
+
+ /**
+ * The top-level window holding the mouse grab
+ * that was explicitly started by startGrab() method
+ */
+ //???AWT: private Window nativeGrabOwner = null;
+ /**
+ * The component that owns the synthetic
+ * mouse grab while at least one of the
+ * mouse buttons is pressed
+ */
+ private Component syntheticGrabOwner = null;
+
+ /**
+ * Previous value of syntheticGrabOwner
+ */
+ private Component lastSyntheticGrabOwner = null;
+
+ /**
+ * Number of mouse buttons currently pressed
+ */
+ private int syntheticGrabDepth = 0;
+
+ /**
+ * The callback to be called when the explicit mouse grab ends
+ */
+ private Runnable whenCanceled;
+
+ /**
+ * Explicitly start the mouse grab
+ * @param grabWindow - the window that will own the grab
+ * @param whenCanceled - the callback to call when the grab ends.
+ * This parameter can be null
+ */
+ //???AWT
+ /*
+ void startGrab(Window grabWindow, Runnable whenCanceled) {
+
+ if (nativeGrabOwner != null) {
+ // awt.12F=Attempt to start nested mouse grab
+ throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$
+ }
+
+ NativeWindow win = grabWindow.getNativeWindow();
+ if (win == null) {
+ // awt.130=Attempt to grab mouse in not displayable window
+ throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$
+ }
+
+ nativeGrabOwner = grabWindow;
+ this.whenCanceled = whenCanceled;
+ win.grabMouse();
+ }
+ */
+
+ /**
+ * Ends the explicit mouse grab. If the non-null callback was provided
+ * in the startGrab() method, this callback is called
+ */
+ void endGrab() {
+ //???AWT
+ /*
+ if (nativeGrabOwner == null) {
+ return;
+ }
+
+ Window grabWindow = nativeGrabOwner;
+ nativeGrabOwner = null;
+ NativeWindow win = grabWindow.getNativeWindow();
+
+ if (win != null) {
+ win.ungrabMouse();
+ if (whenCanceled != null) {
+ whenCanceled.run();
+ whenCanceled = null;
+ }
+ }
+ */
+ }
+
+ /**
+ * Ends both explicit and synthetic grans
+ * @return - always returns false
+ */
+ boolean onGrabCanceled() {
+ endGrab();
+ resetSyntheticGrab();
+
+ return false;
+ }
+
+ /**
+ * Starts the synthetic mouse grab, increases the counter
+ * of currently pressed mouse buttons
+ * @param source - the component where mouse press event occured
+ * @return - the component that owns the synthetic grab
+ */
+ Component onMousePressed(Component source) {
+ if (syntheticGrabDepth == 0) {
+ syntheticGrabOwner = source;
+ lastSyntheticGrabOwner = source;
+ }
+ syntheticGrabDepth++;
+
+ return syntheticGrabOwner;
+ }
+
+ /**
+ * Decreases the counter of currently pressed mouse buttons,
+ * ends the synthetic mouse grab, when this counter becomes zero
+ * @param source - the component where mouse press event occured
+ * @return - the component that owns the synthetic grab,
+ * or source parameter if mouse grab was released
+ */
+ Component onMouseReleased(Component source) {
+ Component ret = source;
+
+ //???AWT
+ /*
+ if (syntheticGrabOwner != null && nativeGrabOwner == null) {
+ ret = syntheticGrabOwner;
+ }
+ */
+ syntheticGrabDepth--;
+ if (syntheticGrabDepth <= 0) {
+ resetSyntheticGrab();
+ lastSyntheticGrabOwner = null;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Update the state of synthetic ouse gram
+ * when the mouse is moved/dragged
+ * @param event - the native event
+ */
+ void preprocessEvent(NativeEvent event) {
+ int id = event.getEventId();
+ switch (id) {
+ case MouseEvent.MOUSE_MOVED:
+ if (syntheticGrabOwner != null) {
+ syntheticGrabOwner = null;
+ syntheticGrabDepth = 0;
+ }
+ if (lastSyntheticGrabOwner != null) {
+ lastSyntheticGrabOwner = null;
+ }
+ case MouseEvent.MOUSE_DRAGGED:
+ if (syntheticGrabOwner == null
+ && lastSyntheticGrabOwner != null) {
+ syntheticGrabOwner = lastSyntheticGrabOwner;
+ syntheticGrabDepth = 0;
+ int mask = event.getInputModifiers();
+ syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1
+ : 0;
+ syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1
+ : 0;
+ syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1
+ : 0;
+ }
+ }
+ }
+
+ /**
+ * @return the component that currently owns the synthetic grab
+ */
+ Component getSyntheticGrabOwner() {
+ return syntheticGrabOwner;
+ }
+
+ /**
+ * ends synthetic grab
+ */
+ private void resetSyntheticGrab() {
+ syntheticGrabOwner = null;
+ syntheticGrabDepth = 0;
+ }
+
+ }
+
+ /**
+ * Dispatches native events related to the pop-up boxes
+ * (the non-component windows such as menus and drop lists)
+ */
+// final class PopupDispatcher {
+//
+// private PopupBox activePopup;
+//
+// private PopupBox underCursor;
+//
+// private final MouseGrab grab = new MouseGrab();
+//
+// /**
+// * Handles the mouse grab for pop-up boxes
+// */
+// private final class MouseGrab {
+// private int depth;
+//
+// private PopupBox owner;
+//
+// private final Point start = new Point();
+//
+// /**
+// * Starts the grab when mouse is pressed
+// * @param src - the pop-up box where mouse event has occured
+// * @param where - the mouse pointer location
+// * @return - the grab owner
+// */
+// PopupBox mousePressed(PopupBox src, Point where) {
+// if (depth == 0) {
+// owner = src;
+// start.setLocation(where);
+// }
+// depth++;
+// return owner;
+// }
+//
+// /**
+// * Ends the grab when all mousebuttons are released
+// * @param src - the pop-up box where mouse event has occured
+// * @param where - the mouse pointer location
+// * @return - the grab owner, or src parameter if the grab has ended
+// */
+// PopupBox mouseReleased(PopupBox src, Point where) {
+// PopupBox ret = (owner != null) ? owner : src;
+// if (depth == 0) {
+// return ret;
+// }
+// depth--;
+// if (depth == 0) {
+// PopupBox tgt = owner;
+// owner = null;
+// if (tgt != null && src == null) {
+// Point a = new Point(start);
+// Point b = new Point(where);
+// Point pos = tgt.getScreenLocation();
+// a.translate(-pos.x, -pos.y);
+// b.translate(-pos.x, -pos.y);
+// if (tgt.closeOnUngrab(a, b)) {
+// return null;
+// }
+// }
+// }
+// return ret;
+// }
+//
+// /**
+// * Set the grab owner to null
+// */
+// void reset() {
+// depth = 0;
+// owner = null;
+// start.setLocation(0, 0);
+// }
+//
+// /**
+// * @return - the pop-up box currently owning the grab
+// */
+// public PopupBox getOwner() {
+// return owner;
+// }
+// }
+//
+// /**
+// * Call the mouse event handler of the pop-up box
+// * @param src - the pop-up box where the mouse event occured
+// * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants
+// * @param where - the mouse pointer location
+// * @param event - native event
+// */
+// private void mouseEvent(PopupBox src, int eventId, Point where,
+// NativeEvent event) {
+// Point pos = src.getScreenLocation();
+// pos.setLocation(where.x - pos.x, where.y - pos.y);
+//
+// src.onMouseEvent(eventId, pos, event.getMouseButton(), event
+// .getTime(), event.getInputModifiers(), event
+// .getWheelRotation());
+// }
+//
+// /**
+// * Handle the native event targeted by a pop-up box. This could be
+// * paint event, mouse or keyboard event.
+// * @param event - the native event
+// * @return - false if the event was handled and doesn't
+// * need the further processing; true when the further
+// * processing is needed
+// */
+// boolean onEvent(NativeEvent event) {
+// PopupBox src = toolkit.getPopupBoxById(event.getWindowId());
+// int id = event.getEventId();
+//
+// if ((id == PaintEvent.PAINT)) {
+// if (src != null) {
+// src.paint(event.getClipRects());
+// return true;
+// }
+// Component c = toolkit.getComponentById(event.getWindowId());
+// if ((c != null) && (c instanceof Frame)) {
+// ((Frame) c).paintMenuBar(event.getClipRects());
+// }
+// return false;
+// }
+//
+// if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) {
+// Point where = event.getScreenPos();
+//
+// if (src != underCursor) {
+// if (underCursor != null) {
+// mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where,
+// event);
+// }
+// underCursor = src;
+// if (underCursor != null) {
+// mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED,
+// where, event);
+// underCursor.setDefaultCursor();
+// }
+// }
+// if (id == MouseEvent.MOUSE_EXITED) {
+// underCursor = null;
+// }
+//
+// if ((activePopup == null) && (src == null || !src.isMenuBar())) {
+// return false;
+// }
+//
+// if (id == MouseEvent.MOUSE_PRESSED) {
+// src = grab.mousePressed(src, where);
+// } else if (id == MouseEvent.MOUSE_RELEASED) {
+// src = grab.mouseReleased(src, where);
+// } else if (src == null) {
+// src = grab.getOwner();
+// }
+//
+// PopupBox wasActive = activePopup;
+//
+// if (src != null) {
+// mouseEvent(src, id, where, event);
+// return src.isMenu() || src.contains(where);
+// }
+//
+// if (wasActive != null && activePopup == null) {
+// return wasActive.isMenu();
+// }
+//
+// if ((id == MouseEvent.MOUSE_PRESSED)
+// || (id == MouseEvent.MOUSE_RELEASED)) {
+// boolean isMenu = activePopup.isMenu();
+// deactivateAll();
+// return !isMenu;
+// }
+// return true;
+// }
+//
+// if (activePopup == null) {
+// return false;
+// }
+//
+// if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) {
+// boolean isMenu = activePopup.isMenu();
+// activePopup.dispatchKeyEvent(id, event.getVKey(), event
+// .getTime(), event.getInputModifiers());
+//
+// return isMenu;
+// }
+//
+// return false;
+// }
+//
+// /**
+// * Remember the pop-up as active and grab the mouse on it
+// * @param popup - the pop-up box to activate
+// */
+// void activate(final PopupBox popup) {
+// if (activePopup == null) {
+//
+// activePopup = popup;
+// mouseGrabManager.startGrab(popup.getOwner(), new Runnable() {
+// public void run() {
+// deactivate(popup);
+// }
+// });
+// }
+// }
+//
+// /**
+// * Deactivate the currently active pop-up box
+// */
+// void deactivateAll() {
+// deactivate(activePopup);
+// }
+//
+// /**
+// * Deactivate the pop-up box, end the mouse grab
+// */
+// void deactivate(PopupBox popup) {
+// grab.reset();
+//
+// if (activePopup != null && activePopup == popup) {
+// activePopup = null;
+// mouseGrabManager.endGrab();
+// popup.hide();
+// underCursor = null;
+// }
+// }
+//
+// /**
+// * Check that the pop-up box is currently active
+// * @param popup - the pop-up box to check
+// * @return - true if active
+// */
+// boolean isActive(PopupBox popup) {
+// return (popup == activePopup) && (popup != null);
+// }
+// }
+
+} \ No newline at end of file
diff --git a/awt/java/awt/DisplayMode.java b/awt/java/awt/DisplayMode.java
new file mode 100644
index 0000000..082c7b8
--- /dev/null
+++ b/awt/java/awt/DisplayMode.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The DisplayMode class containes the bit depth, height, width and
+ * refresh rate of a GraphicsDevice.
+ */
+public final class DisplayMode {
+
+ /** The width. */
+ private final int width;
+
+ /** The height. */
+ private final int height;
+
+ /** The bit depth. */
+ private final int bitDepth;
+
+ /** The refresh rate. */
+ private final int refreshRate;
+
+ /** The Constant Value BIT_DEPTH_MULTI indicates the bit depth */
+
+ public static final int BIT_DEPTH_MULTI = -1;
+
+ /** The Constant REFRESH_RATE_UNKNOWN indicates the refresh rate. */
+ public static final int REFRESH_RATE_UNKNOWN = 0;
+
+ /**
+ * Creates a new DisplayMode object with the specified parameters.
+ *
+ * @param width the width of the display.
+ * @param height the height of the display.
+ * @param bitDepth the bit depth of the display.
+ * @param refreshRate the refresh rate of the display.
+ */
+
+ public DisplayMode(int width, int height, int bitDepth, int refreshRate) {
+ this.width = width;
+ this.height = height;
+ this.bitDepth = bitDepth;
+ this.refreshRate = refreshRate;
+ }
+
+
+ /**
+ * Compares if this DisplayMode is equal to the specified object or not.
+ *
+ * @param dm the Object to be compared.
+ *
+ * @return true, if the specified object is a DisplayMode with the same
+ * data values as this DisplayMode, false otherwise.
+ */
+
+ @Override
+ public boolean equals(Object dm) {
+ if (dm instanceof DisplayMode) {
+ return equals((DisplayMode)dm);
+ }
+ return false;
+ }
+
+ /**
+ * Compares if this DisplayMode is equal to the specified DisplayMode object
+ * or not.
+ *
+ * @param dm the DisplayMode to be compared.
+ *
+ * @return true, if all of the data values of this DisplayMode are equal
+ * to the values of the specified DisplayMode object, false otherwise.
+ */
+ public boolean equals(DisplayMode dm) {
+ if (dm == null) {
+ return false;
+ }
+ if (dm.bitDepth != bitDepth) {
+ return false;
+ }
+ if (dm.refreshRate != refreshRate) {
+ return false;
+ }
+ if (dm.width != width) {
+ return false;
+ }
+ if (dm.height != height) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Gets the bit depth of the DisplayMode, returns BIT_DEPTH_MULTI value
+ * if multiple bit depths are supported in this display mode.
+ *
+ * @return the bit depth of the DisplayMode.
+ */
+ public int getBitDepth() {
+ return bitDepth;
+ }
+
+ /**
+ * Gets the height of the DisplayMode.
+ *
+ * @return the height of the DisplayMode.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the refresh rate of the DisplayMode, returns REFRESH_RATE_UNKNOWN
+ * value if the information is not available.
+ *
+ * @return the refresh rate of the DisplayMode.
+ */
+ public int getRefreshRate() {
+ return refreshRate;
+ }
+
+ /**
+ * Gets the width of the DisplayMode.
+ *
+ * @return the width of the DisplayMode.
+ */
+ public int getWidth() {
+ return width;
+ }
+}
diff --git a/awt/java/awt/Event.java b/awt/java/awt/Event.java
new file mode 100644
index 0000000..f074258
--- /dev/null
+++ b/awt/java/awt/Event.java
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.Serializable;
+
+/**
+ * The Event Class is obsolete and has been replaced by AWTEvent class.
+ *
+ */
+public class Event implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 5488922509400504703L;
+
+ /**
+ * The Constant SHIFT_MASK indicates that the Shift key is down when
+ * the event occurred.
+ */
+ public static final int SHIFT_MASK = 1;
+
+ /**
+ * The Constant CTRL_MASK indicates that the Control key is down when
+ * the event occurred.
+ */
+ public static final int CTRL_MASK = 2;
+
+ /** The Constant META_MASK indicates that the Meta key is down when t
+ * he event occurred (or the right mouse button). */
+ public static final int META_MASK = 4;
+
+ /**
+ * The Constant ALT_MASK indicates that the Alt key is down when
+ * the event occurred (or the middle mouse button).
+ */
+ public static final int ALT_MASK = 8;
+
+ /** The Constant HOME indicates Home key. */
+ public static final int HOME = 1000;
+
+ /** The Constant END indicates End key. */
+ public static final int END = 1001;
+
+ /** The Constant PGUP indicates Page Up key. */
+ public static final int PGUP = 1002;
+
+ /** The Constant PGDN indicates Page Down key. */
+ public static final int PGDN = 1003;
+
+ /** The Constant UP indicates Up key. */
+ public static final int UP = 1004;
+
+ /** The Constant DOWN indicates Down key. */
+ public static final int DOWN = 1005;
+
+ /** The Constant LEFT indicates Left key. */
+ public static final int LEFT = 1006;
+
+ /** The Constant RIGHT indicates Right key. */
+ public static final int RIGHT = 1007;
+
+ /** The Constant F1 indicates F1 key. */
+ public static final int F1 = 1008;
+
+ /** The Constant F2 indicates F2 key. */
+ public static final int F2 = 1009;
+
+ /** The Constant F3 indicates F3 key. */
+ public static final int F3 = 1010;
+
+ /** The Constant F4 indicates F4 key. */
+ public static final int F4 = 1011;
+
+ /** The Constant F5 indicates F5 key. */
+ public static final int F5 = 1012;
+
+ /** The Constant F6 indicates F6 key. */
+ public static final int F6 = 1013;
+
+ /** The Constant F7 indicates F7 key. */
+ public static final int F7 = 1014;
+
+ /** The Constant F8 indicates F8 key. */
+ public static final int F8 = 1015;
+
+ /** The Constant F9 indicates F9 key. */
+ public static final int F9 = 1016;
+
+ /** The Constant F10 indicates F10 key. */
+ public static final int F10 = 1017;
+
+ /** The Constant F11 indicates F11 key. */
+ public static final int F11 = 1018;
+
+ /** The Constant F12 indicates F12 key. */
+ public static final int F12 = 1019;
+
+ /** The Constant PRINT_SCREEN indicates Print Screen key. */
+ public static final int PRINT_SCREEN = 1020;
+
+ /** The Constant SCROLL_LOCK indicates Scroll Lock key. */
+ public static final int SCROLL_LOCK = 1021;
+
+ /** The Constant CAPS_LOCK indicates Caps Lock key. */
+ public static final int CAPS_LOCK = 1022;
+
+ /** The Constant NUM_LOCK indicates Num Lock key. */
+ public static final int NUM_LOCK = 1023;
+
+ /** The Constant PAUSE indicates Pause key. */
+ public static final int PAUSE = 1024;
+
+ /** The Constant INSERT indicates Insert key. */
+ public static final int INSERT = 1025;
+
+ /** The Constant ENTER indicates Enter key. */
+ public static final int ENTER = 10;
+
+ /** The Constant BACK_SPACE indicates Back Space key. */
+ public static final int BACK_SPACE = 8;
+
+ /** The Constant TAB indicates TAb key. */
+ public static final int TAB = 9;
+
+ /** The Constant ESCAPE indicates Escape key. */
+ public static final int ESCAPE = 27;
+
+ /** The Constant DELETE indicates Delete key. */
+ public static final int DELETE = 127;
+
+ /**
+ * The Constant WINDOW_DESTROY indicates an event when the user has asked the
+ * window manager to kill the window.
+ */
+ public static final int WINDOW_DESTROY = 201;
+
+ /**
+ * The Constant WINDOW_EXPOSE indicates an event when the user has asked the
+ * window manager to expose the window.
+ */
+ public static final int WINDOW_EXPOSE = 202;
+
+ /**
+ * The Constant WINDOW_ICONIFY indicates an event when the user has asked the
+ * window manager to inconify the window.
+ */
+ public static final int WINDOW_ICONIFY = 203;
+
+ /**
+ * The Constant WINDOW_DEICONIFY indicates an event when the user has asked the
+ * window manager to deinconify the window.
+ */
+ public static final int WINDOW_DEICONIFY = 204;
+
+ /**
+ * The Constant WINDOW_MOVED indicates an event when the user has asked the
+ * window manager to move the window.
+ */
+ public static final int WINDOW_MOVED = 205;
+
+ /**
+ * The Constant KEY_PRESS indicates an event when the user presses
+ * a normal key.
+ */
+ public static final int KEY_PRESS = 401;
+
+ /**
+ * The Constant KEY_RELEASE indicates an event when the user releases
+ * a normal key.
+ */
+ public static final int KEY_RELEASE = 402;
+
+ /**
+ * The Constant KEY_ACTION indicates an event when the user pressed
+ * a non-ASCII action key.
+ */
+ public static final int KEY_ACTION = 403;
+
+ /**
+ * The Constant KEY_ACTION_RELEASE indicates an event when the user released
+ * a non-ASCII action key.
+ */
+ public static final int KEY_ACTION_RELEASE = 404;
+
+ /**
+ * The Constant MOUSE_DOWN indicates an event when the user has pressed
+ * the mouse button.
+ */
+ public static final int MOUSE_DOWN = 501;
+
+ /**
+ * The Constant MOUSE_UP indicates an event when the user has released
+ * the mouse button.
+ */
+ public static final int MOUSE_UP = 502;
+
+ /**
+ * The Constant MOUSE_MOVE indicates an event when the user has moved
+ * the mouse with no button pressed.
+ */
+ public static final int MOUSE_MOVE = 503;
+
+ /**
+ * The Constant MOUSE_ENTER indicates an event when the mouse
+ * has entered a component.
+ */
+ public static final int MOUSE_ENTER = 504;
+
+ /**
+ * The Constant MOUSE_EXIT indicates an event when the mouse
+ * has exited a component.
+ */
+ public static final int MOUSE_EXIT = 505;
+
+ /** The Constant MOUSE_DRAG indicates an event when the user
+ * has moved a mouse with the pressed button.
+ */
+ public static final int MOUSE_DRAG = 506;
+
+ /**
+ * The Constant SCROLL_LINE_UP indicates an event when the user has
+ * activated line-up area of scrollbar.
+ */
+ public static final int SCROLL_LINE_UP = 601;
+
+ /**
+ * The Constant SCROLL_LINE_DOWN indicates an event when the user has
+ * activated line-down area of scrollbar.
+ */
+ public static final int SCROLL_LINE_DOWN = 602;
+
+ /**
+ * The Constant SCROLL_PAGE_UP indicates an event when the user has
+ * activated page up area of scrollbar.
+ */
+ public static final int SCROLL_PAGE_UP = 603;
+
+ /**
+ * The Constant SCROLL_PAGE_DOWN indicates an event when the user has
+ * activated page down area of scrollbar.
+ */
+ public static final int SCROLL_PAGE_DOWN = 604;
+
+ /**
+ * The Constant SCROLL_ABSOLUTE indicates an event when the user
+ * has moved the bubble in a scroll bar.
+ */
+ public static final int SCROLL_ABSOLUTE = 605;
+
+ /** The Constant SCROLL_BEGIN indicates a scroll begin event. */
+ public static final int SCROLL_BEGIN = 606;
+
+ /** The Constant SCROLL_END indicates a scroll end event. */
+ public static final int SCROLL_END = 607;
+
+ /**
+ * The Constant LIST_SELECT indicates that an item in a list
+ * has been selected.
+ */
+ public static final int LIST_SELECT = 701;
+
+ /**
+ * The Constant LIST_DESELECT indicates that an item in a list
+ * has been deselected.
+ */
+ public static final int LIST_DESELECT = 702;
+
+ /**
+ * The Constant ACTION_EVENT indicates that the user wants some
+ * action to occur.
+ */
+ public static final int ACTION_EVENT = 1001;
+
+ /** The Constant LOAD_FILE indicates a file loading event. */
+ public static final int LOAD_FILE = 1002;
+
+ /** The Constant SAVE_FILE indicates a file saving event. */
+ public static final int SAVE_FILE = 1003;
+
+ /** The Constant GOT_FOCUS indicates that a component got the focus. */
+ public static final int GOT_FOCUS = 1004;
+
+ /** The Constant LOST_FOCUS indicates that the component lost the focus. */
+ public static final int LOST_FOCUS = 1005;
+
+ /** The target is the component with which the event is associated. */
+ public Object target;
+
+ /** The when is timestamp when event has occured. */
+ public long when;
+
+ /** The id indicates the type of the event. */
+ public int id;
+
+ /** The x coordinate of event. */
+ public int x;
+
+ /** The y coordinate of event. */
+ public int y;
+
+ /** The key code of key event. */
+ public int key;
+
+ /** The state of the modifier keys (given by a bitmask). */
+ public int modifiers;
+
+ /** The click count indicates the number of consecutive clicks. */
+ public int clickCount;
+
+ /** The argument of the event. */
+ public Object arg;
+
+ /** The next event. */
+ public Event evt;
+
+ /**
+ * Instantiates a new event with the specified target component,
+ * event type, and argument.
+ *
+ * @param target the target component.
+ * @param id the event type.
+ * @param arg the argument.
+ */
+ public Event(Object target, int id, Object arg) {
+ this(target, 0l, id, 0, 0, 0, 0, arg);
+ }
+
+ /**
+ * Instantiates a new event with the specified target component, time stamp,
+ * event type, x and y coordinates, keyboard key, state of the modifier
+ * keys, and an argument set to null.
+ *
+ * @param target the target component.
+ * @param when the time stamp.
+ * @param id the event type.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param key the key.
+ * @param modifiers the modifier keys state.
+ */
+ public Event(Object target, long when, int id, int x, int y, int key, int modifiers) {
+ this(target, when, id, x, y, key, modifiers, null);
+ }
+
+ /**
+ * Instantiates a new event with the specified target component, time stamp,
+ * event type, x and y coordinates, keyboard key, state of the modifier
+ * keys, and an argument.
+ *
+ * @param target the target component.
+ * @param when the time stamp.
+ * @param id the event type.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param key the key.
+ * @param modifiers the modifier keys state.
+ * @param arg the specified argument.
+ */
+ public Event(Object target, long when, int id, int x, int y, int key, int modifiers, Object arg) {
+ this.target = target;
+ this.when = when;
+ this.id = id;
+ this.x = x;
+ this.y = y;
+ this.key = key;
+ this.modifiers = modifiers;
+ this.arg = arg;
+ }
+
+ /**
+ * Returns a string representation of this Event.
+ *
+ * @return a string representation of this Event.
+ */
+ @Override
+ public String toString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * Event e = new Event(new Button(), 0l, Event.KEY_PRESS,
+ * 0, 0, Event.TAB, Event.SHIFT_MASK, "arg");
+ * System.out.println(e);
+ */
+
+ return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns a string representing the state of this Event.
+ *
+ * @return a string representing the state of this Event.
+ */
+ protected String paramString() {
+ return "id=" + id + ",x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",target=" + target + //$NON-NLS-1$
+ (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Gets a string representation of the modifiers.
+ *
+ * @return a string representation of the modifiers
+ */
+ private String getModifiersString() {
+ String strMod = ""; //$NON-NLS-1$
+ if (shiftDown()) {
+ strMod += ",shift"; //$NON-NLS-1$
+ }
+ if (controlDown()) {
+ strMod += ",control"; //$NON-NLS-1$
+ }
+ if (metaDown()) {
+ strMod += ",meta"; //$NON-NLS-1$
+ }
+ return strMod;
+ }
+
+ /**
+ * Translates x and y coordinates of his event to the x+dx and x+dy
+ * coordinates.
+ *
+ * @param dx the dx - the distance by which the event's x coordinate
+ * is increased
+ * @param dy the dy - the distance by which the event's y coordinate
+ * is increased
+ */
+ public void translate(int dx, int dy) {
+ x += dx;
+ y += dy;
+ }
+
+ /**
+ * Checks if Control key is down or not.
+ *
+ * @return true, if Control key is down; false otherwise.
+ */
+ public boolean controlDown() {
+ return (modifiers & CTRL_MASK) != 0;
+ }
+
+ /**
+ * Checks if Meta key is down or not.
+ *
+ * @return true, if Meta key is down; false otherwise.
+ */
+ public boolean metaDown() {
+ return (modifiers & META_MASK) != 0;
+ }
+
+ /**
+ * Checks if Shift key is down or not.
+ *
+ * @return true, if Shift key is down; false otherwise.
+ */
+ public boolean shiftDown() {
+ return (modifiers & SHIFT_MASK) != 0;
+ }
+
+}
+
diff --git a/awt/java/awt/EventDispatchThread.java b/awt/java/awt/EventDispatchThread.java
new file mode 100644
index 0000000..442c8a2
--- /dev/null
+++ b/awt/java/awt/EventDispatchThread.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+
+class EventDispatchThread extends Thread {
+
+ private static final class MarkerEvent extends AWTEvent {
+ MarkerEvent(Object source, int id) {
+ super(source, id);
+ }
+ }
+
+ final Dispatcher dispatcher;
+ final Toolkit toolkit;
+ private NativeEventQueue nativeQueue;
+
+ protected volatile boolean shutdownPending = false;
+
+ /**
+ * Initialise and run the main event loop
+ */
+ @Override
+ public void run() {
+ nativeQueue = toolkit.getNativeEventQueue();
+
+ try {
+ runModalLoop(null);
+ } finally {
+ toolkit.shutdownWatchdog.forceShutdown();
+ }
+ }
+
+ void runModalLoop(ModalContext context) {
+ long lastPaintTime = System.currentTimeMillis();
+ while (!shutdownPending && (context == null || context.isModalLoopRunning())) {
+ try {
+ EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+
+ NativeEvent ne = nativeQueue.getNextEvent();
+ if (ne != null) {
+ dispatcher.onEvent(ne);
+ MarkerEvent marker = new MarkerEvent(this, 0);
+ eventQueue.postEvent(marker);
+ for (AWTEvent ae = eventQueue.getNextEventNoWait();
+ (ae != null) && (ae != marker);
+ ae = eventQueue.getNextEventNoWait()) {
+ eventQueue.dispatchEvent(ae);
+ }
+ } else {
+ toolkit.shutdownWatchdog.setNativeQueueEmpty(true);
+ AWTEvent ae = eventQueue.getNextEventNoWait();
+ if (ae != null) {
+ eventQueue.dispatchEvent(ae);
+ long curTime = System.currentTimeMillis();
+ if (curTime - lastPaintTime > 10) {
+ toolkit.onQueueEmpty();
+ lastPaintTime = System.currentTimeMillis();
+ }
+ } else {
+ toolkit.shutdownWatchdog.setAwtQueueEmpty(true);
+ toolkit.onQueueEmpty();
+ lastPaintTime = System.currentTimeMillis();
+ waitForAnyEvent();
+ }
+ }
+ } catch (Throwable t) {
+ // TODO: Exception handler should be implemented
+ // t.printStackTrace();
+ }
+ }
+ }
+
+ private void waitForAnyEvent() {
+ EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+ if (!eventQueue.isEmpty() || !nativeQueue.isEmpty()) {
+ return;
+ }
+ Object eventMonitor = nativeQueue.getEventMonitor();
+ synchronized(eventMonitor) {
+ try {
+ eventMonitor.wait();
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ void shutdown() {
+ shutdownPending = true;
+ }
+
+ EventDispatchThread(Toolkit toolkit, Dispatcher dispatcher ) {
+ this.toolkit = toolkit;
+ this.dispatcher = dispatcher;
+ setName("AWT-EventDispatchThread"); //$NON-NLS-1$
+ setDaemon(true);
+ }
+
+}
diff --git a/awt/java/awt/EventQueue.java b/awt/java/awt/EventQueue.java
new file mode 100644
index 0000000..3997546
--- /dev/null
+++ b/awt/java/awt/EventQueue.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.InvocationEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.util.EmptyStackException;
+
+/**
+ * The EventQueue class manages events. It is a platform-independent class
+ * that queues events both from the underlying peer classes and from trusted
+ * application classes.
+ */
+public class EventQueue {
+
+ /** The core ref. */
+ private final EventQueueCoreAtomicReference coreRef =
+ new EventQueueCoreAtomicReference();
+
+ /**
+ * The Class EventQueueCoreAtomicReference.
+ */
+ private static final class EventQueueCoreAtomicReference {
+
+ /** The core. */
+ private EventQueueCore core;
+
+ /*synchronized*/ /**
+ * Gets the.
+ *
+ * @return the event queue core
+ */
+ EventQueueCore get() {
+ return core;
+ }
+
+ /*synchronized*/ /**
+ * Sets the.
+ *
+ * @param newCore the new core
+ */
+ void set(EventQueueCore newCore) {
+ core = newCore;
+ }
+ }
+
+ /**
+ * Returns true if the calling thread is the current
+ * AWT EventQueue's dispatch thread.
+ *
+ * @return true, if the calling thread is the current
+ * AWT EventQueue's dispatch thread; false otherwise.
+ */
+ public static boolean isDispatchThread() {
+ return Thread.currentThread() instanceof EventDispatchThread;
+ }
+
+ /**
+ * Posts an InvocationEvent which executes the run() method on a Runnable
+ * when dispatched by the AWT event dispatcher thread.
+ *
+ * @param runnable the Runnable whose run method should be executed
+ * synchronously on the EventQueue.
+ */
+ public static void invokeLater(Runnable runnable) {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ InvocationEvent event = new InvocationEvent(toolkit, runnable);
+ toolkit.getSystemEventQueueImpl().postEvent(event);
+ }
+
+ /**
+ * Posts an InvocationEvent which executes the run() method on a Runnable
+ * when dispatched by the AWT event dispatcher thread and the
+ * notifyAll method is called on it immediately after run returns.
+ *
+ * @param runnable the Runnable whose run method should be executed
+ * synchronously on the EventQueue.
+ *
+ * @throws InterruptedException if another thread has interrupted
+ * this thread.
+ * @throws InvocationTargetException if a throwable is thrown
+ * when running the runnable.
+ */
+ public static void invokeAndWait(Runnable runnable)
+ throws InterruptedException, InvocationTargetException {
+
+ if (isDispatchThread()) {
+ throw new Error();
+ }
+
+ final Toolkit toolkit = Toolkit.getDefaultToolkit();
+ final Object notifier = new Object(); //$NON-LOCK-1$
+ InvocationEvent event = new InvocationEvent(
+ toolkit, runnable, notifier, true);
+
+ synchronized (notifier) {
+ toolkit.getSystemEventQueueImpl().postEvent(event);
+ notifier.wait();
+ }
+
+ Exception exception = event.getException();
+
+ if (exception != null) {
+ throw new InvocationTargetException(exception);
+ }
+ }
+
+ /**
+ * Gets the system event queue.
+ *
+ * @return the system event queue
+ */
+ private static EventQueue getSystemEventQueue() {
+ Thread th = Thread.currentThread();
+ if (th instanceof EventDispatchThread) {
+ return ((EventDispatchThread)th).toolkit.getSystemEventQueueImpl();
+ }
+ return null;
+ }
+
+ /**
+ * Gets the most recent event's timestamp.
+ * This event was dispatched from the EventQueue associated with the
+ * calling thread.
+ *
+ * @return the timestamp of the last Event to be dispatched,
+ * or System.currentTimeMillis() if this method is invoked from
+ * a thread other than an event-dispatching thread.
+ */
+ public static long getMostRecentEventTime() {
+ EventQueue eq = getSystemEventQueue();
+ return (eq != null) ?
+ eq.getMostRecentEventTimeImpl() : System.currentTimeMillis();
+ }
+
+ /**
+ * Gets the most recent event time impl.
+ *
+ * @return the most recent event time impl
+ */
+ private long getMostRecentEventTimeImpl() {
+ return getCore().getMostRecentEventTime();
+ }
+
+ /**
+ * Returns the the currently dispatched event by the EventQueue
+ * associated with the calling thread.
+ *
+ * @return the currently dispatched event or null if this method
+ * is invoked from a thread other than an event-dispatching thread.
+ */
+ public static AWTEvent getCurrentEvent() {
+ EventQueue eq = getSystemEventQueue();
+ return (eq != null) ?
+ eq.getCurrentEventImpl() : null;
+ }
+
+ /**
+ * Gets the current event impl.
+ *
+ * @return the current event impl
+ */
+ private AWTEvent getCurrentEventImpl() {
+ return getCore().getCurrentEvent();
+ }
+
+ /**
+ * Instantiates a new event queue.
+ */
+ public EventQueue() {
+ setCore(new EventQueueCore(this));
+ }
+
+ /**
+ * Instantiates a new event queue.
+ *
+ * @param t the t
+ */
+ EventQueue(Toolkit t) {
+ setCore(new EventQueueCore(this, t));
+ }
+
+ /**
+ * Posts a event to the EventQueue.
+ *
+ * @param event AWTEvent.
+ */
+ public void postEvent(AWTEvent event) {
+ event.isPosted = true;
+ getCore().postEvent(event);
+ }
+
+ /**
+ * Returns an event from the EventQueue and removes it from this queue.
+ *
+ * @return the next AWTEvent.
+ *
+ * @throws InterruptedException is thrown if another thread
+ * interrupts this thread.
+ */
+ public AWTEvent getNextEvent() throws InterruptedException {
+ return getCore().getNextEvent();
+ }
+
+ /**
+ * Gets the next event no wait.
+ *
+ * @return the next event no wait
+ */
+ AWTEvent getNextEventNoWait() {
+ return getCore().getNextEventNoWait();
+ }
+
+ /**
+ * Returns the first event of the EventQueue (without removing it
+ * from the queue).
+ *
+ * @return the the first AWT event of the EventQueue.
+ */
+ public AWTEvent peekEvent() {
+ return getCore().peekEvent();
+ }
+
+ /**
+ * Returns the first event of the EventQueue with the specified ID
+ * (without removing it from the queue).
+ *
+ * @param id the type ID of event.
+ *
+ * @return the first event of the EventQueue with the specified ID.
+ */
+ public AWTEvent peekEvent(int id) {
+ return getCore().peekEvent(id);
+ }
+
+ /**
+ * Replaces the existing EventQueue with the specified EventQueue.
+ * Any pending events are transferred to the new EventQueue.
+ *
+ * @param newEventQueue the new event queue.
+ */
+ public void push(EventQueue newEventQueue) {
+ getCore().push(newEventQueue);
+ }
+
+ /**
+ * Stops dispatching events using this EventQueue.
+ * Any pending events are transferred to the previous EventQueue.
+ *
+ * @throws EmptyStackException is thrown if no previous push
+ * was made on this EventQueue.
+ */
+ protected void pop() throws EmptyStackException {
+ getCore().pop();
+ }
+
+ /**
+ * Dispatches the specified event.
+ *
+ * @param event the AWTEvent.
+ */
+ protected void dispatchEvent(AWTEvent event) {
+ getCore().dispatchEventImpl(event);
+ }
+
+ /**
+ * Checks if the queue is empty.
+ *
+ * @return true, if is empty
+ */
+ boolean isEmpty() {
+ return getCore().isEmpty();
+ }
+
+ /**
+ * Gets the core.
+ *
+ * @return the core
+ */
+ EventQueueCore getCore() {
+ return coreRef.get();
+ }
+
+ /**
+ * Sets the core.
+ *
+ * @param newCore the new core
+ */
+ void setCore(EventQueueCore newCore) {
+ coreRef.set((newCore != null) ? newCore : new EventQueueCore(this));
+ }
+}
diff --git a/awt/java/awt/EventQueueCore.java b/awt/java/awt/EventQueueCore.java
new file mode 100644
index 0000000..ffc7c46
--- /dev/null
+++ b/awt/java/awt/EventQueueCore.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InvocationEvent;
+import java.awt.event.MouseEvent;
+import java.util.LinkedList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The events storage for EventQueue
+ */
+final class EventQueueCore {
+
+ private final LinkedList<EventQueue> queueStack = new LinkedList<EventQueue>();
+ private final LinkedList<AWTEvent> events = new LinkedList<AWTEvent>();
+
+ private Toolkit toolkit;
+ private EventQueue activeQueue;
+ private Thread dispatchThread;
+
+ AWTEvent currentEvent;
+ long mostRecentEventTime = System.currentTimeMillis();
+
+ EventQueueCore(EventQueue eq) {
+ synchronized (this) {
+ queueStack.addLast(eq);
+ activeQueue = eq;
+ }
+ }
+
+ EventQueueCore(EventQueue eq, Toolkit t) {
+ synchronized (this) {
+ queueStack.addLast(eq);
+ activeQueue = eq;
+ setToolkit(t);
+ }
+ }
+
+ synchronized long getMostRecentEventTime() {
+ return mostRecentEventTime;
+ }
+
+ synchronized AWTEvent getCurrentEvent() {
+ return currentEvent;
+ }
+
+ synchronized boolean isSystemEventQueue() {
+ return toolkit != null;
+ }
+
+ private void setToolkit(Toolkit t) {
+ toolkit = t;
+ if (toolkit != null) {
+ toolkit.setSystemEventQueueCore(this);
+ dispatchThread = toolkit.dispatchThread;
+ }
+ }
+
+ synchronized void postEvent(AWTEvent event) {
+ //???AWT
+ /*
+ events.addLast(event);
+ if ((toolkit == null) && (dispatchThread == null)) {
+ dispatchThread = new EventQueueThread(this);
+ dispatchThread.start();
+ }
+ // TODO: add event coalescing
+ if (toolkit != null) {
+ toolkit.shutdownWatchdog.setAwtQueueEmpty(false);
+ if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) {
+ notifyEventMonitor(toolkit);
+ }
+ }
+ notifyAll();
+ */
+ }
+
+ void notifyEventMonitor(Toolkit t) {
+ Object em = t.getNativeEventQueue().getEventMonitor();
+ synchronized (em) {
+ em.notifyAll();
+ }
+ }
+
+ synchronized AWTEvent getNextEvent() throws InterruptedException {
+ while (events.isEmpty()) {
+ wait();
+ }
+ AWTEvent event = events.removeFirst();
+ // TODO: add event coalescing
+ return event;
+ }
+
+ synchronized AWTEvent peekEvent() {
+ return events.isEmpty() ? null : events.getFirst();
+ }
+
+ synchronized AWTEvent peekEvent(int id) {
+ for (AWTEvent event : events) {
+ if (event.getID() == id) {
+ return event;
+ }
+ }
+ return null;
+ }
+
+ synchronized void dispatchEvent(AWTEvent event) {
+ updateCurrentEventAndTime(event);
+ try {
+ activeQueue.dispatchEvent(event);
+ } finally {
+ currentEvent = null;
+ }
+ }
+
+ void dispatchEventImpl(AWTEvent event) {
+ if (event instanceof ActiveEvent) {
+ updateCurrentEventAndTime(event);
+ try {
+ ((ActiveEvent) event).dispatch();
+ } finally {
+ currentEvent = null;
+ }
+ return;
+ }
+
+ Object src = event.getSource();
+
+ if (src instanceof Component) {
+ if (preprocessComponentEvent(event)) {
+ ((Component) src).dispatchEvent(event);
+ }
+ } else {
+ if (toolkit != null) {
+ toolkit.dispatchAWTEvent(event);
+ }
+ if (src instanceof MenuComponent) {
+ ((MenuComponent) src).dispatchEvent(event);
+ }
+ }
+ }
+
+ private final boolean preprocessComponentEvent(AWTEvent event) {
+ if (event instanceof MouseEvent) {
+ return preprocessMouseEvent((MouseEvent)event);
+ }
+ return true;
+ }
+
+ private final boolean preprocessMouseEvent(MouseEvent event) {
+ //???AWT
+ /*
+ if (toolkit != null && toolkit.mouseEventPreprocessor != null) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.mouseEventPreprocessor.preprocess(event);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ return true;
+ */
+ return true;
+ }
+
+ private void updateCurrentEventAndTime(AWTEvent event) {
+ currentEvent = event;
+ long when = 0;
+ if (event instanceof ActionEvent) {
+ when = ((ActionEvent) event).getWhen();
+ } else if (event instanceof InputEvent) {
+ when = ((InputEvent) event).getWhen();
+ } else if (event instanceof InputMethodEvent) {
+ when = ((InputMethodEvent) event).getWhen();
+ } else if (event instanceof InvocationEvent) {
+ when = ((InvocationEvent) event).getWhen();
+ }
+ if (when != 0) {
+ mostRecentEventTime = when;
+ }
+ }
+
+ synchronized void push(EventQueue newEventQueue) {
+ // TODO: handle incorrect situations
+ if (queueStack.isEmpty()) {
+ // awt.6B=Queue stack is empty
+ throw new IllegalStateException(Messages.getString("awt.6B")); //$NON-NLS-1$
+ }
+
+ queueStack.addLast(newEventQueue);
+ activeQueue = newEventQueue;
+ activeQueue.setCore(this);
+ }
+
+ synchronized void pop() {
+ EventQueue removed = queueStack.removeLast();
+ if (removed != activeQueue) {
+ // awt.6C=Event queue stack is broken
+ throw new IllegalStateException(Messages.getString("awt.6C")); //$NON-NLS-1$
+ }
+ activeQueue = queueStack.getLast();
+ removed.setCore(null);
+ }
+
+ synchronized AWTEvent getNextEventNoWait() {
+ try {
+ return events.isEmpty() ? null : activeQueue.getNextEvent();
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
+ synchronized boolean isEmpty() {
+ return (currentEvent == null) && events.isEmpty();
+ }
+
+ synchronized boolean isEmpty(long timeout) {
+ if (!isEmpty()) {
+ return false;
+ }
+ try {
+ wait(timeout);
+ } catch (InterruptedException e) {}
+ return isEmpty();
+ }
+
+ synchronized EventQueue getActiveEventQueue() {
+ return activeQueue;
+ }
+}
diff --git a/awt/java/awt/Font.java b/awt/java/awt/Font.java
new file mode 100644
index 0000000..139ae68
--- /dev/null
+++ b/awt/java/awt/Font.java
@@ -0,0 +1,1500 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextAttribute;
+import java.awt.font.TransformAttribute;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.text.CharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
+import org.apache.harmony.awt.gl.font.CommonGlyphVector;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The Font class represents fonts for rendering text.
+ * This class allow to map characters to glyphs.
+ * <p>
+ * A glyph is a shape used to render a character or a sequence of
+ * characters. For example one character of Latin writing system
+ * represented by one glyth, but in complex writing system such as
+ * South and South-East Asian there is more complicated correspondence
+ * between characters and glyphs.
+ * <p>
+ * The Font object is identified by two types of names. The logical font name
+ * is the name that is used to construct the font. The font name
+ * is the name of a particular font face (for example, Arial Bold).
+ * The family name is the font's family name that specifies
+ * the typographic design across several faces (for example, Arial). In
+ * all the Font is identified by three attributes: the family name,
+ * the style (such as bold or italic), and the size.
+ */
+public class Font implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4206021311591459213L;
+
+ // Identity Transform attribute
+ /** The Constant IDENTITY_TRANSFORM. */
+ private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute(
+ new AffineTransform());
+
+ /** The Constant PLAIN indicates font's plain style. */
+ public static final int PLAIN = 0;
+
+ /** The Constant BOLD indicates font's bold style. */
+ public static final int BOLD = 1;
+
+ /** The Constant ITALIC indicates font's italic style. */
+ public static final int ITALIC = 2;
+
+ /** The Constant ROMAN_BASELINE indicated roman baseline. */
+ public static final int ROMAN_BASELINE = 0;
+
+ /** The Constant CENTER_BASELINE indicates center baseline. */
+ public static final int CENTER_BASELINE = 1;
+
+ /** The Constant HANGING_BASELINE indicates hanging baseline. */
+ public static final int HANGING_BASELINE = 2;
+
+ /**
+ * The Constant TRUETYPE_FONT indicates a font resource of
+ * type TRUETYPE.
+ */
+ public static final int TRUETYPE_FONT = 0;
+
+ /**
+ * The Constant TYPE1_FONT indicates a font resource of
+ * type TYPE1.
+ */
+ public static final int TYPE1_FONT = 1;
+
+ /**
+ * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is
+ * left to right.
+ */
+ public static final int LAYOUT_LEFT_TO_RIGHT = 0;
+
+ /**
+ * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is
+ * right to left.
+ */
+ public static final int LAYOUT_RIGHT_TO_LEFT = 1;
+
+ /**
+ * The Constant LAYOUT_NO_START_CONTEXT indicates that the text
+ * in the char array before the indicated start should not be examined.
+ */
+ public static final int LAYOUT_NO_START_CONTEXT = 2;
+
+ /** The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in
+ * the char array after the indicated limit should not be examined. */
+ public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
+
+ /** The Constant DEFAULT_FONT. */
+ static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$
+
+ /** The name of the Font. */
+ protected String name;
+
+ /** The style of the Font. */
+ protected int style;
+
+ /** The size of the Font. */
+ protected int size;
+
+ /** The point size of the Font. */
+ protected float pointSize;
+
+ // Flag if the Font object transformed
+ /** The transformed. */
+ private boolean transformed;
+
+ // Set of font attributes
+ /** The requested attributes. */
+ private Hashtable<Attribute, Object> fRequestedAttributes;
+
+ // font peer object corresponding to this Font
+ /** The font peer. */
+ private transient FontPeerImpl fontPeer;
+
+ // number of glyphs in this Font
+ /** The num glyphs. */
+ private transient int numGlyphs = -1;
+
+ // code for missing glyph for this Font
+ /** The missing glyph code. */
+ private transient int missingGlyphCode = -1;
+
+ /**
+ * Writes object to ObjectOutputStream.
+ *
+ * @param out ObjectOutputStream
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ }
+
+ /**
+ * Reads object from ObjectInputStream object and set native platform
+ * dependent fields to default values.
+ *
+ * @param in ObjectInputStream object
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ClassNotFoundException the class not found exception
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ in.defaultReadObject();
+
+ numGlyphs = -1;
+ missingGlyphCode = -1;
+
+ }
+
+ /**
+ * Instantiates a new Font with the specified attributes.
+ * The Font will be created with default attributes
+ * if the attribute's parameter is null.
+ *
+ * @param attributes the attributes to be assigned to the new Font, or null.
+ */
+ public Font(Map<? extends Attribute, ?> attributes) {
+ Object currAttr;
+
+ // Default values are taken from the documentation of the Font class.
+ // See Font constructor, decode and getFont sections.
+
+ this.name = "default"; //$NON-NLS-1$
+ this.size = 12;
+ this.pointSize = 12;
+ this.style = Font.PLAIN;
+
+ if (attributes != null) {
+
+ fRequestedAttributes = new Hashtable<Attribute, Object>(attributes);
+
+ currAttr = attributes.get(TextAttribute.SIZE);
+ if (currAttr != null) {
+ this.pointSize = ((Float) currAttr).floatValue();
+ this.size = (int) Math.ceil(this.pointSize);
+ }
+
+ currAttr = attributes.get(TextAttribute.POSTURE);
+ if (currAttr != null
+ && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) {
+ this.style |= Font.ITALIC;
+ }
+
+ currAttr = attributes.get(TextAttribute.WEIGHT);
+ if ((currAttr != null)
+ && (((Float) currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD)
+ .floatValue())) {
+ this.style |= Font.BOLD;
+ }
+
+ currAttr = attributes.get(TextAttribute.FAMILY);
+ if (currAttr != null) {
+ this.name = (String) currAttr;
+ }
+
+ currAttr = attributes.get(TextAttribute.TRANSFORM);
+ if (currAttr != null) {
+ if (currAttr instanceof TransformAttribute) {
+ this.transformed = !((TransformAttribute) currAttr)
+ .getTransform().isIdentity();
+ } else if (currAttr instanceof AffineTransform) {
+ this.transformed = !((AffineTransform) currAttr)
+ .isIdentity();
+ }
+ }
+
+ } else {
+ fRequestedAttributes = new Hashtable<Attribute, Object>(5);
+ fRequestedAttributes.put(TextAttribute.TRANSFORM,
+ IDENTITY_TRANSFORM);
+
+ this.transformed = false;
+
+ fRequestedAttributes.put(TextAttribute.FAMILY, name);
+
+ fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size));
+
+ if ((this.style & Font.BOLD) != 0) {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_REGULAR);
+ }
+ if ((this.style & Font.ITALIC) != 0) {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_REGULAR);
+ }
+
+ }
+ }
+
+ /**
+ * Instantiates a new Font with the specified name, style and size.
+ *
+ * @param name the name of font.
+ * @param style the style of font.
+ * @param size the size of font.
+ */
+ public Font(String name, int style, int size) {
+
+ this.name = (name != null) ? name : "Default"; //$NON-NLS-1$
+ this.size = (size >= 0) ? size : 0;
+ this.style = (style & ~0x03) == 0 ? style : Font.PLAIN;
+ this.pointSize = this.size;
+
+ fRequestedAttributes = new Hashtable<Attribute, Object>(5);
+
+ fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM);
+
+ this.transformed = false;
+
+ fRequestedAttributes.put(TextAttribute.FAMILY, this.name);
+ fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size));
+
+ if ((this.style & Font.BOLD) != 0) {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_REGULAR);
+ }
+ if ((this.style & Font.ITALIC) != 0) {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_REGULAR);
+ }
+ }
+
+ /**
+ * Returns true if this Font has a glyph for the specified character.
+ *
+ * @param c the character.
+ *
+ * @return true if this Font has a glyph for the specified character,
+ * false otherwise.
+ */
+ public boolean canDisplay(char c) {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.canDisplay(c);
+ }
+
+ /**
+ * Returns true if the Font can display the characters of the
+ * the specified text from the specified start position
+ * to the specified limit position.
+ *
+ * @param text the text.
+ * @param start the start offset (in the character array).
+ * @param limit the limit offset (in the character array).
+ *
+ * @return the a character's position in the text that this Font
+ * can not display, or -1 if this Font can display all characters
+ * in this text.
+ */
+ public int canDisplayUpTo(char[] text, int start, int limit) {
+ int st = start;
+ int result;
+ while ((st < limit) && canDisplay(text[st])) {
+ st++;
+ }
+
+ if (st == limit) {
+ result = -1;
+ } else {
+ result = st;
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns true if the Font can display the characters of the
+ * the specified CharacterIterator from the specified start position
+ * and the specified limit position.
+ *
+ * @param iter the CharacterIterator.
+ * @param start the start offset.
+ * @param limit the limit offset.
+ *
+ * @return the a character's position in the CharacterIterator
+ * that this Font can not display, or -1 if this Font can display
+ * all characters in this text.
+ */
+ public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
+ int st = start;
+ char c = iter.setIndex(start);
+ int result;
+
+ while ((st < limit) && (canDisplay(c))) {
+ st++;
+ c = iter.next();
+ }
+ if (st == limit) {
+ result = -1;
+ } else {
+ result = st;
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns true if this Font can display a specified String.
+ *
+ * @param str the String.
+ *
+ * @return the a character's position in the String that
+ * this Font can not display, or -1 if this Font can display
+ * all characters in this text.
+ */
+ public int canDisplayUpTo(String str) {
+ char[] chars = str.toCharArray();
+ return canDisplayUpTo(chars, 0, chars.length);
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param chars the characters array.
+ *
+ * @return the GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) {
+ return new AndroidGlyphVector(chars, frc, this, 0);
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters contained
+ * in the specified CharacterIterator to glyphs based on
+ * the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param iter the CharacterIterator.
+ *
+ * @return the GlyphVector of associating characters contained
+ * in the specified CharacterIterator to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc,
+ CharacterIterator iter) {
+ throw new RuntimeException("Not implemented!"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters to glyphs based on
+ * the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param glyphCodes the specified integer array of glyph codes.
+ *
+ * @return the GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes)
+ throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented!"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters to glyphs based on
+ * the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param str the specified String.
+ *
+ * @return the GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc, String str) {
+ return new AndroidGlyphVector(str.toCharArray(), frc, this, 0);
+
+ }
+
+ /**
+ * Returns the font style constant value corresponding to one of the font style
+ * names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns Font.PLAIN if
+ * the argument is not one of the predefined style names.
+ *
+ * @param fontStyleName font style name
+ *
+ * @return font style constant value corresponding to the font style name
+ * specified.
+ */
+ private static int getFontStyle(String fontStyleName) {
+ int result = Font.PLAIN;
+
+ if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$
+ result = Font.BOLD | Font.ITALIC;
+ } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$
+ result = Font.BOLD;
+ } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$
+ result = Font.ITALIC;
+ }
+
+ return result;
+ }
+
+ /**
+ * Decodes the specified string which described the Font. The string
+ * should have the following format: fontname-style-pointsize.
+ * The style can be PLAIN, BOLD, BOLDITALIC, or ITALIC.
+ *
+ * @param str the string which describes the font.
+ *
+ * @return the Font from the specified string.
+ */
+ public static Font decode(String str) {
+ // XXX: Documentation doesn't describe all cases, e.g. fonts face names
+ // with
+ // symbols that are suggested as delimiters in the documentation.
+ // In this decode implementation only ***-***-*** format is used with
+ // '-'
+ // as the delimiter to avoid unexpected parse results of font face names
+ // with spaces.
+
+ if (str == null) {
+ return DEFAULT_FONT;
+ }
+
+ StringTokenizer strTokens;
+ String delim = "-"; //$NON-NLS-1$
+ String substr;
+
+ int fontSize = DEFAULT_FONT.size;
+ int fontStyle = DEFAULT_FONT.style;
+ String fontName = DEFAULT_FONT.name;
+
+ strTokens = new StringTokenizer(str.trim(), delim);
+
+ // Font Name
+ if (strTokens.hasMoreTokens()) {
+ fontName = strTokens.nextToken(); // first token is the font name
+ }
+
+ // Font Style or Size (if the style is undefined)
+ if (strTokens.hasMoreTokens()) {
+ substr = strTokens.nextToken();
+
+ try {
+ // if second token is the font size
+ fontSize = Integer.parseInt(substr);
+ } catch (NumberFormatException e) {
+ // then second token is the font style
+ fontStyle = getFontStyle(substr);
+ }
+
+ }
+
+ // Font Size
+ if (strTokens.hasMoreTokens()) {
+ try {
+ fontSize = Integer.parseInt(strTokens.nextToken());
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ return new Font(fontName, fontStyle, fontSize);
+ }
+
+ /**
+ * Perfoms the specified affine transform to the Font and returns
+ * a new Font.
+ *
+ * @param trans the AffineTransform.
+ *
+ * @return the Font object.
+ *
+ * @throws IllegalArgumentException if affine transform parameter
+ * is null.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(AffineTransform trans) {
+
+ if (trans == null) {
+ // awt.94=transform can not be null
+ throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+ }
+
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ derivefRequestedAttributes.put(TextAttribute.TRANSFORM,
+ new TransformAttribute(trans));
+
+ return new Font(derivefRequestedAttributes);
+
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified so that the size is the specified size.
+ *
+ * @param size the size of font.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(float size) {
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+ derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified so that the style is the specified style.
+ *
+ * @param style the style of font.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(int style) {
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ if ((style & Font.BOLD) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+ }
+
+ if ((style & Font.ITALIC) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+ }
+
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified to match the specified style and with the specified
+ * affine transform applied to its glyphs.
+ *
+ * @param style the style of font.
+ * @param trans the AffineTransform.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(int style, AffineTransform trans) {
+
+ if (trans == null) {
+ // awt.94=transform can not be null
+ throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+ }
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ if ((style & BOLD) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+ }
+
+ if ((style & ITALIC) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+ }
+ derivefRequestedAttributes.put(TextAttribute.TRANSFORM,
+ new TransformAttribute(trans));
+
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified so that the size and style are the specified
+ * size and style.
+ *
+ * @param style the style of font.
+ * @param size the size of font.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(int style, float size) {
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ if ((style & BOLD) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+ }
+
+ if ((style & ITALIC) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+ }
+
+ derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
+ return new Font(derivefRequestedAttributes);
+
+ }
+
+ /**
+ * Returns a new Font object with a new set of font attributes.
+ *
+ * @param attributes the map of attributes.
+ *
+ * @return the Font.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(Map<? extends Attribute, ?> attributes) {
+ Attribute[] avalAttributes = this.getAvailableAttributes();
+
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+ Object currAttribute;
+ for (Attribute element : avalAttributes) {
+ currAttribute = attributes.get(element);
+ if (currAttribute != null) {
+ derivefRequestedAttributes.put(element, currAttribute);
+ }
+ }
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Compares the specified Object with the current Font.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is an instance of Font
+ * with the same family, size, and style as this Font, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null) {
+ try {
+ Font font = (Font) obj;
+
+ return ((this.style == font.style) && (this.size == font.size)
+ && this.name.equals(font.name)
+ && (this.pointSize == font.pointSize) && (this
+ .getTransform()).equals(font.getTransform()));
+ } catch (ClassCastException e) {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets the map of font's attributes.
+ *
+ * @return the map of font's attributes.
+ */
+ @SuppressWarnings("unchecked")
+ public Map<TextAttribute, ?> getAttributes() {
+ return (Map<TextAttribute, ?>) fRequestedAttributes.clone();
+ }
+
+ /**
+ * Gets the keys of all available attributes.
+ *
+ * @return the keys array of all available attributes.
+ */
+ public Attribute[] getAvailableAttributes() {
+ Attribute[] attrs = { TextAttribute.FAMILY, TextAttribute.POSTURE,
+ TextAttribute.SIZE, TextAttribute.TRANSFORM,
+ TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT,
+ TextAttribute.WIDTH };
+ return attrs;
+ }
+
+ /**
+ * Gets the baseline for this character.
+ *
+ * @param c the character.
+ *
+ * @return the baseline for this character.
+ */
+ public byte getBaselineFor(char c) {
+ // TODO: implement using TT BASE table data
+ return 0;
+ }
+
+ /**
+ * Gets the family name of the Font.
+ *
+ * @return the family name of the Font.
+ */
+ public String getFamily() {
+ if (fRequestedAttributes != null) {
+ fRequestedAttributes.get(TextAttribute.FAMILY);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the family name of this Font associated with
+ * the specified locale.
+ *
+ * @param l the locale.
+ *
+ * @return the family name of this Font associated with
+ * the specified locale.
+ */
+ public String getFamily(Locale l) {
+ if (l == null) {
+ // awt.01='{0}' parameter is null
+ throw new NullPointerException(Messages.getString(
+ "awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return getFamily();
+ }
+
+ /**
+ * Gets a Font with the specified attribute set.
+ *
+ * @param attributes the attributes to be assigned to the new Font.
+ *
+ * @return the Font.
+ */
+ public static Font getFont(Map<? extends Attribute, ?> attributes) {
+ Font fnt = (Font) attributes.get(TextAttribute.FONT);
+ if (fnt != null) {
+ return fnt;
+ }
+ return new Font(attributes);
+ }
+
+ /**
+ * Gets a Font object from the system properties list with the specified name
+ * or returns the specified Font if there is no such property.
+ *
+ * @param sp the specified property name.
+ * @param f the Font.
+ *
+ * @return the Font object from the system properties list with the specified name
+ * or the specified Font if there is no such property.
+ */
+ public static Font getFont(String sp, Font f) {
+ String pr = System.getProperty(sp);
+ if (pr == null) {
+ return f;
+ }
+ return decode(pr);
+ }
+
+ /**
+ * Gets a Font object from the system properties list with the specified name.
+ *
+ * @param sp the system property name.
+ *
+ * @return the Font, or null if there is no shuch property
+ * with the specified name.
+ */
+ public static Font getFont(String sp) {
+ return getFont(sp, null);
+ }
+
+ /**
+ * Gets the font name.
+ *
+ * @return the font name.
+ */
+ public String getFontName() {
+ if (fRequestedAttributes != null) {
+ fRequestedAttributes.get(TextAttribute.FAMILY);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the font name associated with the specified locale.
+ *
+ * @param l the locale.
+ *
+ * @return the font name associated with the specified locale.
+ */
+ public String getFontName(Locale l) {
+ return getFamily();
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param chars the chars array.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(char[] chars, int start, int end,
+ FontRenderContext frc) {
+ if (frc == null) {
+ // awt.00=FontRenderContext is null
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ //FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics();
+ FontMetrics fm = new FontMetricsImpl(this);
+ float[] fmet = {fm.getAscent(), fm.getDescent(), fm.getLeading()};
+ return new LineMetricsImpl(chars.length, fmet, null);
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param iter the CharacterIterator.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(CharacterIterator iter, int start,
+ int end, FontRenderContext frc) {
+
+ if (frc == null) {
+ // awt.00=FontRenderContext is null
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ String resultString;
+ int iterCount;
+
+ iterCount = end - start;
+ if (iterCount < 0) {
+ resultString = ""; //$NON-NLS-1$
+ } else {
+ char[] chars = new char[iterCount];
+ int i = 0;
+ for (char c = iter.setIndex(start); c != CharacterIterator.DONE
+ && (i < iterCount); c = iter.next()) {
+ chars[i] = c;
+ i++;
+ }
+ resultString = new String(chars);
+ }
+ return this.getLineMetrics(resultString, frc);
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param str the String.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc) {
+ //FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics();
+ FontMetrics fm = new FontMetricsImpl(this);
+ float[] fmet = {fm.getAscent(), fm.getDescent(), fm.getLeading()};
+ //Log.i("FONT FMET", fmet.toString());
+ return new LineMetricsImpl(str.length(), fmet, null);
+
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param str the String.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(String str, int start, int end,
+ FontRenderContext frc) {
+ return this.getLineMetrics(str.substring(start, end), frc);
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param ci the specified CharacterIterator.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(CharacterIterator ci, int start,
+ int end, FontRenderContext frc) {
+ int first = ci.getBeginIndex();
+ int finish = ci.getEndIndex();
+ char[] chars;
+
+ if (start < first) {
+ // awt.95=Wrong start index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.95", start)); //$NON-NLS-1$
+ }
+ if (end > finish) {
+ // awt.96=Wrong finish index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.96", end)); //$NON-NLS-1$
+ }
+ if (start > end) {
+ // awt.97=Wrong range length: {0}
+ throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$
+ (end - start)));
+ }
+
+ if (frc == null) {
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ chars = new char[end - start];
+
+ ci.setIndex(start);
+ for (int i = 0; i < chars.length; i++) {
+ chars[i] = ci.current();
+ ci.next();
+ }
+
+ return this.getStringBounds(chars, 0, chars.length, frc);
+
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param str the specified String.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(String str, FontRenderContext frc) {
+ char[] chars = str.toCharArray();
+ return this.getStringBounds(chars, 0, chars.length, frc);
+
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param str the specified String.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(String str, int start, int end,
+ FontRenderContext frc) {
+
+ return this.getStringBounds((str.substring(start, end)), frc);
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param chars the specified character array.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(char[] chars, int start, int end,
+ FontRenderContext frc) {
+ if (start < 0) {
+ // awt.95=Wrong start index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.95", start)); //$NON-NLS-1$
+ }
+ if (end > chars.length) {
+ // awt.96=Wrong finish index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.96", end)); //$NON-NLS-1$
+ }
+ if (start > end) {
+ // awt.97=Wrong range length: {0}
+ throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$
+ (end - start)));
+ }
+
+ if (frc == null) {
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+
+ final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION
+ | AffineTransform.TYPE_GENERAL_TRANSFORM;
+ Rectangle2D bounds;
+
+ AffineTransform transform = getTransform();
+
+ // XXX: for transforms where an angle between basis vectors is not 90
+ // degrees Rectanlge2D class doesn't fit as Logical bounds.
+ if ((transform.getType() & TRANSFORM_MASK) == 0) {
+ int width = 0;
+ for (int i = start; i < end; i++) {
+ width += peer.charWidth(chars[i]);
+ }
+ //LineMetrics nlm = peer.getLineMetrics();
+
+ LineMetrics nlm = getLineMetrics(chars, start, end, frc);
+
+ bounds = transform.createTransformedShape(
+ new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm
+ .getHeight())).getBounds2D();
+ } else {
+ int len = end - start;
+ char[] subChars = new char[len];
+ System.arraycopy(chars, start, subChars, 0, len);
+ bounds = createGlyphVector(frc, subChars).getLogicalBounds();
+ }
+ return bounds;
+ }
+
+ /**
+ * Gets the character's maximum bounds as defined in
+ * the specified FontRenderContext.
+ *
+ * @param frc the FontRenderContext.
+ *
+ * @return the character's maximum bounds.
+ */
+ public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
+ if (frc == null) {
+ // awt.00=FontRenderContext is null
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+
+ Rectangle2D bounds = peer.getMaxCharBounds(frc);
+ AffineTransform transform = getTransform();
+ // !! Documentation doesn't describe meaning of max char bounds
+ // for the fonts that have rotate transforms. For all transforms
+ // returned bounds are the bounds of transformed maxCharBounds
+ // Rectangle2D that corresponds to the font with identity transform.
+ // TODO: resolve this issue to return correct bounds
+ bounds = transform.createTransformedShape(bounds).getBounds2D();
+
+ return bounds;
+ }
+
+ /**
+ * Returns a new GlyphVector object performing full layout of
+ * the text.
+ *
+ * @param frc the FontRenderContext.
+ * @param chars the character array to be layout.
+ * @param start the start offset of the text to use for
+ * the GlyphVector.
+ * @param count the count of characters to use for
+ * the GlyphVector.
+ * @param flags the flag indicating text direction:
+ * LAYOUT_RIGHT_TO_LEFT, LAYOUT_LEFT_TO_RIGHT.
+ *
+ * @return the GlyphVector.
+ */
+ public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars,
+ int start, int count, int flags) {
+ // TODO: implement method for bidirectional text.
+ // At the moment only LTR and RTL texts supported.
+ if (start < 0) {
+ // awt.95=Wrong start index: {0}
+ throw new ArrayIndexOutOfBoundsException(Messages.getString(
+ "awt.95", //$NON-NLS-1$
+ start));
+ }
+
+ if (count < 0) {
+ // awt.98=Wrong count value, can not be negative: {0}
+ throw new ArrayIndexOutOfBoundsException(Messages.getString(
+ "awt.98", //$NON-NLS-1$
+ count));
+ }
+
+ if (start + count > chars.length) {
+ // awt.99=Wrong [start + count] is out of range: {0}
+ throw new ArrayIndexOutOfBoundsException(Messages.getString(
+ "awt.99", //$NON-NLS-1$
+ (start + count)));
+ }
+
+ char[] out = new char[count];
+ System.arraycopy(chars, start, out, 0, count);
+
+ return new CommonGlyphVector(out, frc, this, flags);
+ }
+
+ /**
+ * Returns the String representation of this Font.
+ *
+ * @return the String representation of this Font.
+ */
+ @Override
+ public String toString() {
+ String stl = "plain"; //$NON-NLS-1$
+ String result;
+
+ if (this.isBold() && this.isItalic()) {
+ stl = "bolditalic"; //$NON-NLS-1$
+ }
+ if (this.isBold() && !this.isItalic()) {
+ stl = "bold"; //$NON-NLS-1$
+ }
+
+ if (!this.isBold() && this.isItalic()) {
+ stl = "italic"; //$NON-NLS-1$
+ }
+
+ result = this.getClass().getName() + "[family=" + this.getFamily() + //$NON-NLS-1$
+ ",name=" + this.name + //$NON-NLS-1$
+ ",style=" + stl + //$NON-NLS-1$
+ ",size=" + this.size + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ return result;
+ }
+
+ /**
+ * Gets the postscript name of this Font.
+ *
+ * @return the postscript name of this Font.
+ */
+ public String getPSName() {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.getPSName();
+ }
+
+ /**
+ * Gets the logical name of this Font.
+ *
+ * @return the logical name of this Font.
+ */
+ public String getName() {
+ return (this.name);
+ }
+
+ /**
+ * Gets the peer of this Font.
+ *
+ * @return the peer of this Font.
+ *
+ * @deprecated Font rendering is platform independent now.
+ */
+ @Deprecated
+ public java.awt.peer.FontPeer getPeer() {
+ if (fontPeer == null) {
+ fontPeer = (FontPeerImpl) Toolkit.getDefaultToolkit()
+ .getGraphicsFactory().getFontPeer(this);
+ }
+ return fontPeer;
+
+ }
+
+ /**
+ * Gets the transform acting on this Font (from the Font's
+ * attributes).
+ *
+ * @return the transformation of this Font.
+ */
+ public AffineTransform getTransform() {
+ Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM);
+
+ if (transform != null) {
+ if (transform instanceof TransformAttribute) {
+ return ((TransformAttribute) transform).getTransform();
+ }
+ if (transform instanceof AffineTransform) {
+ return new AffineTransform((AffineTransform) transform);
+ }
+ } else {
+ transform = new AffineTransform();
+ }
+ return (AffineTransform) transform;
+
+ }
+
+ /**
+ * Checks if this font is transformed or not.
+ *
+ * @return true, if this font is transformed, false otherwise.
+ */
+ public boolean isTransformed() {
+ return this.transformed;
+ }
+
+ /**
+ * Checks if this font has plain style or not.
+ *
+ * @return true, if this font has plain style, false otherwise.
+ */
+ public boolean isPlain() {
+ return (this.style == PLAIN);
+ }
+
+ /**
+ * Checks if this font has italic style or not.
+ *
+ * @return true, if this font has italic style, false otherwise.
+ */
+ public boolean isItalic() {
+ return (this.style & ITALIC) != 0;
+ }
+
+ /**
+ * Checks if this font has bold style or not.
+ *
+ * @return true, if this font has bold style, false otherwise.
+ */
+ public boolean isBold() {
+ return (this.style & BOLD) != 0;
+ }
+
+ /**
+ * Returns true if this Font has uniform line metrics.
+ *
+ * @return true if this Font has uniform line metrics,
+ * false otherwise.
+ */
+ public boolean hasUniformLineMetrics() {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.hasUniformLineMetrics();
+ }
+
+ /**
+ * Returns hash code of this Font object.
+ *
+ * @return the hash code of this Font object.
+
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+
+ hash.append(this.name);
+ hash.append(this.style);
+ hash.append(this.size);
+
+ return hash.hashCode();
+ }
+
+ /**
+ * Gets the style of this Font.
+ *
+ * @return the style of this Font.
+ */
+ public int getStyle() {
+ return this.style;
+ }
+
+ /**
+ * Gets the size of this Font.
+ *
+ * @return the size of this Font.
+ */
+ public int getSize() {
+ return this.size;
+ }
+
+ /**
+ * Gets the number of glyphs for this Font.
+ *
+ * @return the number of glyphs for this Font.
+ */
+ public int getNumGlyphs() {
+ if (numGlyphs == -1) {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ this.numGlyphs = peer.getNumGlyphs();
+ }
+ return this.numGlyphs;
+ }
+
+ /**
+ * Gets the glyphCode which is used as default glyph when this Font
+ * does not have a glyph for a specified unicode.
+ *
+ * @return the missing glyph code.
+ */
+ public int getMissingGlyphCode() {
+ if (missingGlyphCode == -1) {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ this.missingGlyphCode = peer.getMissingGlyphCode();
+ }
+ return this.missingGlyphCode;
+ }
+
+ /**
+ * Gets the float value of font's size.
+ *
+ * @return the float value of font's size.
+ */
+ public float getSize2D() {
+ return this.pointSize;
+ }
+
+ /**
+ * Gets the italic angle of this Font.
+ *
+ * @return the italic angle of this Font.
+ */
+ public float getItalicAngle() {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.getItalicAngle();
+ }
+
+ /**
+ * Creates the font with the specified font format and font file.
+ *
+ * @param fontFormat the font format.
+ * @param fontFile the file object represented the input data
+ * for the font.
+ *
+ * @return the Font.
+ *
+ * @throws FontFormatException is thrown if fontFile does not contain
+ * the required font tables for the specified format.
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static Font createFont(int fontFormat, File fontFile)
+ throws FontFormatException, IOException {
+ // ???AWT not supported
+ InputStream is = new FileInputStream(fontFile);
+ try {
+ return createFont(fontFormat, is);
+ } finally {
+ is.close();
+ }
+ }
+
+ /**
+ * Creates the font with the specified font format and input stream.
+ *
+ * @param fontFormat the font format.
+ * @param fontStream the input stream represented input data for
+ * the font.
+ *
+ * @return the Font.
+ *
+ * @throws FontFormatException is thrown if fontFile does not contain
+ * the required font tables for the specified format.
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static Font createFont(int fontFormat, InputStream fontStream)
+ throws FontFormatException, IOException {
+
+ // ???AWT not supported
+
+ BufferedInputStream buffStream;
+ int bRead = 0;
+ int size = 8192;
+ // memory page size, for the faster reading
+ byte buf[] = new byte[size];
+
+ if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format
+ throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$
+ }
+
+ /* Get font file in system-specific directory */
+
+ File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory()
+ .getFontManager().getTempFontFile();
+
+ // BEGIN android-modified
+ buffStream = new BufferedInputStream(fontStream, 8192);
+ // END android-modified
+ FileOutputStream fOutStream = new FileOutputStream(fontFile);
+
+ bRead = buffStream.read(buf, 0, size);
+
+ while (bRead != -1) {
+ fOutStream.write(buf, 0, bRead);
+ bRead = buffStream.read(buf, 0, size);
+ }
+
+ buffStream.close();
+ fOutStream.close();
+
+ Font font = null;
+
+ font = Toolkit.getDefaultToolkit().getGraphicsFactory().embedFont(
+ fontFile.getAbsolutePath());
+ if (font == null) { // awt.9B=Can't create font - bad font data
+ throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$
+ }
+ return font;
+ }
+
+}
diff --git a/awt/java/awt/FontFormatException.java b/awt/java/awt/FontFormatException.java
new file mode 100644
index 0000000..c017fd2
--- /dev/null
+++ b/awt/java/awt/FontFormatException.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The FontFormatException class is used to provide notification
+ * and information that font can't be created.
+ */
+public class FontFormatException extends Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4481290147811361272L;
+
+ /**
+ * Instantiates a new font format exception with detailed message.
+ *
+ * @param reason the detailed message.
+ */
+ public FontFormatException(String reason) {
+ super(reason);
+ }
+
+}
diff --git a/awt/java/awt/FontMetrics.java b/awt/java/awt/FontMetrics.java
new file mode 100644
index 0000000..3948d73
--- /dev/null
+++ b/awt/java/awt/FontMetrics.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.text.CharacterIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The FontMetrics class contains information about the rendering
+ * of a particular font on a particular screen.
+ * <p>
+ * Each character in the Font has three values that help define where
+ * to place it: an ascent, a descent, and an advance. The ascent is the
+ * distance the character extends above the baseline. The descent is
+ * the distance the character extends below the baseline.
+ * The advance width defines the position at which the next character
+ * should be placed.
+ * <p>
+ * An array of characters or a string has an ascent, a descent,
+ * and an advance width too. The ascent or descent of the array
+ * is specified by the maximum ascent or descent of the characters
+ * in the array. The advance width is the sum of the advance widths
+ * of each of the characters in the character array.
+ */
+public abstract class FontMetrics implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 1681126225205050147L;
+
+ /** The font from which the FontMetrics is created. */
+ protected Font font;
+
+ /**
+ * Instantiates a new font metrics from the specified Font.
+ *
+ * @param fnt the Font.
+ */
+ protected FontMetrics(Font fnt) {
+ this.font = fnt;
+ }
+
+ /**
+ * Returns the String representation of this FontMetrics.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getName() +
+ "[font=" + this.getFont() + //$NON-NLS-1$
+ "ascent=" + this.getAscent() + //$NON-NLS-1$
+ ", descent=" + this.getDescent() + //$NON-NLS-1$
+ ", height=" + this.getHeight() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Gets the font associated with this FontMetrics.
+ *
+ * @return the font associated with this FontMetrics.
+ */
+ public Font getFont() {
+ return font;
+ }
+
+ /**
+ * Gets the height of the text line in this Font.
+ *
+ * @return the height of the text line in this Font.
+ */
+ public int getHeight() {
+ return this.getAscent() + this.getDescent() + this.getLeading();
+ }
+
+ /**
+ * Gets the font ascent of the Font associated with this FontMetrics.
+ * The font ascent is the distance from the font's baseline to
+ * the top of most alphanumeric characters.
+ *
+ * @return the ascent of the Font associated with this FontMetrics.
+ */
+ public int getAscent() {
+ return 0;
+ }
+
+ /**
+ * Gets the font descent of the Font associated with this FontMetrics.
+ * The font descent is the distance from the font's baseline to
+ * the bottom of most alphanumeric characters with descenders.
+ *
+ * @return the descent of the Font associated with this FontMetrics.
+ */
+ public int getDescent() {
+ return 0;
+ }
+
+ /**
+ * Gets the leading of the Font associated with this FontMetrics.
+ *
+ * @return the leading of the Font associated with this FontMetrics.
+ */
+ public int getLeading() {
+ return 0;
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified CharacterIterator
+ * in the specified Graphics.
+ *
+ * @param ci the CharacterIterator.
+ * @param beginIndex the offset.
+ * @param limit the number of characters to be used.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified CharacterIterator
+ * in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex,
+ int limit, Graphics context) {
+ return font.getLineMetrics(ci, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified String
+ * in the specified Graphics.
+ *
+ * @param str the String.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified String
+ * in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(String str, Graphics context) {
+ return font.getLineMetrics(str, this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified character
+ * array in the specified Graphics.
+ *
+ * @param chars the character array.
+ * @param beginIndex the offset of array.
+ * @param limit the number of characters to be used.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified character
+ * array in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit,
+ Graphics context) {
+ return font.getLineMetrics(chars, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified String
+ * in the specified Graphics.
+ *
+ * @param str the String.
+ * @param beginIndex the offset.
+ * @param limit the number of characters to be used.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified String
+ * in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(String str, int beginIndex, int limit,
+ Graphics context) {
+ return font.getLineMetrics(str, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Returns the character's maximum bounds in the specified
+ * Graphics context.
+ *
+ * @param context the Graphics context.
+ *
+ * @return the character's maximum bounds in the specified
+ * Graphics context.
+ */
+ public Rectangle2D getMaxCharBounds(Graphics context) {
+ return this.font.getMaxCharBounds(this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the bounds of the specified CharacterIterator
+ * in the specified Graphics context.
+ *
+ * @param ci the CharacterIterator.
+ * @param beginIndex the begin offset of the array.
+ * @param limit the number of characters.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified CharacterIterator
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex,
+ int limit, Graphics context) {
+ return font.getStringBounds(ci, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the bounds of the specified String
+ * in the specified Graphics context.
+ *
+ * @param str the String.
+ * @param beginIndex the begin offset of the array.
+ * @param limit the number of characters.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified String
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(String str, int beginIndex, int limit,
+ Graphics context) {
+ return font.getStringBounds(str, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+
+ /**
+ * Gets the bounds of the specified characters array
+ * in the specified Graphics context.
+ *
+ * @param chars the characters array.
+ * @param beginIndex the begin offset of the array.
+ * @param limit the number of characters.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified characters array
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit,
+ Graphics context) {
+ return font.getStringBounds(chars, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the bounds of the specified String
+ * in the specified Graphics context.
+ *
+ * @param str the String.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified String
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(String str, Graphics context) {
+ return font.getStringBounds(str, this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Checks if the Font has uniform line metrics or not.
+ * The Font can contain characters of other fonts for
+ * covering character set. In this case the Font isn't
+ * uniform.
+ *
+ * @return true, if the Font has uniform line metrics,
+ * false otherwise.
+ */
+ public boolean hasUniformLineMetrics() {
+ return this.font.hasUniformLineMetrics();
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point on the string's baseline showing the specified array
+ * of bytes in this Font.
+ *
+ * @param data the array of bytes to be measured.
+ * @param off the start offset.
+ * @param len the number of bytes to be measured.
+ *
+ * @return the advance width of the array.
+ */
+ public int bytesWidth(byte[] data, int off, int len) {
+ int width = 0;
+ if ((off >= data.length) || (off < 0)){
+ // awt.13B=offset off is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$
+ }
+
+ if ((off+len > data.length)){
+ // awt.13C=number of elemets len is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$
+ }
+
+ for (int i = off; i < off+len; i++){
+ width += charWidth(data[i]);
+ }
+
+ return width;
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point on the string's baseline showing the specified array
+ * of characters in this Font.
+ *
+ * @param data the array of characters to be measured.
+ * @param off the start offset.
+ * @param len the number of bytes to be measured.
+ *
+ * @return the advance width of the array.
+ */
+ public int charsWidth(char[] data, int off , int len){
+ int width = 0;
+ if ((off >= data.length) || (off < 0)){
+ // awt.13B=offset off is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$
+ }
+
+ if ((off+len > data.length)){
+ // awt.13C=number of elemets len is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$
+ }
+
+ for (int i = off; i < off+len; i++){
+ width += charWidth(data[i]);
+ }
+
+ return width;
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point of the specified character in this Font.
+ *
+ * @param ch the specified unicode point code of
+ * character to be measured.
+ *
+ * @return the advance width of the character.
+ */
+ public int charWidth(int ch) {
+ return 0;
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point of the specified character in this Font.
+ *
+ * @param ch the specified character to be measured.
+ *
+ * @return the advance width of the character.
+ */
+ public int charWidth(char ch) {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum advance width of character in this Font.
+ *
+ * @return the maximum advance width of character in this Font.
+ */
+ public int getMaxAdvance() {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum font ascent of the Font associated with
+ * this FontMetrics.
+ *
+ * @return the maximum font ascent of the Font associated with
+ * this FontMetrics.
+ */
+ public int getMaxAscent() {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum font descent of character in this Font.
+ *
+ * @return the maximum font descent of character in this Font.
+ *
+ * @deprecated Replaced by getMaxDescent() method.
+ */
+ @Deprecated
+ public int getMaxDecent() {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum font descent of character in this Font.
+ *
+ * @return the maximum font descent of character in this Font.
+ */
+ public int getMaxDescent() {
+ return 0;
+ }
+
+ /**
+ * Gets the advance widths of the characters in the Font.
+ *
+ * @return the advance widths of the characters in the Font.
+ */
+ public int[] getWidths() {
+ return null;
+ }
+
+ /**
+ * Returns the advance width for the specified String in this Font.
+ *
+ * @param str String to be measured.
+ *
+ * @return the the advance width for the specified String
+ * in this Font.
+ */
+ public int stringWidth(String str) {
+ return 0;
+ }
+
+ /**
+ * Returns FontRenderContext instanse of the Graphics context specified.
+ *
+ * @param context the specified Graphics context
+ *
+ * @return a FontRenderContext of the specified Graphics context.
+ */
+ private FontRenderContext getFRCFromGraphics(Graphics context){
+ FontRenderContext frc;
+ if (context instanceof Graphics2D) {
+ frc = ((Graphics2D)context).getFontRenderContext();
+ } else {
+ frc = new FontRenderContext(null, false, false);
+ }
+
+ return frc;
+ }
+}
+
diff --git a/awt/java/awt/GradientPaint.java b/awt/java/awt/GradientPaint.java
new file mode 100644
index 0000000..0e06528
--- /dev/null
+++ b/awt/java/awt/GradientPaint.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GradientPaint class defines a way to fill a Shape with a linear color
+ * gradient pattern.
+ * <p>
+ * The GradientPaint's fill pattern is determined by two points and two colors,
+ * plus the cyclic mode option.
+ * Each of the two points is painted with its corresponding color, and on
+ * the line segment connecting the two points, the color is proportionally
+ * changed between the two colors. For points on the same line which are not
+ * between the two specified points (outside of the connecting segment) their
+ * color is determined by the cyclic mode option. If the mode is cyclic, then
+ * the rest of the line repeats the color pattern of the connecting segment,
+ * cycling back and forth between the two colors. If not, the mode is acyclic
+ * which means that all points
+ * on the line outside the connecting line segment are given the same
+ * color as the closest of the two specified points.
+ * <p>
+ * The color of points that are not on the line connecting the two
+ * specified points are given by perpendicular projection: by taking
+ * the set of lines perpendicular to the connecting line and for each
+ * one, the whole line is colored with the same color.
+ */
+public class GradientPaint implements Paint {
+
+ /** The start point color. */
+ Color color1;
+
+ /** The end color point. */
+ Color color2;
+
+ /** The location of the start point. */
+ Point2D point1;
+
+ /** The location of the end point. */
+ Point2D point2;
+
+ /** The indicator of cycle filling. If TRUE filling
+ * repeated outside points stripe, if FALSE solid color filling outside. */
+ boolean cyclic;
+
+ /**
+ * Instantiates a new GradientPaint with cyclic or acyclic mode.
+ *
+ * @param point1 the first specified point.
+ * @param color1 the Color of the first specified point.
+ * @param point2 the second specified point.
+ * @param color2 the Color of the second specified point.
+ * @param cyclic the cyclic mode - true if the gradient pattern should cycle
+ * repeatedly between the two colors; false otherwise.
+ */
+ public GradientPaint(Point2D point1, Color color1, Point2D point2,
+ Color color2, boolean cyclic) {
+ if (point1 == null || point2 == null) {
+ // awt.6D=Point is null
+ throw new NullPointerException(Messages.getString("awt.6D")); //$NON-NLS-1$
+ }
+ if (color1 == null || color2 == null) {
+ // awt.6E=Color is null
+ throw new NullPointerException(Messages.getString("awt.6E")); //$NON-NLS-1$
+ }
+
+ this.point1 = point1;
+ this.point2 = point2;
+ this.color1 = color1;
+ this.color2 = color2;
+ this.cyclic = cyclic;
+ }
+
+ /**
+ * Instantiates a new GradientPaint with cyclic or acyclic mode;
+ * points are specified by coordinates.
+ *
+ * @param x1 the X coordinate of the first point.
+ * @param y1 the Y coordinate of the first point.
+ * @param color1 the color of the first point.
+ * @param x2 the X coordinate of the second point.
+ * @param y2 the Y coordinate of the second point.
+ * @param color2 the color of the second point.
+ * @param cyclic the cyclic mode - true if the gradient pattern should cycle
+ * repeatedly between the two colors; false otherwise.
+ */
+ public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2,
+ boolean cyclic) {
+ this(new Point2D.Float(x1, y1), color1, new Point2D.Float(x2, y2), color2, cyclic);
+ }
+
+ /**
+ * Instantiates a new acyclic GradientPaint;
+ * points are specified by coordinates.
+ *
+ * @param x1 the X coordinate of the first point.
+ * @param y1 the Y coordinate of the first point.
+ * @param color1 the color of the first point.
+ * @param x2 the X coordinate of the second point.
+ * @param y2 the Y coordinate of the second point.
+ * @param color2 the color of the second point.
+ */
+ public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) {
+ this(x1, y1, color1, x2, y2, color2, false);
+ }
+
+ /**
+ * Instantiates a new acyclic GradientPaint.
+ *
+ * @param point1 the first specified point.
+ * @param color1 the Color of the first specified point.
+ * @param point2 the second specified point.
+ * @param color2 the Color of the second specified point.
+ */
+ public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2) {
+ this(point1, color1, point2, color2, false);
+ }
+
+ /**
+ * Creates PaintContext for a color pattern generating.
+ *
+ * @param cm the ColorModel of the Paint data.
+ * @param deviceBounds the bounding Rectangle of graphics primitives
+ * being rendered in the device space.
+ * @param userBounds tthe bounding Rectangle of graphics primitives
+ * being rendered in the user space.
+ * @param t the AffineTransform from user space into device space.
+ * @param hints the RrenderingHints object.
+ *
+ * @return the PaintContext for color pattern generating.
+ *
+ * @see java.awt.Paint#createContext(java.awt.image.ColorModel, java.awt.Rectangle, java.awt.geom.Rectangle2D, java.awt.geom.AffineTransform, java.awt.RenderingHints)
+ */
+ public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+ Rectangle2D userBounds, AffineTransform t, RenderingHints hints) {
+ return new GradientPaintContext(cm, t, point1, color1, point2, color2, cyclic);
+ }
+
+ /**
+ * Gets the color of the first point.
+ *
+ * @return the color of the first point.
+ */
+ public Color getColor1() {
+ return color1;
+ }
+
+ /**
+ * Gets the color of the second point.
+ *
+ * @return the color of the second point.
+ */
+ public Color getColor2() {
+ return color2;
+ }
+
+ /**
+ * Gets the first point.
+ *
+ * @return the Point object - the first point.
+ */
+ public Point2D getPoint1() {
+ return point1;
+ }
+
+ /**
+ * Gets the second point.
+ *
+ * @return the Point object - the second point.
+ */
+ public Point2D getPoint2() {
+ return point2;
+ }
+
+ /**
+ * Gets the transparency mode for the GradientPaint.
+ *
+ * @return the transparency mode for the GradientPaint.
+ *
+ * @see java.awt.Transparency#getTransparency()
+ */
+ public int getTransparency() {
+ int a1 = color1.getAlpha();
+ int a2 = color2.getAlpha();
+ return (a1 == 0xFF && a2 == 0xFF) ? OPAQUE : TRANSLUCENT;
+ }
+
+ /**
+ * Returns the GradientPaint mode: true for cyclic mode, false for
+ * acyclic mode.
+ *
+ * @return true if the gradient cycles repeatedly between the two colors;
+ * false otherwise.
+ */
+ public boolean isCyclic() {
+ return cyclic;
+ }
+}
diff --git a/awt/java/awt/GradientPaintContext.java b/awt/java/awt/GradientPaintContext.java
new file mode 100644
index 0000000..74575f5
--- /dev/null
+++ b/awt/java/awt/GradientPaintContext.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+class GradientPaintContext implements PaintContext {
+
+ /**
+ * The size of noncyclic part of color lookup table
+ */
+ static int LOOKUP_SIZE = 256;
+
+ /**
+ * The index mask to lookup color in the table
+ */
+ static int LOOKUP_MASK = 0x1FF;
+
+ /**
+ * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.
+ */
+ static double ZERO = 1E-10;
+
+ /**
+ * The ColorModel user defined for PaintContext
+ */
+ ColorModel cm;
+
+ /**
+ * The indicator of cycle filling.
+ */
+ boolean cyclic;
+
+ /**
+ * The integer color value of the start point
+ */
+ int c1;
+
+ /**
+ * The integer color value of the end point
+ */
+ int c2;
+
+ /**
+ * The lookup gradient color table
+ */
+ int[] table;
+
+ /**
+ * The tempopary pre-calculated value to evalutae color index
+ */
+ int dx;
+
+ /**
+ * The tempopary pre-calculated value to evalutae color index
+ */
+ int dy;
+
+ /**
+ * The tempopary pre-calculated value to evalutae color index
+ */
+ int delta;
+
+ /**
+ * Constructs a new GradientPaintcontext
+ * @param cm - not used
+ * @param t - the fill transformation
+ * @param point1 - the start fill point
+ * @param color1 - color of the start point
+ * @param point2 - the end fill point
+ * @param color2 - color of the end point
+ * @param cyclic - the indicator of cycle filling
+ */
+ GradientPaintContext(ColorModel cm, AffineTransform t, Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) {
+ this.cyclic = cyclic;
+ this.cm = ColorModel.getRGBdefault();
+
+ c1 = color1.getRGB();
+ c2 = color2.getRGB();
+
+ double px = point2.getX() - point1.getX();
+ double py = point2.getY() - point1.getY();
+
+ Point2D p = t.transform(point1, null);
+ Point2D bx = new Point2D.Double(px, py);
+ Point2D by = new Point2D.Double(py, -px);
+
+ t.deltaTransform(bx, bx);
+ t.deltaTransform(by, by);
+
+ double vec = bx.getX() * by.getY() - bx.getY() * by.getX();
+
+ if (Math.abs(vec) < ZERO) {
+ dx = dy = delta = 0;
+ table = new int[1];
+ table[0] = c1;
+ } else {
+ double mult = LOOKUP_SIZE * 256 / vec;
+ dx = (int)(by.getX() * mult);
+ dy = (int)(by.getY() * mult);
+ delta = (int)((p.getX() * by.getY() - p.getY() * by.getX()) * mult);
+ createTable();
+ }
+ }
+
+ /**
+ * Create color index lookup table. Calculate 256 step trasformation from
+ * the start point color to the end point color. Colors multiplied by 256 to do integer calculations.
+ */
+ void createTable() {
+ double ca = (c1 >> 24) & 0xFF;
+ double cr = (c1 >> 16) & 0xFF;
+ double cg = (c1 >> 8) & 0xFF;
+ double cb = c1 & 0xFF;
+
+ double k = 1.0 / LOOKUP_SIZE;
+ double da = (((c2 >> 24) & 0xFF) - ca) * k;
+ double dr = (((c2 >> 16) & 0xFF) - cr) * k;
+ double dg = (((c2 >> 8) & 0xFF) - cg) * k;
+ double db = ((c2 & 0xFF) - cb) * k;
+
+ table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE : LOOKUP_SIZE];
+ for(int i = 0; i < LOOKUP_SIZE; i++) {
+ table[i] =
+ (int)ca << 24 |
+ (int)cr << 16 |
+ (int)cg << 8 |
+ (int)cb;
+ ca += da;
+ cr += dr;
+ cg += dg;
+ cb += db;
+ }
+ if (cyclic) {
+ for(int i = 0; i < LOOKUP_SIZE; i++) {
+ table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i];
+ }
+ }
+ }
+
+ public ColorModel getColorModel() {
+ return cm;
+ }
+
+ public void dispose() {
+ }
+
+ public Raster getRaster(int x, int y, int w, int h) {
+ WritableRaster rast = cm.createCompatibleWritableRaster(w, h);
+
+ int[] buf = ((DataBufferInt)rast.getDataBuffer()).getData();
+
+ int c = x * dy - y * dx - delta;
+ int cx = dy;
+ int cy = - w * dy - dx;
+ int k = 0;
+
+ if (cyclic) {
+ for(int j = 0; j < h; j++) {
+ for(int i = 0; i < w; i++) {
+ buf[k++] = table[(c >> 8) & LOOKUP_MASK];
+ c += cx;
+ }
+ c += cy;
+ }
+ } else {
+ for(int j = 0; j < h; j++) {
+ for(int i = 0; i < w; i++) {
+ int index = c >> 8;
+ buf[k++] = index < 0 ? c1 : index >= LOOKUP_SIZE ? c2 : table[index];
+ c += cx;
+ }
+ c += cy;
+ }
+ }
+
+ return rast;
+ }
+
+}
+
diff --git a/awt/java/awt/Graphics.java b/awt/java/awt/Graphics.java
new file mode 100644
index 0000000..c20f6bc
--- /dev/null
+++ b/awt/java/awt/Graphics.java
@@ -0,0 +1,737 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.ImageObserver;
+import java.text.AttributedCharacterIterator;
+
+/**
+ * The abstract Graphics class allows applications to draw on a screen
+ * or other rendering target. There are several properties which
+ * define rendering options: origin point, clipping area, color, font.
+ * <br><br>
+ * The origin point specifies the beggining of the clipping area coordinate
+ * system. All coordinates used in rendering operations are computed with
+ * respect to this point. The clipping area defines the boundaries where
+ * rendering operations can be performed. Rendering operations can't modify
+ * pixels outside of the clipping area.
+ * <br><br>
+ * The draw and fill methods allow applications to drawing shapes, text,
+ * images with specified font and color options in the specified part
+ * of the screen.
+ *
+ */
+public abstract class Graphics {
+
+ // Constructors
+
+ /**
+ * Instantiates a new Graphics. This constructor is default for Graphics and
+ * can not be called directly.
+ */
+ protected Graphics() {
+ }
+
+ // Public methods
+
+ /**
+ * Creates a copy of the Graphics object with a new origin and a new
+ * specified clip area. The new clip area is the rectangle defined by
+ * the origin point with coordinates X,Y and the given width and height.
+ * The coordinates of all subsequent rendering operations will be computed
+ * with respect to the new origin and can be performed only within the
+ * range of the clipping area dimentions.
+ *
+ * @param x the X coordinate of the original point
+ * @param y the Y coordinate of the original point
+ * @param width the width of clipping area
+ * @param height the height of clipping area
+ *
+ * @return the Graphics object with new origin point and clipping area.
+ */
+ public Graphics create(int x, int y, int width, int height) {
+ Graphics res = create();
+ res.translate(x, y);
+ res.clipRect(0, 0, width, height);
+ return res;
+ }
+
+ /**
+ * Draws the higlighted outline of a rectangle.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ */
+ public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+ // Note: lighter/darker colors should be used to draw 3d rect.
+ // The resulting rect is (width+1)x(height+1). Stroke and paint attributes of
+ // the Graphics2D should be reset to the default values.
+ // fillRect is used instead of drawLine to bypass stroke
+ // reset/set and rasterization.
+
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ }
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ /**
+ * Draws the text represented by byte array. This method uses the current
+ * font and color for rendering.
+ *
+ * @param bytes the byte array which contains the text to be drawn.
+ * @param off the offset within the byte array of the text to be drawn.
+ * @param len the number of bytes of text to draw.
+ * @param x the X coordinate where the text is to be drawn.
+ * @param y the Y coordinate where the text is to be drawn.
+ */
+ public void drawBytes(byte[] bytes, int off, int len, int x, int y) {
+ drawString(new String(bytes, off, len), x, y);
+ }
+
+ /**
+ * Draws the text represented by character array. This method uses the
+ * current font and color for rendering.
+ *
+ * @param chars the character array.
+ * @param off the offset within the character array of the text to be drawn.
+ * @param len the number of characters which will be drawn.
+ * @param x the X coordinate where the text is to be drawn.
+ * @param y the Y coordinate where the text is to be drawn.
+ */
+ public void drawChars(char[] chars, int off, int len, int x, int y) {
+ drawString(new String(chars, off, len), x, y);
+ }
+
+ /**
+ * Draws the outline of a polygon which is defined by Polygon object.
+ *
+ * @param p the Polygon object.
+ */
+ public void drawPolygon(Polygon p) {
+ drawPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ /**
+ * Draws the rectangle with the specified width and length and top left
+ * corner coordinates.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ */
+ public void drawRect(int x, int y, int width, int height) {
+ int []xpoints = {x, x, x+width, x+width};
+ int []ypoints = {y, y+height, y+height, y};
+
+ drawPolygon(xpoints, ypoints, 4);
+ }
+
+ /**
+ * Fills the higlighted outline of a rectangle.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ */
+ public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+ // Note: lighter/darker colors should be used to draw 3d rect.
+ // The resulting rect is (width)x(height), same as fillRect.
+ // Stroke and paint attributes of the Graphics2D should be reset
+ // to the default values. fillRect is used instead of drawLine to
+ // bypass stroke reset/set and line rasterization.
+
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ setColor(color);
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ setColor(colorUp);
+ }
+
+ width--;
+ height--;
+ fillRect(x+1, y+1, width-1, height-1);
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ /**
+ * Fills the polygon with the current color.
+ *
+ * @param p the Polygon object.
+ */
+ public void fillPolygon(Polygon p) {
+ fillPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ /**
+ * Disposes of the Graphics.
+ */
+ @Override
+ public void finalize() {
+ }
+
+ /**
+ * Gets the bounds of the current clipping area as a rectangle
+ * and copies it to an existing rectangle.
+ *
+ * @param r a Rectangle object where the current clipping area
+ * bounds are to be copied.
+ *
+ * @return the bounds of the current clipping area.
+ */
+ public Rectangle getClipBounds(Rectangle r) {
+ Shape clip = getClip();
+
+ if (clip != null) {
+ // TODO: Can we get shape bounds without creating Rectangle object?
+ Rectangle b = clip.getBounds();
+ r.x = b.x;
+ r.y = b.y;
+ r.width = b.width;
+ r.height = b.height;
+ }
+
+ return r;
+ }
+
+ /**
+ * Gets the bounds of the current clipping area as a rectangle.
+ *
+ * @return a Rectangle object
+ *
+ * @deprecated Use {@link #getClipBounds()}
+ */
+ @Deprecated
+ public Rectangle getClipRect() {
+ return getClipBounds();
+ }
+
+ /**
+ * Gets the font metrics of the current font.
+ * The font metrics object contains information about the rendering
+ * of a particular font.
+ *
+ * @return the font metrics of current font.
+ */
+ public FontMetrics getFontMetrics() {
+ return getFontMetrics(getFont());
+ }
+
+ /**
+ * Determines whether or not the specified rectangle intersects the
+ * current clipping area.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ *
+ * @return true, if the specified rectangle intersects the current clipping area,
+ * overwise false.
+ */
+ public boolean hitClip(int x, int y, int width, int height) {
+ // TODO: Create package private method Rectangle.intersects(int, int, int, int);
+ return getClipBounds().intersects(new Rectangle(x, y, width, height));
+ }
+
+ /**
+ * Returns string which represents this Graphics object.
+ *
+ * @return the string which represents this Graphics object.
+ */
+ @Override
+ public String toString() {
+ // TODO: Think about string representation of Graphics.
+ return "Graphics"; //$NON-NLS-1$
+ }
+
+ // Abstract methods
+
+ /**
+ * Clears the specified rectangle. This method fills specified rectangle
+ * with background color.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ */
+ public abstract void clearRect(int x, int y, int width, int height);
+
+ /**
+ * Intersects the current clipping area with a new rectangle.
+ * If the current clipping area is not defined, the rectangle
+ * becomes a new clipping area. Rendering operations are only allowed
+ * within the new the clipping area.
+ *
+ * @param x the X coordinate of the rectangle for intersection.
+ * @param y the Y coordinate of the rectangle for intersection.
+ * @param width the width of the rectangle for intersection.
+ * @param height the height of the rectangle for intersection.
+ */
+ public abstract void clipRect(int x, int y, int width, int height);
+
+ /**
+ * Copies the rectangle area to another area specified by
+ * a distance (dx, dy) from the original rectangle's location.
+ * Positive dx and dy values give a new location defined by
+ * translation to the right and down from the original location,
+ * negative dx and dy values - to the left and up.
+ * <br><br>
+ *
+ * @param sx the X coordinate of the rectangle which will be copied.
+ * @param sy the Y coordinate of the rectangle which will be copied.
+ * @param width the width of the rectangle which will be copied.
+ * @param height the height of the rectangle which will be copied.
+ * @param dx the horizontal distance from the source rectangle's
+ * location to the copy's location.
+ * @param dy the vertical distance from the source rectangle's
+ * location to the copy's location.
+ */
+ public abstract void copyArea(int sx, int sy, int width, int height, int dx, int dy);
+
+ /**
+ * Creates a new copy of this Graphics.
+ *
+ * @return a new Graphics context which is a copy of this Graphics.
+ */
+ public abstract Graphics create();
+
+ /**
+ * Disposes of the Graphics. This Graphics object can not be used after
+ * calling this method.
+ */
+ public abstract void dispose();
+
+ /**
+ * Draws the arc covering the specified rectangle and using the current color.
+ * The rectangle is defined by the origin point (X, Y) and dimentions
+ * (width and height). The arc center is the the center of specified rectangle.
+ * The angle origin is 3 o'clock position, the positive angle is counted as a
+ * counter-clockwise rotation, the negotive angle is counted as clockwise rotation.
+ *
+ * @param x the X origin coordinate of the rectangle which scales the arc.
+ * @param y the Y origin coordinate of the rectangle which scales the arc.
+ * @param width the width of the rectangle which scales the arc.
+ * @param height the height of the rectangle which scales the arc.
+ * @param sa start angle - the origin angle of arc.
+ * @param ea arc angle - the angular arc value relative to the start angle.
+ */
+ public abstract void drawArc(int x, int y, int width, int height, int sa, int ea);
+
+ /**
+ * Draws the specified image with the defined background color.
+ * The top left corner of image will be drawn at point (x, y)
+ * in current coordinate system. The image loading process notifies the
+ * specified Image Observer. This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image top left corner.
+ * @param y the Y coordinate of the image top left corner.
+ * @param bgcolor the background color.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer);
+
+ /**
+ * Draws the specified image.
+ * The top left corner of image will be drawn at point (x, y)
+ * in current coordinate system. The image loading process notifies the
+ * specified Image Observer. This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image top left corner.
+ * @param y the Y coordinate of the image top left corner.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer);
+
+ /**
+ * Scales the specified image to fit in the specified rectangle and
+ * draws it with the defined background color. The top left corner
+ * of the image will be drawn at the point (x, y) in current coordinate
+ * system. The non-opaque pixels will be drawn in the background color.
+ * The image loading process notifies the specified Image Observer.
+ * This method returns true if the image has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image's top left corner.
+ * @param y the Y coordinate of the image's top left corner.
+ * @param width the width of rectangle which scales the image.
+ * @param height the height of rectangle which scales the image.
+ * @param bgcolor the background color.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer);
+
+ /**
+ * Scales the specified image to fit in the specified rectangle and
+ * draws it. The top left corner of the image will be drawn at the
+ * point (x, y) in current coordinate system. The image loading process
+ * notifies the specified Image Observer.
+ * This method returns true if the image has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image top left corner.
+ * @param y the Y coordinate of the image top left corner.
+ * @param width the width of rectangle which scales the image.
+ * @param height the height of rectangle which scales the image.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer);
+
+ /**
+ * Scales the specified area of the specified image to fit in the rectangle area
+ * defined by its corners coordinates and draws the sub-image with the specified
+ * background color. The sub-image to be drawn is defined by its top left
+ * corner coordinates (sx1, sy1) and bottom right corner coordinates (sx2, sy2)
+ * computed with respect to the origin (top left corner) of the source image.
+ * The non opaque pixels will be drawn in the background color. The
+ * image loading process notifies specified Image Observer.
+ * This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param dx1 the X top left corner coordinate of the destination rectangle area.
+ * @param dy1 the Y top left corner coordinate of the destination rectangle area.
+ * @param dx2 the X bottom right corner coordinate of the destination rectangle area.
+ * @param dy2 the Y bottom right corner coordinate of the destination rectangle area.
+ * @param sx1 the X top left corner coordinate of the area to be drawn within the source image.
+ * @param sy1 the Y top left corner coordinate of the area to be drawn within the source image.
+ * @param sx2 the X bottom right corner coordinate of the area to be drawn within the source image.
+ * @param sy2 the Y bottom right corner coordinate of the area to be drawn within the source image.
+ * @param bgcolor the background color.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer);
+
+ /**
+ * Scales the specified area of the specified image to fit in the rectangle area
+ * defined by its corners coordinates and draws the sub-image. The sub-image
+ * to be drawn is defined by its top left
+ * corner coordinates (sx1, sy1) and bottom right corner coordinates (sx2, sy2)
+ * computed with respect to the origin (top left corner) of the source image.
+ * The image loading process notifies specified Image Observer.
+ * This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param dx1 the X top left corner coordinate of the destination rectangle area.
+ * @param dy1 the Y top left corner coordinate of the destination rectangle area.
+ * @param dx2 the X bottom right corner coordinate of the destination rectangle area.
+ * @param dy2 the Y bottom right corner coordinate of the destination rectangle area.
+ * @param sx1 the X top left corner coordinate of the area to be drawn within the source image.
+ * @param sy1 the Y top left corner coordinate of the area to be drawn within the source image.
+ * @param sx2 the X bottom right corner coordinate of the area to be drawn within the source image.
+ * @param sy2 the Y bottom right corner coordinate of the area to be drawn within the source image.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer);
+
+ /**
+ * Draws a line from the point (x1, y1) to the point (x2, y2).
+ * This method draws the line with current color
+ * which can be changed by setColor(Color c) method.
+ *
+ * @param x1 the X coordinate of the first point.
+ * @param y1 the Y coordinate of the first point.
+ * @param x2 the X coordinate of the second point.
+ * @param y2 the Y coordinate of the second point.
+ */
+ public abstract void drawLine(int x1, int y1, int x2, int y2);
+
+ /**
+ * Draws the ouline of an oval to fit in the rectangle defined
+ * by the given width, height, and top left corner.
+ *
+ * @param x the X top left corner oval coordinate
+ * @param y the Y top left corner oval coordinate
+ * @param width the oval width
+ * @param height the oval height
+ */
+ public abstract void drawOval(int x, int y, int width, int height);
+
+ /**
+ * Draws the outline of a polygon. The polygon vertices are defined by points
+ * with xpoints[i], ypoints[i] as coordinates. The polygon edges are the
+ * lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates to
+ * the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < npoints +1.
+ *
+ * @param xpoints the array of X coordinates of the polygon vertices.
+ * @param ypoints the array of Y coordinates of the polygon vertices.
+ * @param npoints the number of polygon vertices/points.
+ */
+ public abstract void drawPolygon(int[] xpoints, int[] ypoints, int npoints);
+
+ /**
+ * Draws a set of connected lines which are defined by the x and y coordinate arrays.
+ * The polyline is closed if coordinates of the first point are the same as
+ * coordinates of the last point.
+ *
+ * @param xpoints the array of X point coordinates.
+ * @param ypoints the array of Y point coordinates.
+ * @param npoints the number of points.
+ */
+ public abstract void drawPolyline(int[] xpoints, int[] ypoints, int npoints);
+
+ /**
+ * Draws the outline of a rectangle with round corners.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ * @param arcWidth the arc width for the corners.
+ * @param arcHeight the arc height for the corners.
+ */
+ public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
+
+ /**
+ * Draws a text defined by an iterator. The iterator should specify the font
+ * for every character.
+ *
+ * @param iterator the iterator.
+ * @param x the X coordinate of the firt character.
+ * @param y the Y coordinate of the first character.
+ */
+ public abstract void drawString(AttributedCharacterIterator iterator, int x, int y);
+
+ /**
+ * Draws a text defined by a string. This method draws the text with current
+ * font and color.
+ *
+ * @param str the string.
+ * @param x the X coordinate of the firt character.
+ * @param y the Y coordinate of the first character.
+ */
+ public abstract void drawString(String str, int x, int y);
+
+ /**
+ * Fills the arc covering the rectangle and using the current color.
+ * The rectangle is defined by the origin point (X, Y) and dimentions (width and height).
+ * The arc center is the the center of specified rectangle.
+ * The angle origin is at the 3 o'clock position, and a positive angle gives
+ * counter-clockwise rotation, a negative angle gives clockwise rotation.
+ *
+ * @param x the X origin coordinate of the rectangle which scales the arc.
+ * @param y the Y origin coordinate of the rectangle which scales the arc.
+ * @param width the width of the rectangle which scales the arc.
+ * @param height the height of the rectangle which scales the arc.
+ * @param sa start angle - the origin angle of arc.
+ * @param ea arc angle - the angular arc value relative to the start angle.
+ */
+ public abstract void fillArc(int x, int y, int width, int height, int sa, int ea);
+
+ /**
+ * Fills an oval with the current color where the oval is defined by the
+ * bounding rectangle with the given width, height, and top left corner.
+ *
+ * @param x the X top left corner oval coordinate.
+ * @param y the Y top left corner oval coordinate.
+ * @param width the oval width.
+ * @param height the oval height.
+ */
+ public abstract void fillOval(int x, int y, int width, int height);
+
+ /**
+ * Fills a polygon with the current color. The polygon vertices are defined by the points
+ * with xpoints[i], ypoints[i] as coordinates. The polygon edges are the
+ * lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates to
+ * the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < npoints +1.
+ *
+ * @param xpoints the array of X coordinates of the polygon vertices.
+ * @param ypoints the array of Y coordinates of the polygon vertices.
+ * @param npoints the number of polygon vertices/points.
+ */
+ public abstract void fillPolygon(int[] xpoints, int[] ypoints, int npoints);
+
+ /**
+ * Fills a rectangle with the current color.
+ * The rectangle is defined by its width and length and top left corner coordinates.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public abstract void fillRect(int x, int y, int width, int height);
+
+ /**
+ * Fills a round cornered rectangle with the current color.
+ *
+ * @param x the X coordinate of the top left corner of the bounding rectangle.
+ * @param y the Y coordinate of the top left corner of the bounding rectangle.
+ * @param width the width of the bounding rectangle.
+ * @param height the height of the bounding rectangle.
+ * @param arcWidth the arc width at the corners.
+ * @param arcHeight the arc height at the corners.
+ */
+ public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
+
+ /**
+ * Gets the clipping area.
+ * <br> <br>
+ *
+ * @return a Shape object of the clipping area or null if it is not set.
+ */
+ public abstract Shape getClip();
+
+ /**
+ * Gets the bounds of the current clipping area as a rectangle.
+ *
+ * @return a Rectangle object which represents the bounds of the current clipping area.
+ */
+ public abstract Rectangle getClipBounds();
+
+ /**
+ * Gets the current color of Graphics.
+ *
+ * @return the current color.
+ */
+ public abstract Color getColor();
+
+ /**
+ * Gets the current font of Graphics.
+ *
+ * @return the current font.
+ */
+ public abstract Font getFont();
+
+ /**
+ * Gets the font metrics of the specified font.
+ * The font metrics object contains information about the rendering of a particular font.
+ *
+ * @param font the specified font
+ *
+ * @return the font metrics for the specified font.
+ */
+ public abstract FontMetrics getFontMetrics(Font font);
+
+ /**
+ * Sets the new clipping area specified by rectangle. The new clipping area
+ * doesn't depend on the window's visibility. Rendering operations can't be performed
+ * outside new clipping area.
+ *
+ * @param x the X coordinate of the new clipping rectangle.
+ * @param y the Y coordinate of the new clipping rectangle.
+ * @param width the width of the new clipping rectangle.
+ * @param height the height of the new clipping rectangle.
+ */
+ public abstract void setClip(int x, int y, int width, int height);
+
+ /**
+ * Sets the new clipping area to be the area specified by Shape object.
+ * The new clipping area doesn't depend on the window's visibility.
+ * Rendering operations can't be performed outside new clipping area.
+ *
+ * @param clip a Shape object which representes new clipping area.
+ */
+ public abstract void setClip(Shape clip);
+
+ /**
+ * Sets the current Graphics color. All rendering operations with this Graphics
+ * will use this color.
+ *
+ * @param c the new color.
+ */
+ public abstract void setColor(Color c);
+
+ /**
+ * Sets the current Graphics font. All rendering operations with this Graphics
+ * will use this font.
+ *
+ * @param font the new font.
+ */
+ public abstract void setFont(Font font);
+
+ /**
+ * Sets the paint mode for the Graphics which overwrites all rendering
+ * operations with the current color.
+ *
+ */
+ public abstract void setPaintMode();
+
+ /**
+ * Sets the XOR mode for the Graphics which changes a pixel from
+ * the current color to the specified XOR color.
+ * <br> <br>
+ *
+ * @param color the new XOR mode
+ */
+ public abstract void setXORMode(Color color);
+
+ /**
+ * Translates the origin of Graphics current coordinate system
+ * to the point with X, Y coordinates in the current coordinate system.
+ * All rendering operation in this Graphics will be related to the new origin.
+ *
+ * @param x the X coordinate of the origin
+ * @param y the Y coordinate of the origin
+ */
+ public abstract void translate(int x, int y);
+}
diff --git a/awt/java/awt/Graphics2D.java b/awt/java/awt/Graphics2D.java
new file mode 100644
index 0000000..2ff5e0c
--- /dev/null
+++ b/awt/java/awt/Graphics2D.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.font.GlyphVector;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+/**
+ * The Graphics2D class extends Graphics class and provides more capabilities
+ * for rendering text, images, shapes. This provides methods to peform
+ * transformation of coordinate system, color management, and text layout.
+ * The following attributes exist for rendering:
+ * <ul>
+ * <li>Color - current Graphics2D color;</li>
+ * <li>Font - current Graphics2D font;</li>
+ * <li>Stroke - pen with a width of 1 pixel;</li>
+ * <li>Transform - current Graphics2D Transformation;</li>
+ * <li>Composite - alpha compositing rules for combining source and destination colors.</li>
+ * </ul>
+ */
+public abstract class Graphics2D extends Graphics {
+
+ /**
+ * Instantiates a new Graphics2D object. This constructor should never be
+ * called directly.
+ */
+ protected Graphics2D() {
+ super();
+ }
+
+ /**
+ * Adds preferences for the rendering algorithms. The preferences
+ * are arbitrary and specified by Map objects. All specified by Map object
+ * preferencies can be modified.
+ *
+ * @param hints the rendering hints.
+ */
+ public abstract void addRenderingHints(Map<?, ?> hints);
+
+ /**
+ * Intersects the current clipping area with the specified Shape
+ * and the result becomes a new clipping area.
+ * If current clipping area is not defined, the Shape
+ * becomes the new clipping area. No rendering operations
+ * are allowed outside the clipping area.
+ *
+ * @param s the specified Shape object which will be intersected
+ * with current clipping area.
+ */
+ public abstract void clip(Shape s);
+
+ /**
+ * Draws the outline of the specified Shape.
+ *
+ * @param s the Shape which ouline is drawn.
+ */
+ public abstract void draw(Shape s);
+
+ /**
+ * Draws the specified GlyphVector object's text at the point x, y.
+ *
+ * @param g the GlyphVector object to be drawn.
+ * @param x the X position where the GlyphVector's text should
+ * be rendered.
+ * @param y the Y position where the GlyphVector's text should
+ * be rendered.
+ */
+ public abstract void drawGlyphVector(GlyphVector g, float x, float y);
+
+ /**
+ * Draws the BufferedImage -- modified according to the operation
+ * BufferedImageOp -- at the point x, y.
+ *
+ * @param img the BufferedImage to be rendered.
+ * @param op the filter to be applied to the image before rendering.
+ * @param x the X coordinate of the point where the image's upper left corner
+ * will be placed.
+ * @param y the Y coordinate of the point where the image's upper left corner
+ * will be placed.
+ */
+ public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y);
+
+ /**
+ * Draws BufferedImage transformed from image space into user space
+ * according to the AffineTransform xform and notifies the ImageObserver.
+ *
+ * @param img the BufferedImage to be rendered.
+ * @param xform the affine transformation from the image to the user space.
+ * @param obs the ImageObserver to be notified about the image conversion.
+ *
+ * @return true, if the image is successfully loaded and rendered,
+ * or it's null, otherwise false.
+ */
+ public abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs);
+
+ /**
+ * Draws a RenderableImage which is transformed from image space into user
+ * according to the AffineTransform xform.
+ *
+ * @param img the RenderableImage to be rendered.
+ * @param xform the affine transformation from image to user space.
+ */
+ public abstract void drawRenderableImage(RenderableImage img, AffineTransform xform);
+
+ /**
+ * Draws a RenderedImage which is transformed from image space into user
+ * according to the AffineTransform xform.
+ *
+ * @param img the RenderedImage to be rendered.
+ * @param xform the affine transformation from image to user space.
+ */
+ public abstract void drawRenderedImage(RenderedImage img, AffineTransform xform);
+
+ /**
+ * Draws the string specified by the AttributedCharacterIterator.
+ * The first character's position is specified by the X, Y parameters.
+ *
+ * @param iterator whose text is drawn.
+ * @param x the X position where the first character is drawn.
+ * @param y the Y position where the first character is drawn.
+ */
+ public abstract void drawString(AttributedCharacterIterator iterator, float x, float y);
+
+ /**
+ * Draws the string specified by the AttributedCharacterIterator.
+ * The first character's position is specified by the X, Y parameters.
+ *
+ * @param iterator whose text is drawn.
+ * @param x the X position where the first character is drawn.
+ * @param y the Y position where the first character is drawn.
+ *
+ * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int)
+ */
+ @Override
+ public abstract void drawString(AttributedCharacterIterator iterator, int x, int y);
+
+ /**
+ * Draws the String whose the first character position is specified
+ * by the parameters X, Y.
+ *
+ * @param s the String to be drawn.
+ * @param x the X position of the first character.
+ * @param y the Y position of the first character.
+ */
+ public abstract void drawString(String s, float x, float y);
+
+ /**
+ * Draws the String whose the first character coordinates are specified
+ * by the parameters X, Y.
+ *
+ * @param str the String to be drawn.
+ * @param x the X coordinate of the first character.
+ * @param y the Y coordinate of the first character.
+ *
+ * @see java.awt.Graphics#drawString(String, int, int)
+ */
+ @Override
+ public abstract void drawString(String str, int x, int y);
+
+ /**
+ * Fills the interior of the specified Shape.
+ *
+ * @param s the Shape to be filled.
+ */
+ public abstract void fill(Shape s);
+
+ /**
+ * Gets the background color.
+ *
+ * @return the current background color.
+ */
+ public abstract Color getBackground();
+
+ /**
+ * Gets the current composite of the Graphics2D.
+ *
+ * @return the current composite which specifies the compositing style.
+ */
+ public abstract Composite getComposite();
+
+ /**
+ * Gets the device configuration.
+ *
+ * @return the device configuration
+ */
+ public abstract GraphicsConfiguration getDeviceConfiguration();
+
+ /**
+ * Gets the rendering context of the Font.
+ *
+ * @return the FontRenderContext.
+ */
+ public abstract FontRenderContext getFontRenderContext();
+
+ /**
+ * Gets the current Paint of Graphics2D.
+ *
+ * @return the current Paint of Graphics2D.
+ */
+ public abstract Paint getPaint();
+
+ /**
+ * Gets the value of single preference for specified key.
+ *
+ * @param key the specified key of the rendering hint.
+ *
+ * @return the value of rendering hint for specified key.
+ */
+ public abstract Object getRenderingHint(RenderingHints.Key key);
+
+ /**
+ * Gets the set of the rendering preferences as a collection of
+ * key/value pairs.
+ *
+ * @return the RenderingHints which contains the rendering preferences.
+ */
+ public abstract RenderingHints getRenderingHints();
+
+ /**
+ * Gets current stroke of the Graphics2D.
+ *
+ * @return current stroke of the Graphics2D.
+ */
+ public abstract Stroke getStroke();
+
+ /**
+ * Gets current affine transform of the Graphics2D.
+ *
+ * @return current AffineTransform of the Graphics2D.
+ */
+ public abstract AffineTransform getTransform();
+
+ /**
+ * Determines wether or not the specified Shape intersects the specified
+ * Rectangle. If the onStroke parameter is true, this method
+ * checks whether or not the specified Shape outline intersects the specified
+ * Rectangle, otherwise this method checks whether or not the specified
+ * Shape's interior intersects the specified Rectangle.
+ *
+ * @param rect the specified Rectangle.
+ * @param s the Shape to check for intersection.
+ * @param onStroke the parameter determines whether or not this method checks
+ * for intersection of the Shape outline or of the Shape interior with
+ * the Rectangle.
+ *
+ * @return true, if there is a hit, otherwise false.
+ */
+ public abstract boolean hit(Rectangle rect, Shape s, boolean onStroke);
+
+ /**
+ * Performs a rotation transform relative to current Graphics2D Transform.
+ * The coordinate system is rotated by the specified angle in radians relative to
+ * current origin.
+ *
+ * @param theta the angle of rotation in radians.
+ */
+ public abstract void rotate(double theta);
+
+ /**
+ * Performs a translated rotation transform relative to current Graphics2D
+ * Transform. The coordinate system is rotated by the specified angle in radians
+ * relative to current origin and then moved to point (x, y).
+ *
+ * Is this right?
+ *
+ * @param theta the angle of rotation in radians.
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ */
+ public abstract void rotate(double theta, double x, double y);
+
+ /**
+ * Performs a linear scale transform relative to current Graphics2D Transform.
+ * The coordinate system is rescaled vertically and horizontally
+ * by the specified parameters.
+ *
+ * @param sx the scaling factor by which the X coordinate is multiplied.
+ * @param sy the scaling factor by which the Y coordinate is multiplied.
+ */
+ public abstract void scale(double sx, double sy);
+
+ /**
+ * Sets a new background color for clearing rectangular areas.
+ * The clearRect method uses the current background color.
+ *
+ * @param color the new background color.
+ */
+ public abstract void setBackground(Color color);
+
+ /**
+ * Sets the current composite for Graphics2D.
+ *
+ * @param comp the Composite object.
+ */
+ public abstract void setComposite(Composite comp);
+
+ /**
+ * Sets the paint for Graphics2D.
+ *
+ * @param paint the Paint object.
+ */
+ public abstract void setPaint(Paint paint);
+
+ /**
+ * Sets a key-value pair in the current RenderingHints map.
+ *
+ * @param key the key of the rendering hint to set.
+ * @param value the value to set for the rendering hint.
+ */
+ public abstract void setRenderingHint(RenderingHints.Key key, Object value);
+
+ /**
+ * Replaces the current rendering hints with the specified rendering preferences.
+ *
+ * @param hints the new Map of rendering hints.
+ */
+ public abstract void setRenderingHints(Map<?, ?> hints);
+
+ /**
+ * Sets the stroke for the Graphics2D.
+ *
+ * @param s the Stroke object.
+ */
+ public abstract void setStroke(Stroke s);
+
+ /**
+ * Overwrite the current Transform of the Graphics2D. The specified Transform
+ * should be received from the getTransform() method and should be used
+ * only for restoring the original Graphics2D transform after calling
+ * draw or fill methods.
+ *
+ * @param Tx the specified Transform.
+ */
+ public abstract void setTransform(AffineTransform Tx);
+
+ /**
+ * Performs a shear transform relative to current Graphics2D Transform.
+ * The coordinate system is shifted by the specified multipliers relative to
+ * current position.
+ *
+ * @param shx the multiplier by which the X coordinates shift position
+ * along X axis as a function of Y coordinates.
+ * @param shy the multiplier by which the Y coordinates shift position
+ * along Y axis as a function of X coordinates.
+ */
+ public abstract void shear(double shx, double shy);
+
+ /**
+ * Concatenates the AffineTransform object with current Transform
+ * of this Graphics2D. The transforms are applied in reverse order
+ * with the last specified transform applied first and the next
+ * transformation applied to the result of previous transformation.
+ * More precisely, if Cx is the current Graphics2D transform, the
+ * transform method's result with Tx as the parameter
+ * is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p - a point
+ * in current coordinate system. Rx becomes the current Transform
+ * for this Graphics2D.
+ *
+ * @param Tx the AffineTransform object to be concatenated with
+ * current Transform.
+ */
+ public abstract void transform(AffineTransform Tx);
+
+ /**
+ * Performs a translate transform relative to current Graphics2D Transform.
+ * The coordinate system is moved by the specified distance relative
+ * to current position.
+ *
+ * @param tx the translation distance along the X axis.
+ * @param ty the translation distance along the Y axis.
+ */
+ public abstract void translate(double tx, double ty);
+
+ /**
+ * Moves the origin Graphics2D Transform to the point with x, y
+ * coordinates in current coordinate system. The new origin of coordinate
+ * system is moved to the (x, y) point accordingly. All rendering and
+ * transform operations are performed relative to this new origin.
+ *
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ *
+ * @see java.awt.Graphics#translate(int, int)
+ */
+ @Override
+ public abstract void translate(int x, int y);
+
+ /**
+ * Fills a 3D rectangle with the current color.
+ * The rectangle is specified by its width, height, and top left corner
+ * coordinates.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ *
+ * @see java.awt.Graphics#fill3DRect(int, int, int, int, boolean)
+ */
+ @Override
+ public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+ // According to the spec, color should be used instead of paint,
+ // so Graphics.fill3DRect resets paint and
+ // it should be restored after the call
+ Paint savedPaint = getPaint();
+ super.fill3DRect(x, y, width, height, raised);
+ setPaint(savedPaint);
+ }
+
+ /**
+ * Draws the higlighted outline of a rectangle.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ *
+ * @see java.awt.Graphics#draw3DRect(int, int, int, int, boolean)
+ */
+ @Override
+ public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+ // According to the spec, color should be used instead of paint,
+ // so Graphics.draw3DRect resets paint and
+ // it should be restored after the call
+ Paint savedPaint = getPaint();
+ super.draw3DRect(x, y, width, height, raised);
+ setPaint(savedPaint);
+ }
+} \ No newline at end of file
diff --git a/awt/java/awt/GraphicsConfiguration.java b/awt/java/awt/GraphicsConfiguration.java
new file mode 100644
index 0000000..8bec253
--- /dev/null
+++ b/awt/java/awt/GraphicsConfiguration.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicsConfiguration class contains the characteristics of graphics
+ * devices such as a printer or monitor, and represents device's capabilities
+ * and modes. Many GraphicsConfiguration objects can be associated with
+ * single graphics device.
+ */
+public abstract class GraphicsConfiguration {
+
+ /**
+ * Constructor could not be used directly and should be obtained in
+ * extended classes.
+ */
+
+ protected GraphicsConfiguration() {
+ }
+
+
+ /**
+ * Creates BufferedImage image object with a data layout and color model
+ * compatible with this GraphicsConfiguration with specified width
+ * and height parameters.
+ *
+ * @param width the width of BufferedImage.
+ * @param height the height of BufferedImage.
+ *
+ * @return the BufferedImage object with specified width and height
+ * parameters.
+ */
+ public abstract BufferedImage createCompatibleImage(int width, int height);
+
+ /**
+ * Creates a BufferedImage that has the specified width, height,
+ * transparency and has a data layout and color model compatible with this
+ * GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param transparency the transparency mode.
+ *
+ * @return the BufferedImage object.
+ */
+ public abstract BufferedImage createCompatibleImage(int width, int height, int transparency);
+
+ /**
+ * Creates a VolatileImage that has the specified width and height
+ * and has a data layout and color model compatible with this
+ * GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ *
+ * @return the VolatileImage object.
+ */
+ public abstract VolatileImage createCompatibleVolatileImage(int width, int height);
+
+ /**
+ * Creates a VolatileImage that supports the specified width, height,
+ * transparency and has a data layout and color model compatible with this
+ * GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param transparency the transparency mode.
+ *
+ * @return the VolatileImage object.
+ */
+ public abstract VolatileImage createCompatibleVolatileImage(int width, int height, int transparency);
+
+ /**
+ * Gets the bounds of area covered by the GraphicsConfiguration in the
+ * device coordinates space.
+ *
+ * @return the Rectangle of GraphicsConfiguration's bounds.
+ */
+ public abstract Rectangle getBounds();
+
+ /**
+ * Gets the ColorModel of the GraphicsConfiguration.
+ *
+ * @return the ColorModel object of the GraphicsConfiguration.
+ */
+ public abstract ColorModel getColorModel();
+
+ /**
+ * Gets the ColorModel of the GraphicsConfiguration which
+ * supports specified Transparency.
+ *
+ * @param transparency the Transparency mode: OPAQUE, BITMASK, or
+ * TRANSLUCENT.
+ *
+ * @return the ColorModel of the GraphicsConfiguration which
+ * supports specified Transparency.
+ */
+ public abstract ColorModel getColorModel(int transparency);
+
+ /**
+ * Gets the default AffineTransform of the GraphicsConfiguration.
+ * This method translates user coordinates to device coordinates.
+ *
+ * @return the default AffineTransform of the GraphicsConfiguration.
+ */
+ public abstract AffineTransform getDefaultTransform();
+
+ /**
+ * Gets the GraphicsDevice of the GraphicsConfiguration.
+ *
+ * @return the GraphicsDevice of the GraphicsConfiguration.
+ */
+ public abstract GraphicsDevice getDevice();
+
+ /**
+ * Gets the normalizing AffineTransform of the GraphicsConfiguration.
+ *
+ * @return the normalizing AffineTransform of the GraphicsConfiguration.
+ */
+ public abstract AffineTransform getNormalizingTransform();
+
+
+ /**
+ * Creates VolatileImage with specified width, height, ImageCapabilities;
+ * a data layout and color model compatible with this GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param caps the ImageCapabilities object.
+ *
+ * @return the VolatileImage which data layout and color model compatible
+ * with this GraphicsConfiguration.
+ *
+ * @throws AWTException if ImageCapabilities is not supported by the
+ * GraphicsConfiguration.
+ */
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ ImageCapabilities caps) throws AWTException {
+ VolatileImage res = createCompatibleVolatileImage(width, height);
+ if (!res.getCapabilities().equals(caps)) {
+ // awt.14A=Can not create VolatileImage with specified capabilities
+ throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$
+ }
+ return res;
+ }
+
+ /**
+ * Creates a VolatileImage with specified width, height, transparency
+ * and ImageCapabilities; a data layout and color model compatible with
+ * this GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param caps the ImageCapabilities object.
+ * @param transparency the Transparency mode: OPAQUE, BITMASK, or
+ * TRANSLUCENT.
+ *
+ * @return the VolatileImage which data layout and color model compatible
+ * with this GraphicsConfiguration.
+ *
+ * @throws AWTException if ImageCapabilities is not supported by the
+ * GraphicsConfiguration.
+ */
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ ImageCapabilities caps, int transparency) throws AWTException {
+ VolatileImage res = createCompatibleVolatileImage(width, height, transparency);
+ if (!res.getCapabilities().equals(caps)) {
+ // awt.14A=Can not create VolatileImage with specified capabilities
+ throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$
+ }
+ return res;
+ }
+
+ /**
+ * Gets the buffering capabilities of the GraphicsConfiguration.
+ *
+ * @return the BufferCapabilities object.
+ */
+ public BufferCapabilities getBufferCapabilities() {
+ return new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false),
+ BufferCapabilities.FlipContents.UNDEFINED);
+ }
+
+ /**
+ * Gets the image capabilities of the GraphicsConfiguration.
+ *
+ * @return the ImageCapabilities object.
+ */
+ public ImageCapabilities getImageCapabilities() {
+ return new ImageCapabilities(false);
+ }
+}
diff --git a/awt/java/awt/GraphicsDevice.java b/awt/java/awt/GraphicsDevice.java
new file mode 100644
index 0000000..8cf700a
--- /dev/null
+++ b/awt/java/awt/GraphicsDevice.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicsDevice class describes the graphics devices (such as screens
+ * or printers) which are available in a particular graphics environment.
+ * Many GraphicsDevice instances can be associated with a single
+ * GraphicsEnvironment. Each GraphicsDevice has one or more GraphicsConfiguration
+ * objects which specify the different configurations and modes of GraphicsDevice.
+ */
+public abstract class GraphicsDevice {
+
+ /** The display mode. */
+ private DisplayMode displayMode;
+
+ //???AWT
+// private Window fullScreenWindow = null;
+
+ /** The Constant TYPE_IMAGE_BUFFER indicates a image buffer device. */
+
+ public static final int TYPE_IMAGE_BUFFER = 2;
+
+ /** The Constant TYPE_PRINTER indicates a printer device. */
+ public static final int TYPE_PRINTER = 1;
+
+ /** The Constant TYPE_RASTER_SCREEN indicates a raster screen device. */
+ public static final int TYPE_RASTER_SCREEN = 0;
+
+ /**
+ * Constructor is not to be used directly as this class is abstract.
+ */
+ protected GraphicsDevice() {
+ displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI, DisplayMode.REFRESH_RATE_UNKNOWN);
+ }
+
+
+ /**
+ * Returns an array of GraphicsConfiguration objects associated
+ * with the GraphicsDevice.
+ *
+ * @return an array of GraphicsConfiguration objects associated
+ * with the GraphicsDevice.
+ */
+ public abstract GraphicsConfiguration[] getConfigurations();
+
+ /**
+ * Gets the default configuration for the GraphicsDevice.
+ *
+ * @return the default GraphicsConfiguration object for the GraphicsDevice.
+ */
+ public abstract GraphicsConfiguration getDefaultConfiguration();
+
+ /**
+ * Gets the String identifier which associated with the GraphicsDevice in
+ * the GraphicsEnvironment.
+ *
+ * @return the String identifier of the GraphicsDevice in
+ * the GraphicsEnvironment.
+ */
+ public abstract String getIDstring();
+
+ /**
+ * Gets the type of this GraphicsDevice:
+ * TYPE_IMAGE_BUFFER, TYPE_PRINTER or TYPE_RASTER_SCREEN.
+ *
+ * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER,
+ * TYPE_PRINTER or TYPE_RASTER_SCREEN.
+ */
+ public abstract int getType();
+
+
+
+ /**
+ * Returns the number of bytes available in accelerated
+ * memory on this device.
+ *
+ * @return the number of bytes available accelerated memory.
+ */
+ public int getAvailableAcceleratedMemory() {
+ return 0;
+ }
+
+ /* ???AWT
+ public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) {
+ return gct.getBestConfiguration(getConfigurations());
+ }
+ */
+
+ /**
+ * Gets the current display mode of the GraphicsDevice.
+ *
+ * @return the current display mode of the GraphicsDevice.
+ */
+ public DisplayMode getDisplayMode() {
+ return displayMode;
+ }
+
+ /**
+ * Gets an array of display modes available in this GraphicsDevice.
+ *
+ * @return an array of display modes available in this GraphicsDevice.
+ */
+ public DisplayMode[] getDisplayModes() {
+ DisplayMode []dms = {displayMode};
+ return dms;
+ }
+
+ /* ???AWT
+ public Window getFullScreenWindow() {
+ return fullScreenWindow;
+ }
+ */
+
+ /**
+ * Returns true if this GraphicsDevice supports low-level
+ * display changes.
+ *
+ * @return true, if this GraphicsDevice supports low-level
+ * display changes; false otherwise.
+ */
+ public boolean isDisplayChangeSupported() {
+ return false;
+ }
+
+ /**
+ * Returns true if this GraphicsDevice supports full screen
+ * mode.
+ *
+ * @return true, if this GraphicsDevice supports full screen
+ * mode; otherwise false.
+ */
+ public boolean isFullScreenSupported() {
+ return false;
+ }
+ //an array of display modes available in this GraphicsDevice.
+
+ /**
+ * Sets the display mode of this GraphicsDevice.
+ *
+ * @param dm the new display mode of this GraphicsDevice.
+ */
+ public void setDisplayMode(DisplayMode dm) {
+ if (!isDisplayChangeSupported()) {
+ // awt.122=Does not support display mode changes
+ throw new UnsupportedOperationException(Messages.getString("awt.122")); //$NON-NLS-1$
+ }
+
+ DisplayMode []dms = getDisplayModes();
+ for (DisplayMode element : dms) {
+ if (element.equals(dm)) {
+ displayMode = dm;
+ return;
+ }
+ }
+ // awt.123=Unsupported display mode: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.123", dm)); //$NON-NLS-1$
+ }
+
+ /* ???AWT
+ public void setFullScreenWindow(Window w) {
+ if (w == null) {
+ fullScreenWindow = null;
+ return;
+ }
+
+ fullScreenWindow = w;
+
+ if (isFullScreenSupported()) {
+ w.enableInputMethods(false);
+ } else {
+ w.setSize(displayMode.getWidth(), displayMode.getHeight());
+ w.setLocation(0, 0);
+ }
+ w.setVisible(true);
+ w.setAlwaysOnTop(true);
+ }
+ */
+}
diff --git a/awt/java/awt/GraphicsEnvironment.java b/awt/java/awt/GraphicsEnvironment.java
new file mode 100644
index 0000000..3b14f55
--- /dev/null
+++ b/awt/java/awt/GraphicsEnvironment.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.BufferedImage;
+import java.util.Locale;
+
+import org.apache.harmony.awt.ContextStorage;
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+
+/**
+ * The GraphicsEnvironment class defines a collection of GraphicsDevice
+ * objects and Font objects which are available for Java application on
+ * current platform.
+ */
+public abstract class GraphicsEnvironment {
+
+ /**
+ * Constructor could not be used directly and should be obtained in
+ * extended classes.
+ */
+ protected GraphicsEnvironment() {}
+
+ /**
+ * Gets the local GraphicsEnvironment.
+ *
+ * @return the local GraphicsEnvironment.
+ */
+ public static GraphicsEnvironment getLocalGraphicsEnvironment() {
+ synchronized(ContextStorage.getContextLock()) {
+ if (ContextStorage.getGraphicsEnvironment() == null) {
+ if (isHeadless()) {
+ ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment());
+ } else {
+ CommonGraphics2DFactory g2df =
+ (CommonGraphics2DFactory) Toolkit.getDefaultToolkit().getGraphicsFactory();
+
+ ContextStorage.setGraphicsEnvironment(
+ g2df.createGraphicsEnvironment(ContextStorage.getWindowFactory())
+ );
+ }
+ }
+
+ return ContextStorage.getGraphicsEnvironment();
+ }
+ }
+
+ /**
+ * Returns whether or not a display, keyboard, and mouse are supported
+ * in this graphics environment.
+ *
+ * @return true, if HeadlessException will be thrown from areas of
+ * the graphics environment that are dependent on a display, keyboard,
+ * or mouse; false otherwise.
+ */
+ public boolean isHeadlessInstance() {
+ return false;
+ }
+
+ /**
+ * Checks whether or not a display, keyboard, and mouse are supported
+ * in this environment.
+ *
+ * @return true, if a HeadlessException is thrown from areas of
+ * the Toolkit and GraphicsEnvironment that are dependent on
+ * a display, keyboard, or mouse; false otherwise.
+ */
+ public static boolean isHeadless() {
+ return "true".equals(System.getProperty("java.awt.headless"));
+ }
+
+ /**
+ * Gets the maximum bounds of system centered windows.
+ *
+ * @return the maximum bounds of system centered windows.
+ *
+ * @throws HeadlessException if isHeadless() method returns true.
+ */
+ public Rectangle getMaximumWindowBounds() throws HeadlessException {
+ return getDefaultScreenDevice().getDefaultConfiguration().getBounds();
+ }
+
+ /**
+ * Gets the Point which should defines the center of system window.
+ *
+ * @return the Point where the system window should be centered.
+ *
+ * @throws HeadlessException if isHeadless() method returns true.
+ */
+ public Point getCenterPoint() throws HeadlessException {
+ Rectangle mwb = getMaximumWindowBounds();
+ return new Point(mwb.width >> 1, mwb.height >> 1);
+ }
+
+ /**
+ * Indicates that the primary font should be used.
+ * Primary font is specified by initial system locale or default encoding).
+ *
+ */
+ public void preferLocaleFonts() {
+ // Note: API specification says following:
+ // "The actual change in font rendering behavior resulting
+ // from a call to this method is implementation dependent;
+ // it may have no effect at all." So, doing nothing is an
+ // acceptable behavior for this method.
+
+ // For now FontManager uses 1.4 font.properties scheme for font mapping, so
+ // this method doesn't make any sense. The implementation of this method
+ // which will influence font mapping is postponed until
+ // 1.5 mapping scheme not implemented.
+
+ // todo - Implement non-default behavior with 1.5 font mapping scheme
+ }
+
+ /**
+ * Indicates that a proportional preference of the font should be used.
+ */
+ public void preferProportionalFonts() {
+ // Note: API specification says following:
+ // "The actual change in font rendering behavior resulting
+ // from a call to this method is implementation dependent;
+ // it may have no effect at all." So, doing nothing is an
+ // acceptable behavior for this method.
+
+ // For now FontManager uses 1.4 font.properties scheme for font mapping, so
+ // this method doesn't make any sense. The implementation of this method
+ // which will influence font mapping is postponed until
+ // 1.5 mapping scheme not implemented.
+
+ // todo - Implement non-default behavior with 1.5 font mapping scheme
+ }
+
+ /**
+ * Creates the Graphics2D object for rendering to the specified
+ * BufferedImage.
+ *
+ * @param bufferedImage the BufferedImage object.
+ *
+ * @return the Graphics2D object which allows to render to the specified
+ * BufferedImage.
+ */
+ public abstract Graphics2D createGraphics(BufferedImage bufferedImage);
+
+ /**
+ * Gets the array of all available fonts instances in this
+ * GraphicsEnviroments.
+ *
+ * @return the array of all available fonts instances in this
+ * GraphicsEnviroments.
+ */
+ public abstract Font[] getAllFonts();
+
+ /**
+ * Gets the array of all available font family names.
+ *
+ * @return the array of all available font family names.
+ */
+ public abstract String[] getAvailableFontFamilyNames();
+
+ /**
+ * Gets the array of all available font family names for the specified
+ * locale.
+ *
+ * @param locale the Locale object which represents geographical
+ * region. The default locale is used if locale is null.
+ *
+ * @return the array of available font family names for the specified
+ * locale.
+ */
+ public abstract String[] getAvailableFontFamilyNames(Locale locale);
+
+ /**
+ * Gets the default screen device as GraphicDevice object.
+ *
+ * @return the GraphicDevice object which represents default screen device.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ public abstract GraphicsDevice getDefaultScreenDevice() throws HeadlessException;
+
+ /**
+ * Gets an array of all available screen devices.
+ *
+ * @return the array of GraphicsDevice obgects which represents
+ * all available screen devices.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ public abstract GraphicsDevice[] getScreenDevices() throws HeadlessException;
+}
diff --git a/awt/java/awt/HeadlessException.java b/awt/java/awt/HeadlessException.java
new file mode 100644
index 0000000..28e463b
--- /dev/null
+++ b/awt/java/awt/HeadlessException.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The HeadlessException class provides notifications and error messages
+ * when code that is dependent on a keyboard, display, or mouse is called
+ * in an environment that does not support a keyboard, display, or mouse.
+ */
+public class HeadlessException extends UnsupportedOperationException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 167183644944358563L;
+
+ /**
+ * Instantiates a new headless exception.
+ */
+ public HeadlessException() {
+ super();
+ }
+
+ /**
+ * Instantiates a new headless exception with the specified message.
+ *
+ * @param msg the String which represents error message.
+ */
+ public HeadlessException(String msg) {
+ super(msg);
+ }
+}
diff --git a/awt/java/awt/HeadlessGraphicsEnvironment.java b/awt/java/awt/HeadlessGraphicsEnvironment.java
new file mode 100644
index 0000000..97f88d1
--- /dev/null
+++ b/awt/java/awt/HeadlessGraphicsEnvironment.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java.awt;
+
+import java.awt.GraphicsDevice;
+import java.awt.HeadlessException;
+
+import org.apache.harmony.awt.gl.CommonGraphicsEnvironment;
+
+/**
+ * The HeadlessGraphicsEnvironment class is the CommonGraphicsEnvironment
+ * implementation to use in the case where the environment lacks display,
+ * keyboard, and mouse support.
+ */
+public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment {
+
+ /**
+ * Returns whether or not a display, keyboard, and mouse are supported
+ * in this graphics environment.
+ *
+ * @return true, if HeadlessException will be thrown from areas of
+ * the graphics environment that are dependent on a display, keyboard,
+ * or mouse; false otherwise.
+ */
+ @Override
+ public boolean isHeadlessInstance() {
+ return true;
+ }
+
+ /**
+ * Gets the default screen device as GraphicDevice object.
+ *
+ * @return the GraphicDevice object which represents default screen device.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ @Override
+ public GraphicsDevice getDefaultScreenDevice() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ /**
+ * Gets an array of all available screen devices.
+ *
+ * @return the array of GraphicsDevice objects which represents
+ * all available screen devices.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ @Override
+ public GraphicsDevice[] getScreenDevices() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+}
diff --git a/awt/java/awt/HeadlessToolkit.java b/awt/java/awt/HeadlessToolkit.java
new file mode 100644
index 0000000..a7dd557
--- /dev/null
+++ b/awt/java/awt/HeadlessToolkit.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+//???AWT
+//import java.awt.datatransfer.Clipboard;
+//import java.awt.dnd.DragGestureEvent;
+//import java.awt.dnd.DragGestureListener;
+//import java.awt.dnd.DragGestureRecognizer;
+//import java.awt.dnd.DragSource;
+//import java.awt.dnd.InvalidDnDOperationException;
+//import java.awt.dnd.peer.DragSourceContextPeer;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+//import java.awt.peer.*;
+//import java.beans.PropertyChangeSupport;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.harmony.awt.ComponentInternals;
+//import org.apache.harmony.awt.datatransfer.DTK;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.WindowFactory;
+
+/**
+ * The HeadlessToolkit class is a subclass of ToolkitImpl to
+ * be used for graphical environments that lack keyboard and
+ * mouse capabilities.
+ */
+public final class HeadlessToolkit extends ToolkitImpl {
+
+ //???AWT
+ /*
+ @Override
+ protected ButtonPeer createButton(Button a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected CheckboxPeer createCheckbox(Checkbox a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ChoicePeer createChoice(Choice a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ public Cursor createCustomCursor(Image img, Point hotSpot, String name)
+ throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected DialogPeer createDialog(Dialog a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
+ Class<T> recognizerAbstractClass, DragSource ds, Component c, int srcActions,
+ DragGestureListener dgl) {
+ return null;
+ }
+
+ @Override
+ public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
+ throws InvalidDnDOperationException {
+ throw new InvalidDnDOperationException();
+ }
+
+ @Override
+ protected FileDialogPeer createFileDialog(FileDialog a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected FramePeer createFrame(Frame a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected LabelPeer createLabel(Label a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ListPeer createList(List a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected MenuPeer createMenu(Menu a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected MenuBarPeer createMenuBar(MenuBar a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected MenuItemPeer createMenuItem(MenuItem a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ScrollbarPeer createScrollbar(Scrollbar a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ScrollPanePeer createScrollPane(ScrollPane a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected TextAreaPeer createTextArea(TextArea a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected TextFieldPeer createTextField(TextField a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected WindowPeer createWindow(Window a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+ */
+
+ @Override
+ public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public ColorModel getColorModel() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public GraphicsFactory getGraphicsFactory() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public int getMaximumCursorColors() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public int getMenuShortcutKeyMask() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ //???AWT
+ /*
+ @Override
+ NativeEventQueue getNativeEventQueue() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public PrintJob getPrintJob(Frame frame, String jobtitle, JobAttributes jobAttributes,
+ PageAttributes pageAttributes) throws IllegalArgumentException {
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public PrintJob getPrintJob(Frame frame, String jobtitle, Properties props) throws NullPointerException {
+ throw new NullPointerException();
+ }
+ */
+
+ @Override
+ public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public int getScreenResolution() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public Dimension getScreenSize() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ //???AWT
+ /*
+ @Override
+ public Clipboard getSystemClipboard() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public Clipboard getSystemSelection() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ WindowFactory getWindowFactory() throws HeadlessException {
+ throw new HeadlessException();
+ }
+ */
+
+ @Override
+ protected void init() {
+ lockAWT();
+ try {
+ ComponentInternals.setComponentInternals(new ComponentInternalsImpl());
+ //???AWT: new EventQueue(this); // create the system EventQueue
+ //???AWT: dispatcher = new Dispatcher(this);
+ desktopProperties = new HashMap<String, Object>();
+ //???AWT: desktopPropsSupport = new PropertyChangeSupport(this);
+// ???AWT: awtEventsManager = new AWTEventsManager();
+// ???AWT: dispatchThread = new HeadlessEventDispatchThread(this, dispatcher);
+// ???AWT: dtk = DTK.getDTK();
+ dispatchThread.start();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public boolean isDynamicLayoutActive() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected boolean isDynamicLayoutSet() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public boolean isFrameStateSupported(int state) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected void loadSystemColors(int[] systemColors) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+ InputMethodHighlight highlight) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(
+ InputMethodHighlight highlight) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public void setDynamicLayout(boolean dynamic) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public void setLockingKeyState(int keyCode, boolean on) throws UnsupportedOperationException {
+ throw new HeadlessException();
+ }
+}
diff --git a/awt/java/awt/IllegalComponentStateException.java b/awt/java/awt/IllegalComponentStateException.java
new file mode 100644
index 0000000..21dc35f
--- /dev/null
+++ b/awt/java/awt/IllegalComponentStateException.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The IllegalComponentStateException class is used to provide
+ * notification that AWT component is not in an appropriate state
+ * for the requested operation.
+ */
+public class IllegalComponentStateException extends IllegalStateException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1889339587208144238L;
+
+ /**
+ * Instantiates a new IllegalComponentStateException with
+ * the specified message.
+ *
+ * @param s the String message which describes the exception.
+ */
+ public IllegalComponentStateException(String s) {
+ super(s);
+ }
+
+ /**
+ * Instantiates a new IllegalComponentStateException without
+ * detailed message.
+ */
+ public IllegalComponentStateException() {
+ }
+
+}
+
diff --git a/awt/java/awt/Image.java b/awt/java/awt/Image.java
new file mode 100644
index 0000000..c217e38
--- /dev/null
+++ b/awt/java/awt/Image.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.AreaAveragingScaleFilter;
+import java.awt.image.FilteredImageSource;
+import java.awt.image.ImageFilter;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.ReplicateScaleFilter;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Image abstract class represents the graphic images.
+ */
+public abstract class Image {
+
+ /**
+ * The UndefinedProperty object should be returned if
+ * property is not defined for a particular image.
+ */
+ public static final Object UndefinedProperty = new Object(); //$NON-LOCK-1$
+
+ /**
+ * The Constant SCALE_DEFAULT indicates the default image
+ * scaling algorithm.
+ */
+ public static final int SCALE_DEFAULT = 1;
+
+ /**
+ * The Constant SCALE_FAST indicates an image scaling algorithm which
+ * places a higher priority on scaling speed than on the image's smoothness.
+ */
+ public static final int SCALE_FAST = 2;
+
+ /**
+ * The Constant SCALE_SMOOTH indicates an image scaling algorithm which
+ * places a higher priority on image smoothness than on scaling speed.
+ */
+ public static final int SCALE_SMOOTH = 4;
+
+ /**
+ * The Constant SCALE_REPLICATE indicates the image scaling
+ * algorithm in the ReplicateScaleFilter class.
+ */
+ public static final int SCALE_REPLICATE = 8;
+
+ /**
+ * The Constant SCALE_AREA_AVERAGING indicates
+ * the area averaging image scaling algorithm.
+ */
+ public static final int SCALE_AREA_AVERAGING = 16;
+
+ /**
+ * The acceleration priority indicates image acceleration.
+ */
+ protected float accelerationPriority = 0.5f;
+
+ /** The Constant capabilities. */
+ private static final ImageCapabilities capabilities = new ImageCapabilities(false);
+
+ /**
+ * Gets the image property with the specified name.
+ * The UndefinedProperty object should be return if the property is
+ * not specified for this image. The return value should be null if the
+ * property is currently unknown yet and the specified ImageObserver is
+ * to be notified later.
+ *
+ * @param name the name of image's property.
+ * @param observer the ImageObserver.
+ *
+ * @return the Object which represents value of the specified property.
+ */
+ public abstract Object getProperty(String name, ImageObserver observer);
+
+ /**
+ * Gets the ImageProducer object which represents data of this Image.
+ *
+ * @return the ImageProducer object which represents data of this Image.
+ */
+ public abstract ImageProducer getSource();
+
+ /**
+ * Gets the width of this image. The specified ImageObserver object
+ * is notified when the width of this image is available.
+ *
+ * @param observer the ImageObserver object which is
+ * is notified when the width of this image is available.
+ *
+ * @return the width of image, or -1 if the width of this image
+ * is not available.
+ */
+ public abstract int getWidth(ImageObserver observer);
+
+ /**
+ * Gets the height of this image. The specified ImageObserver object
+ * is notified when the height of this image is available.
+ *
+ * @param observer the ImageObserver object which is
+ * is notified when the height of this image is available.
+ *
+ * @return the height of image, or -1 if the height of this image
+ * is not available.
+ */
+ public abstract int getHeight(ImageObserver observer);
+
+ /**
+ * Gets the scaled instance of this Image. This method returns
+ * an Image object constructed from the source of this image
+ * with the specified width, height, and applied scaling
+ * alghorithm.
+ *
+ * @param width the width of scaled Image.
+ * @param height the height of scaled Image.
+ * @param hints the constant which indicates scaling algorithm.
+ *
+ * @return the scaled Image.
+ */
+ public Image getScaledInstance(int width, int height, int hints) {
+ ImageFilter filter;
+ if ((hints & (SCALE_SMOOTH | SCALE_AREA_AVERAGING)) != 0) {
+ filter = new AreaAveragingScaleFilter(width, height);
+ } else {
+ filter = new ReplicateScaleFilter(width, height);
+ }
+ ImageProducer producer = new FilteredImageSource(getSource(), filter);
+ return Toolkit.getDefaultToolkit().createImage(producer);
+ }
+
+ /**
+ * Gets a Graphics object for rendering this image.
+ * This method can be used for off-screen images.
+ *
+ * @return a Graphics object for rendering to this image.
+ */
+ public abstract Graphics getGraphics();
+
+ /**
+ * Flushes resources which are used by this Image object.
+ * This method resets the image to the reconstructered state
+ * from the image's source.
+ */
+ public abstract void flush();
+
+ /**
+ * Gets the acceleration priority of this image.
+ *
+ * @return the acceleration priority of this image.
+ */
+ public float getAccelerationPriority() {
+ return accelerationPriority;
+ }
+
+ /**
+ * Sets the acceleration priority for this image.
+ *
+ * @param priority the new acceleration priority (value in the
+ * range 0-1).
+ */
+ public void setAccelerationPriority(float priority) {
+ if (priority < 0 || priority > 1) {
+ // awt.10A=Priority must be a value between 0 and 1, inclusive
+ throw new IllegalArgumentException(Messages.getString("awt.10A")); //$NON-NLS-1$
+ }
+ accelerationPriority = priority;
+ }
+
+ /**
+ * Gets an ImageCapabilities object of this Image object
+ * for the specified GraphicsConfiguration.
+ *
+ * @param gc the specified GraphicsConfiguration object
+ * (null value means default GraphicsConfiguration).
+ *
+ * @return an ImageCapabilities object of this Image object
+ * for the specified GraphicsConfiguration.
+ */
+ public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
+ // Note: common image is not accelerated.
+ return capabilities;
+ }
+}
+
+
diff --git a/awt/java/awt/ImageCapabilities.java b/awt/java/awt/ImageCapabilities.java
new file mode 100644
index 0000000..6e9ecfc
--- /dev/null
+++ b/awt/java/awt/ImageCapabilities.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The ImageCapabilities class gives information about an image's capabilities.
+ */
+public class ImageCapabilities implements Cloneable {
+
+ /** The accelerated. */
+ private final boolean accelerated;
+
+ /**
+ * Instantiates a new ImageCapabilities with the specified
+ * acceleration flag which indicates whether acceleration
+ * is desired or not.
+ *
+ * @param accelerated the accelerated flag.
+ */
+ public ImageCapabilities(boolean accelerated) {
+ this.accelerated = accelerated;
+ }
+
+ /**
+ * Returns a copy of this ImageCapabilities object.
+ *
+ * @return the copy of this ImageCapabilities object.
+ */
+ @Override
+ public Object clone() {
+ return new ImageCapabilities(accelerated);
+ }
+
+ /**
+ * Returne true if the Image of this ImageCapabilities is or can be
+ * accelerated.
+ *
+ * @return true, if the Image of this ImageCapabilities is or can be
+ * accelerated, false otherwise.
+ */
+ public boolean isAccelerated() {
+ return accelerated;
+ }
+
+ /**
+ * Returns true if this ImageCapabilities applies to
+ * the VolatileImage which can lose its surfaces.
+ *
+ * @return true if this ImageCapabilities applies to
+ * the VolatileImage which can lose its surfaces,
+ * false otherwise.
+ */
+ public boolean isTrueVolatile() {
+ return true;
+ }
+}
diff --git a/awt/java/awt/Insets.java b/awt/java/awt/Insets.java
new file mode 100644
index 0000000..61f3fd8
--- /dev/null
+++ b/awt/java/awt/Insets.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.Serializable;
+
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The Insets class represents the borders of a container.
+ * This class describes the space that a container should leave at each edge:
+ * the top, the bottom, the right side, and the left side.
+ * The space can be filled with a border, a blank space, or a title.
+ */
+public class Insets implements Cloneable, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -2272572637695466749L;
+
+ /**
+ * The top inset indicates the size of the space added to the
+ * top of the rectangle.
+ */
+ public int top;
+
+ /**
+ * The left inset indicates the size of the space added to the
+ * left side of the rectangle.
+ */
+ public int left;
+
+ /**
+ * The bottom inset indicates the size of the space subtracted from
+ * the bottom of the rectangle.
+ */
+ public int bottom;
+
+ /** The right inset indicates the size of the space subtracted from
+ * the right side of the rectangle.
+ */
+ public int right;
+
+ /**
+ * Instantiates a new Inset object with the specified top, left, bottom,
+ * right parameters.
+ *
+ * @param top the top inset.
+ * @param left the left inset.
+ * @param bottom the bottom inset.
+ * @param right the right inset.
+ */
+ public Insets(int top, int left, int bottom, int right) {
+ setValues(top, left, bottom, right);
+ }
+
+ /**
+ * Returns a hash code of the Insets object.
+ *
+ * @return a hash code of the Insets object.
+ */
+ @Override
+ public int hashCode() {
+ int hashCode = HashCode.EMPTY_HASH_CODE;
+ hashCode = HashCode.combine(hashCode, top);
+ hashCode = HashCode.combine(hashCode, left);
+ hashCode = HashCode.combine(hashCode, bottom);
+ hashCode = HashCode.combine(hashCode, right);
+ return hashCode;
+ }
+
+ /**
+ * Returns a copy of this Insets object.
+ *
+ * @return a copy of this Insets object.
+ */
+ @Override
+ public Object clone() {
+ return new Insets(top, left, bottom, right);
+ }
+
+ /**
+ * Checks if this Insets object is equal to the specified object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if the object is an Insets object whose data values
+ * are equal to those of this object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof Insets) {
+ Insets i = (Insets) o;
+ return ((i.left == left) && (i.bottom == bottom) &&
+ (i.right == right) && (i.top == top));
+ }
+ return false;
+ }
+
+ /**
+ * Returns a String representation of this Insets object.
+ *
+ * @return a String representation of this Insets object.
+ */
+ @Override
+ public String toString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ * System.out.println(new Insets(1, 2, 3, 4));
+ */
+
+ return (getClass().getName() +
+ "[left=" + left + ",top=" + top + //$NON-NLS-1$ //$NON-NLS-2$
+ ",right=" + right + ",bottom=" + bottom + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Sets top, left, bottom, and right insets to the specified values.
+ *
+ * @param top the top inset.
+ * @param left the left inset.
+ * @param bottom the bottom inset.
+ * @param right the right inset.
+ */
+ public void set(int top, int left, int bottom, int right) {
+ setValues(top, left, bottom, right);
+ }
+
+ /**
+ * Sets the values.
+ *
+ * @param top the top
+ * @param left the left
+ * @param bottom the bottom
+ * @param right the right
+ */
+ private void setValues(int top, int left, int bottom, int right) {
+ this.top = top;
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ }
+}
+
diff --git a/awt/java/awt/ItemSelectable.java b/awt/java/awt/ItemSelectable.java
new file mode 100644
index 0000000..a46364b
--- /dev/null
+++ b/awt/java/awt/ItemSelectable.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ItemListener;
+
+/**
+ * The ItemSelectable interface represents a set of items which can be selected.
+ */
+public interface ItemSelectable {
+
+ /**
+ * Adds an ItemListener for receiving item events when the state of an item
+ * is changed by the user.
+ *
+ * @param l the ItemListener.
+ */
+ public void addItemListener(ItemListener l);
+
+ /**
+ * Gets an array of the selected objects or null if there is no selected object.
+ *
+ * @return an array of the selected objects or null if there is no selected
+ * object.
+ */
+ public Object[] getSelectedObjects();
+
+ /**
+ * Removes the specified ItemListener.
+ *
+ * @param l the ItemListener which will be removed.
+ */
+ public void removeItemListener(ItemListener l);
+
+}
diff --git a/awt/java/awt/MenuComponent.java b/awt/java/awt/MenuComponent.java
new file mode 100644
index 0000000..9eb4f3d
--- /dev/null
+++ b/awt/java/awt/MenuComponent.java
@@ -0,0 +1,1041 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.peer.MenuComponentPeer;
+import java.io.Serializable;
+import java.util.Locale;
+//import javax.accessibility.Accessible;
+//import javax.accessibility.AccessibleComponent;
+//import javax.accessibility.AccessibleContext;
+//import javax.accessibility.AccessibleRole;
+//import javax.accessibility.AccessibleSelection;
+//import javax.accessibility.AccessibleStateSet;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.state.MenuItemState;
+import org.apache.harmony.awt.state.MenuState;
+
+/**
+ * The MenuComponent abstract class is the superclass for menu
+ * components. Menu components receive and process AWT events.
+ */
+public abstract class MenuComponent implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4536902356223894379L;
+
+ /** The name. */
+ private String name;
+
+ /** The font. */
+ private Font font;
+
+ /** The parent. */
+ MenuContainer parent;
+
+ /** The deprecated event handler. */
+ boolean deprecatedEventHandler = true;
+
+ /** The selected item index. */
+ private int selectedItemIndex;
+
+ //???AWT: private AccessibleContext accessibleContext;
+
+ /** The toolkit. */
+ final Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+ //???AWT
+ /*
+ protected abstract class AccessibleAWTMenuComponent extends AccessibleContext implements
+ Serializable, AccessibleComponent, AccessibleSelection {
+ private static final long serialVersionUID = -4269533416223798698L;
+
+ public void addFocusListener(FocusListener listener) {
+ }
+
+ public boolean contains(Point pt) {
+ return false;
+ }
+
+ public Accessible getAccessibleAt(Point pt) {
+ return null;
+ }
+
+ public Color getBackground() {
+ return null;
+ }
+
+ public Rectangle getBounds() {
+ return null;
+ }
+
+ public Cursor getCursor() {
+ return null;
+ }
+
+ public Font getFont() {
+ return MenuComponent.this.getFont();
+ }
+
+ public FontMetrics getFontMetrics(Font font) {
+ return null;
+ }
+
+ public Color getForeground() {
+ return null;
+ }
+
+ public Point getLocation() {
+ return null;
+ }
+
+ public Point getLocationOnScreen() {
+ return null;
+ }
+
+ public Dimension getSize() {
+ return null;
+ }
+
+ public boolean isEnabled() {
+ return true; // always enabled
+ }
+
+ public boolean isFocusTraversable() {
+ return true; // always focus traversable
+ }
+
+ public boolean isShowing() {
+ return true;// always showing
+ }
+
+ public boolean isVisible() {
+ return true; // always visible
+ }
+
+ public void removeFocusListener(FocusListener listener) {
+ }
+
+ public void requestFocus() {
+ }
+
+ public void setBackground(Color color) {
+ }
+
+ public void setBounds(Rectangle rect) {
+ }
+
+ public void setCursor(Cursor cursor) {
+ }
+
+ public void setEnabled(boolean enabled) {
+ }
+
+ public void setFont(Font font) {
+ MenuComponent.this.setFont(font);
+ }
+
+ public void setForeground(Color color) {
+ }
+
+ public void setLocation(Point pt) {
+ }
+
+ public void setSize(Dimension pt) {
+ }
+
+ public void setVisible(boolean visible) {
+ }
+
+ public void addAccessibleSelection(int index) {
+ }
+
+ public void clearAccessibleSelection() {
+ }
+
+ public Accessible getAccessibleSelection(int index) {
+ return null;
+ }
+
+ public int getAccessibleSelectionCount() {
+ return 0;
+ }
+
+ public boolean isAccessibleChildSelected(int index) {
+ return false;
+ }
+
+ public void removeAccessibleSelection(int index) {
+ }
+
+ public void selectAllAccessibleSelection() {
+ }
+
+ @Override
+ public Accessible getAccessibleChild(int index) {
+ return null;
+ }
+
+ @Override
+ public int getAccessibleChildrenCount() {
+ return 0;
+ }
+
+ @Override
+ public AccessibleComponent getAccessibleComponent() {
+ return this;
+ }
+
+ @Override
+ public String getAccessibleDescription() {
+ return super.getAccessibleDescription();
+ }
+
+ @Override
+ public int getAccessibleIndexInParent() {
+ toolkit.lockAWT();
+ try {
+ Accessible aParent = getAccessibleParent();
+ int aIndex = -1;
+ if (aParent instanceof MenuComponent) {
+ MenuComponent parent = (MenuComponent) aParent;
+ int count = parent.getItemCount();
+ for (int i = 0; i < count; i++) {
+ MenuComponent comp = parent.getItem(i);
+ if (comp instanceof Accessible) {
+ aIndex++;
+ if (comp == MenuComponent.this) {
+ return aIndex;
+ }
+ }
+ }
+ }
+ return -1;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public String getAccessibleName() {
+ return super.getAccessibleName();
+ }
+
+ @Override
+ public Accessible getAccessibleParent() {
+ toolkit.lockAWT();
+ try {
+ Accessible aParent = super.getAccessibleParent();
+ if (aParent != null) {
+ return aParent;
+ }
+ MenuContainer parent = getParent();
+ if (parent instanceof Accessible) {
+ aParent = (Accessible) parent;
+ }
+ return aParent;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleRole getAccessibleRole() {
+ return AccessibleRole.AWT_COMPONENT;
+ }
+
+ @Override
+ public AccessibleSelection getAccessibleSelection() {
+ return this;
+ }
+
+ @Override
+ public AccessibleStateSet getAccessibleStateSet() {
+ return new AccessibleStateSet();
+ }
+
+ @Override
+ public Locale getLocale() {
+ return Locale.getDefault();
+ }
+ }
+ */
+
+ /**
+ * The accessor to MenuComponent internal state,
+ * utilized by the visual theme.
+ *
+ * @throws HeadlessException the headless exception
+ */
+ //???AWT
+ /*
+ class State implements MenuState {
+ Dimension size;
+
+ Dimension getSize() {
+ if (size == null) {
+ calculate();
+ }
+ return size;
+ }
+
+ public int getWidth() {
+ return getSize().width;
+ }
+
+ public int getHeight() {
+ return getSize().height;
+ }
+
+ public Font getFont() {
+ return MenuComponent.this.getFont();
+ }
+
+ public int getItemCount() {
+ return MenuComponent.this.getItemCount();
+ }
+
+ public int getSelectedItemIndex() {
+ return MenuComponent.this.getSelectedItemIndex();
+ }
+
+ public boolean isFontSet() {
+ return MenuComponent.this.isFontSet();
+ }
+
+ @SuppressWarnings("deprecation")
+ public FontMetrics getFontMetrics(Font f) {
+ return MenuComponent.this.toolkit.getFontMetrics(f);
+ }
+
+ public Point getLocation() {
+ return MenuComponent.this.getLocation();
+ }
+
+ public MenuItemState getItem(int index) {
+ MenuItem item = MenuComponent.this.getItem(index);
+ return item.itemState;
+ }
+
+ public void setSize(int w, int h) {
+ this.size = new Dimension(w, h);
+ }
+
+ void calculate() {
+ size = new Dimension();
+ size.setSize(toolkit.theme.calculateMenuSize(this));
+ }
+
+ void reset() {
+ for (int i = 0; i < getItemCount(); i++) {
+ ((MenuItem.State) getItem(i)).reset();
+ }
+ }
+
+ }
+ */
+
+ /**
+ * Pop-up box for menu. It transfers the paint events,
+ * keyboard and mouse events to the menu component itself
+ */
+ //???AWT
+ /*
+ class MenuPopupBox extends PopupBox {
+ private final Point lastMousePos = new Point();
+
+ @Override
+ boolean isMenu() {
+ return true;
+ }
+
+ @Override
+ void paint(Graphics gr) {
+ MenuComponent.this.paint(gr);
+ }
+
+ @Override
+ void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
+ MenuComponent.this.onKeyEvent(eventId, vKey, when, modifiers);
+ }
+
+ @Override
+ void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers,
+ int wheelRotation) {
+ // prevent conflict of mouse and keyboard
+ // when sub-menu drops down due to keyboard navigation
+ if (lastMousePos.equals(where)
+ && (eventId == MouseEvent.MOUSE_MOVED || eventId == MouseEvent.MOUSE_ENTERED)) {
+ return;
+ }
+ lastMousePos.setLocation(where);
+ MenuComponent.this.onMouseEvent(eventId, where, mouseButton, when, modifiers);
+ }
+ }
+ */
+
+ /**
+ * Instantiates a new MenuComponent object.
+ *
+ * @throws HeadlessException if the graphical interface
+ * environment can't support MenuComponents
+ */
+ public MenuComponent() throws HeadlessException {
+ toolkit.lockAWT();
+ try {
+ Toolkit.checkHeadless();
+ name = autoName();
+ selectedItemIndex = -1;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the name of the MenuComponent object.
+ *
+ * @return the name of the MenuComponent object.
+ */
+ public String getName() {
+ toolkit.lockAWT();
+ try {
+ return name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns a String representation of the MenuComponent object.
+ *
+ * @return a String representation of the MenuComponent object.
+ */
+ @Override
+ public String toString() {
+ toolkit.lockAWT();
+ try {
+ return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Parent menu Container .
+ *
+ * @return the parent
+ */
+ public MenuContainer getParent() {
+ toolkit.lockAWT();
+ try {
+ return parent;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the name of the MenuComponent to the specified string.
+ *
+ * @param name the new name of the MenuComponent object.
+ */
+ public void setName(String name) {
+ toolkit.lockAWT();
+ try {
+ this.name = name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Dispatches AWT event.
+ *
+ * @param event the AWTEvent.
+ */
+ public final void dispatchEvent(AWTEvent event) {
+ toolkit.lockAWT();
+ try {
+ processEvent(event);
+ if (deprecatedEventHandler) {
+ postDeprecatedEvent(event);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Post deprecated event.
+ *
+ * @param event the event
+ */
+ void postDeprecatedEvent(AWTEvent event) {
+ Event evt = event.getEvent();
+ if (evt != null) {
+ postEvent(evt);
+ }
+ }
+
+ /**
+ * Gets the peer of the MenuComponent; an application must not
+ * use this method directly.
+ *
+ * @return the MenuComponentPeer object.
+ *
+ * @deprecated an application must not use this method directly.
+ */
+ @Deprecated
+ public MenuComponentPeer getPeer() throws org.apache.harmony.luni.util.NotImplementedException {
+ toolkit.lockAWT();
+ try {
+ } finally {
+ toolkit.unlockAWT();
+ }
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Gets the locking object of this MenuComponent.
+ *
+ * @return the locking object of this MenuComponent.
+ */
+ protected final Object getTreeLock() {
+ return toolkit.awtTreeLock;
+ }
+
+ /**
+ * Posts the Event to the MenuComponent.
+ *
+ * @param e the Event.
+ *
+ * @return true, if the event is posted successfully;
+ * false otherwise.
+ *
+ * @deprecated Replaced dispatchEvent method.
+ */
+ @SuppressWarnings("deprecation")
+ @Deprecated
+ public boolean postEvent(Event e) {
+ toolkit.lockAWT();
+ try {
+ if (parent != null) {
+ return parent.postEvent(e);
+ }
+ return false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the string representation of the MenuComponent state.
+ *
+ * @return returns the string representation of the MenuComponent
+ * state.
+ */
+ protected String paramString() {
+ toolkit.lockAWT();
+ try {
+ return getName();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public AccessibleContext getAccessibleContext() {
+ toolkit.lockAWT();
+ try {
+ if (accessibleContext == null) {
+ accessibleContext = createAccessibleContext();
+ }
+ return accessibleContext;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Gets the font of the MenuComponent object.
+ *
+ * @return the Font of the MenuComponent object.
+ */
+ public Font getFont() {
+ toolkit.lockAWT();
+ try {
+ if (font == null && hasDefaultFont()) {
+ return toolkit.getDefaultFont();
+ }
+ if (font == null && parent != null) {
+ return parent.getFont();
+ }
+ return font;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if is font set.
+ *
+ * @return true, if is font set
+ */
+ boolean isFontSet() {
+ return font != null
+ || ((parent instanceof MenuComponent) && ((MenuComponent) parent).isFontSet());
+ }
+
+ /**
+ * Checks for default font.
+ *
+ * @return true, if successful
+ */
+ boolean hasDefaultFont() {
+ return false;
+ }
+
+ /**
+ * Processes an AWTEevent on this menu component.
+ *
+ * @param event the AWTEvent.
+ */
+ protected void processEvent(AWTEvent event) {
+ toolkit.lockAWT();
+ try {
+ // do nothing
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Removes the peer of the MenuComponent.
+ */
+ public void removeNotify() {
+ toolkit.lockAWT();
+ try {
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the Font for this MenuComponent object.
+ *
+ * @param font the new Font to be used for this MenuComponent.
+ */
+ public void setFont(Font font) {
+ toolkit.lockAWT();
+ try {
+ this.font = font;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the parent.
+ *
+ * @param parent the new parent
+ */
+ void setParent(MenuContainer parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the location.
+ *
+ * @return the location
+ */
+ Point getLocation() {
+ // to be overridden
+ return new Point(0, 0);
+ }
+
+ /**
+ * Gets the width.
+ *
+ * @return the width
+ */
+ int getWidth() {
+ // to be overridden
+ return 1;
+ }
+
+ /**
+ * Gets the height.
+ *
+ * @return the height
+ */
+ int getHeight() {
+ // to be overridden
+ return 1;
+ }
+
+ /**
+ * Recursively find the menu item for a menu shortcut.
+ *
+ * @param gr the gr
+ *
+ * @return the menu item;
+ * or null if the item is not available for this shortcut
+ */
+ //???AWT
+ /*
+ MenuItem getShortcutMenuItemImpl(MenuShortcut ms) {
+ if (ms == null) {
+ return null;
+ }
+ for (int i = 0; i < getItemCount(); i++) {
+ MenuItem mi = getItem(i);
+ if (mi instanceof Menu) {
+ mi = ((Menu) mi).getShortcutMenuItemImpl(ms);
+ if (mi != null) {
+ return mi;
+ }
+ } else if (ms.equals(mi.getShortcut())) {
+ return mi;
+ }
+ }
+ return null;
+ }
+ */
+
+ void paint(Graphics gr) {
+ gr.setColor(Color.LIGHT_GRAY);
+ gr.fillRect(0, 0, getWidth(), getHeight());
+ gr.setColor(Color.BLACK);
+ }
+
+ /**
+ * Mouse events handler.
+ *
+ * @param eventId - one of the MouseEvent.MOUSE_* constants
+ * @param where - mouse location
+ * @param mouseButton - mouse button that was pressed or released
+ * @param when - event time
+ * @param modifiers - input event modifiers
+ */
+ void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) {
+ // to be overridden
+ }
+
+ /**
+ * Keyboard event handler.
+ *
+ * @param eventId - one of the KeyEvent.KEY_* constants
+ * @param vKey - the key code
+ * @param when - event time
+ * @param modifiers - input event modifiers
+ */
+ void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
+ // to be overridden
+ }
+
+ /**
+ * Post the ActionEvent or ItemEvent,
+ * depending on type of the menu item.
+ *
+ * @param index the index
+ *
+ * @return the item rect
+ */
+ //???AWT
+ /*
+ void fireItemAction(int item, long when, int modifiers) {
+ MenuItem mi = getItem(item);
+ mi.itemSelected(when, modifiers);
+ }
+
+ MenuItem getItem(int index) {
+ // to be overridden
+ return null;
+ }
+
+ int getItemCount() {
+ return 0;
+ }
+ */
+
+ /**
+ * @return The sub-menu of currently selecetd item,
+ * or null if such a sub-menu is not available
+ */
+ //???AWT
+ /*
+ Menu getSelectedSubmenu() {
+ if (selectedItemIndex < 0) {
+ return null;
+ }
+ MenuItem item = getItem(selectedItemIndex);
+ return (item instanceof Menu) ? (Menu) item : null;
+ }
+ */
+
+ /**
+ * Convenience method for selectItem(index, true)
+ */
+ //???AWT
+ /*
+ void selectItem(int index) {
+ selectItem(index, true);
+ }
+ */
+
+ /**
+ * Change the selection in the menu
+ * @param index - new selecetd item's index
+ * @param showSubMenu - if new selected item has a sub-menu,
+ * should that sub-menu be displayed
+ */
+ //???AWT
+ /*
+ void selectItem(int index, boolean showSubMenu) {
+ if (selectedItemIndex == index) {
+ return;
+ }
+ if (selectedItemIndex >= 0 && getItem(selectedItemIndex) instanceof Menu) {
+ ((Menu) getItem(selectedItemIndex)).hide();
+ }
+ MultiRectArea clip = getUpdateClip(index, selectedItemIndex);
+ selectedItemIndex = index;
+ Graphics gr = getGraphics(clip);
+ if (gr != null) {
+ paint(gr);
+ }
+ if (showSubMenu) {
+ showSubMenu(selectedItemIndex);
+ }
+ }
+ */
+
+ /**
+ * Change the selected item to the next one in the requested direction
+ * moving cyclically, skipping separators
+ * @param forward - the direction to move the selection
+ * @param showSubMenu - if new selected item has a sub-menu,
+ * should that sub-menu be displayed
+ */
+ //???AWT
+ /*
+ void selectNextItem(boolean forward, boolean showSubMenu) {
+ int selected = getSelectedItemIndex();
+ int count = getItemCount();
+ if (count == 0) {
+ return;
+ }
+ if (selected < 0) {
+ selected = (forward ? count - 1 : 0);
+ }
+ int i = selected;
+ do {
+ i = (forward ? (i + 1) : (i + count - 1)) % count;
+ i %= count;
+ MenuItem item = getItem(i);
+ if (!"-".equals(item.getLabel())) { //$NON-NLS-1$
+ selectItem(i, showSubMenu);
+ return;
+ }
+ } while (i != selected);
+ }
+
+
+ void showSubMenu(int index) {
+ if ((index < 0) || !isActive()) {
+ return;
+ }
+ MenuItem item = getItem(index);
+ if (item instanceof Menu) {
+ Menu menu = ((Menu) getItem(index));
+ if (menu.getItemCount() == 0) {
+ return;
+ }
+ Point location = getSubmenuLocation(index);
+ menu.show(location.x, location.y, false);
+ }
+ }
+ */
+
+ /**
+ * @return - the menu bar which is the root of crrent menu's hierarchy;
+ * or null if the hierarchy root is not a menu bar
+ */
+ //???AWT
+ /*
+ MenuBar getMenuBar() {
+ if (parent instanceof MenuBar) {
+ return (MenuBar) parent;
+ }
+ if (parent instanceof MenuComponent) {
+ return ((MenuComponent) parent).getMenuBar();
+ }
+ return null;
+ }
+
+ PopupBox getPopupBox() {
+ return null;
+ }
+ */
+
+ Rectangle getItemRect(int index) {
+ // to be overridden
+ return null;
+ }
+
+ /**
+ * Determine the clip region when menu selection is changed
+ * from index1 to index2.
+ *
+ * @param index1 - old selected intem
+ * @param index2 - new selected item
+ *
+ * @return - the region to repaint
+ */
+ final MultiRectArea getUpdateClip(int index1, int index2) {
+ MultiRectArea clip = new MultiRectArea();
+ if (index1 >= 0) {
+ clip.add(getItemRect(index1));
+ }
+ if (index2 >= 0) {
+ clip.add(getItemRect(index2));
+ }
+ return clip;
+ }
+
+ /**
+ * Gets the submenu location.
+ *
+ * @param index the index
+ *
+ * @return the submenu location
+ */
+ Point getSubmenuLocation(int index) {
+ // to be overridden
+ return new Point(0, 0);
+ }
+
+ /**
+ * Gets the selected item index.
+ *
+ * @return the selected item index
+ */
+ int getSelectedItemIndex() {
+ return selectedItemIndex;
+ }
+
+ /**
+ * Hide.
+ */
+ void hide() {
+ selectedItemIndex = -1;
+ if (parent instanceof MenuComponent) {
+ ((MenuComponent) parent).itemHidden(this);
+ }
+ }
+
+ /**
+ * Item hidden.
+ *
+ * @param mc the mc
+ */
+ void itemHidden(MenuComponent mc) {
+ // to be overridden
+ }
+
+ /**
+ * Checks if is visible.
+ *
+ * @return true, if is visible
+ */
+ boolean isVisible() {
+ return true;
+ }
+
+ /**
+ * Checks if is active.
+ *
+ * @return true, if is active
+ */
+ boolean isActive() {
+ return true;
+ }
+
+ /**
+ * Hide all menu hierarchy.
+ */
+ void endMenu() {
+ //???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll();
+ }
+
+ /**
+ * Handle the mouse click or Enter key event on a menu's item.
+ *
+ * @param when - the event time
+ * @param modifiers - input event modifiers
+ */
+ void itemSelected(long when, int modifiers) {
+ endMenu();
+ }
+
+ /**
+ * Auto name.
+ *
+ * @return the string
+ */
+ String autoName() {
+ String name = getClass().getName();
+ if (name.indexOf("$") != -1) { //$NON-NLS-1$
+ return null;
+ }
+ //???AWT: int number = toolkit.autoNumber.nextMenuComponent++;
+ int number = 0;
+ name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$
+ return name;
+ }
+
+ /**
+ * Creates the Graphics object for the pop-up box of this menu component.
+ *
+ * @param clip - the clip to set on this Graphics
+ *
+ * @return - the created Graphics object,
+ * or null if such object is not available.
+ */
+ Graphics getGraphics(MultiRectArea clip) {
+ // to be overridden
+ return null;
+ }
+
+ /**
+ * @return accessible context specific for particular menu component
+ */
+ //???AWT
+ /*
+ AccessibleContext createAccessibleContext() {
+ return null;
+ }
+ */
+}
diff --git a/awt/java/awt/MenuContainer.java b/awt/java/awt/MenuContainer.java
new file mode 100644
index 0000000..7a48f13
--- /dev/null
+++ b/awt/java/awt/MenuContainer.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The MenuContainer interface represents all menu containers.
+ */
+public interface MenuContainer {
+
+ /**
+ * Removes the specified MenuComponent from the MenuContainer.
+ *
+ * @param c the MenuComponent.
+ */
+ public void remove(MenuComponent c);
+
+ /**
+ * Gets the Font of the MenuContainer.
+ *
+ * @return the font of the MenuContainer.
+ */
+ public Font getFont();
+
+ /**
+ * Posts an Event.
+ *
+ * @param e the Event.
+ *
+ * @return true if the event is posted successfully;
+ * false otherwise.
+ *
+ * @deprecated Replaced by dispatchEvent method.
+ */
+ @Deprecated
+ public boolean postEvent(Event e);
+
+}
+
diff --git a/awt/java/awt/ModalContext.java b/awt/java/awt/ModalContext.java
new file mode 100644
index 0000000..32a5912
--- /dev/null
+++ b/awt/java/awt/ModalContext.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ *
+ * The context for nested event loop. It can be dialog, popup menu etc.
+ */
+class ModalContext {
+
+ private boolean running = false;
+
+ private final Toolkit toolkit;
+
+ ModalContext() {
+ toolkit = Toolkit.getDefaultToolkit();
+ }
+
+ /**
+ * Set up and run modal loop in this context
+ *
+ */
+ void runModalLoop() {
+ running = true;
+ toolkit.dispatchThread.runModalLoop(this);
+ }
+
+ /**
+ * Leave the modal loop running in this context
+ * This method doesn't stops the loop immediately,
+ * it just sets the flag that says the modal loop to stop
+ *
+ */
+ void endModalLoop() {
+ running = false;
+ }
+
+ /**
+ *
+ * @return modal loop is currently running in this context
+ */
+ boolean isModalLoopRunning() {
+ return running;
+ }
+
+}
diff --git a/awt/java/awt/MouseDispatcher.java b/awt/java/awt/MouseDispatcher.java
new file mode 100644
index 0000000..df48f9d
--- /dev/null
+++ b/awt/java/awt/MouseDispatcher.java
@@ -0,0 +1,418 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.Dispatcher.MouseGrabManager;
+import java.util.EventListener;
+
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+
+class MouseDispatcher {
+
+ // Fields for synthetic mouse click events generation
+ private static final int clickDelta = 5;
+ private final long[] lastPressTime = new long[] {0l, 0l, 0l};
+ private final Point[] lastPressPos = new Point[] {null, null, null};
+ private final boolean[] buttonPressed = new boolean[] {false, false, false};
+ private final int[] clickCount = new int[] {0, 0, 0};
+
+ // Fields for mouse entered/exited support
+ private Component lastUnderPointer = null;
+ private final Point lastScreenPos = new Point(-1, -1);
+
+ // Fields for redundant mouse moved/dragged filtering
+ private Component lastUnderMotion = null;
+ private Point lastLocalPos = new Point(-1, -1);
+
+ private final MouseGrabManager mouseGrabManager;
+ private final Toolkit toolkit;
+
+ static Point convertPoint(Component src, int x, int y, Component dest) {
+ Point srcPoint = getAbsLocation(src);
+ Point destPoint = getAbsLocation(dest);
+
+ return new Point(x + (srcPoint.x - destPoint.x),
+ y + (srcPoint.y - destPoint.y));
+ }
+
+ static Point convertPoint(Component src, Point p, Component dst) {
+ return convertPoint(src, p.x, p.y, dst);
+ }
+
+ private static Point getAbsLocation(Component comp) {
+ Point location = new Point(0, 0);
+// BEGIN android-changed: AWT components not supported
+// for (Component parent = comp; parent != null; parent = parent.parent) {
+// Point parentPos = (parent instanceof EmbeddedWindow ?
+// parent.getNativeWindow().getScreenPos() :
+// parent.getLocation());
+//
+// location.translate(parentPos.x, parentPos.y);
+//
+// if (parent instanceof Window) {
+// break;
+// }
+// }
+// END android-changed
+
+ return location;
+ }
+
+ MouseDispatcher(MouseGrabManager mouseGrabManager,
+ Toolkit toolkit) {
+ this.mouseGrabManager = mouseGrabManager;
+ this.toolkit = toolkit;
+ }
+
+ Point getPointerPos() {
+ return lastScreenPos;
+ }
+
+ boolean dispatch(Component src, NativeEvent event) {
+ int id = event.getEventId();
+
+ lastScreenPos.setLocation(event.getScreenPos());
+ checkMouseEnterExit(event.getInputModifiers(), event.getTime());
+
+ if (id == MouseEvent.MOUSE_WHEEL) {
+// BEGIN android-changed: AWT components not supported
+// dispatchWheelEvent(src, event);
+// END android-changed
+ } else if ((id != MouseEvent.MOUSE_ENTERED) &&
+ (id != MouseEvent.MOUSE_EXITED)) {
+ PointerInfo info = new PointerInfo(src, event.getLocalPos());
+
+ mouseGrabManager.preprocessEvent(event);
+ findEventSource(info);
+ if ((id == MouseEvent.MOUSE_PRESSED) ||
+ (id == MouseEvent.MOUSE_RELEASED)) {
+
+ dispatchButtonEvent(info, event);
+ } else if ((id == MouseEvent.MOUSE_MOVED) ||
+ (id == MouseEvent.MOUSE_DRAGGED)) {
+
+ dispatchMotionEvent(info, event);
+ }
+ }
+
+ return false;
+ }
+
+ private void checkMouseEnterExit(int modifiers, long when) {
+// BEGIN android-changed: AWT components not supported
+// PointerInfo info = findComponentUnderPointer();
+// Component curUnderPointer =
+// propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
+// MouseListener.class, false).src;
+//
+// if (curUnderPointer != lastUnderPointer) {
+// Point pos = info.position;
+// if ((lastUnderPointer != null) &&
+// lastUnderPointer.isMouseExitedExpected()) {
+//
+// Point exitPos = convertPoint(null, lastScreenPos.x,
+// lastScreenPos.y, lastUnderPointer);
+//
+// postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when,
+// exitPos.x, exitPos.y, lastUnderPointer);
+// }
+// setCursor(curUnderPointer);
+// if (curUnderPointer != null) {
+// postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when,
+// pos.x, pos.y, curUnderPointer);
+// }
+// lastUnderPointer = curUnderPointer;
+// }
+// END android-changed
+ }
+
+ private void setCursor(Component comp) {
+ if (comp == null) {
+ return;
+ }
+ Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
+ Component cursorComp = ((grabOwner != null) &&
+ grabOwner.isShowing() ? grabOwner : comp);
+ cursorComp.setCursor();
+ }
+
+ private void postMouseEnterExit(int id, int mod, long when,
+ int x, int y, Component comp) {
+ if (comp.isIndirectlyEnabled()) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(comp, id, when, mod, x, y, 0, false));
+ comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED);
+ } else {
+ comp.setMouseExitedExpected(false);
+ }
+ }
+
+ // BEGIN android-changed: AWT components not supported
+// private PointerInfo findComponentUnderPointer() {
+// NativeWindow nativeWindow = toolkit.getWindowFactory().
+// getWindowFromPoint(lastScreenPos);
+//
+// if (nativeWindow != null) {
+// Component comp = toolkit.getComponentById(nativeWindow.getId());
+//
+// if (comp != null) {
+// Window window = comp.getWindowAncestor();
+// Point pointerPos = convertPoint(null, lastScreenPos.x,
+// lastScreenPos.y, window);
+//
+// if (window.getClient().contains(pointerPos)) {
+// PointerInfo info = new PointerInfo(window, pointerPos);
+//
+// fall2Child(info);
+//
+// return info;
+// }
+// }
+// }
+//
+// return new PointerInfo(null, null);
+// }
+// END android-changed
+
+ private void findEventSource(PointerInfo info) {
+ Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
+
+ if (grabOwner != null && grabOwner.isShowing()) {
+ info.position = convertPoint(info.src, info.position, grabOwner);
+ info.src = grabOwner;
+ } else {
+ //???AWT: rise2TopLevel(info);
+ //???AWT: fall2Child(info);
+ }
+ }
+
+ // BEGIN android-changed: AWT components not supported
+// private void rise2TopLevel(PointerInfo info) {
+// while (!(info.src instanceof Window)) {
+// info.position.translate(info.src.x, info.src.y);
+// info.src = info.src.parent;
+// }
+// }
+//
+// private void fall2Child(PointerInfo info) {
+// Insets insets = info.src.getInsets();
+//
+// final Point pos = info.position;
+// final int x = pos.x;
+// final int y = pos.y;
+// if ((x >= insets.left) && (y >= insets.top) &&
+// (x < (info.src.w - insets.right)) &&
+// (y < (info.src.h - insets.bottom)))
+// {
+// Component[] children = ((Container) info.src).getComponents();
+//
+// for (Component child : children) {
+// if (child.isShowing()) {
+// if (child.contains(x - child.getX(),
+// y - child.getY()))
+// {
+// info.src = child;
+// pos.translate(-child.x, -child.y);
+//
+// if (child instanceof Container) {
+// fall2Child(info);
+// }
+//
+// return;
+// }
+// }
+// }
+// }
+// }
+// END android-changed
+
+ private void dispatchButtonEvent(PointerInfo info, NativeEvent event) {
+ int button = event.getMouseButton();
+ long time = event.getTime();
+ int id = event.getEventId();
+ int index = button - 1;
+ boolean clickRequired = false;
+
+ propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
+ MouseListener.class, false);
+ if (id == MouseEvent.MOUSE_PRESSED) {
+ int clickInterval = toolkit.dispatcher.clickInterval;
+ mouseGrabManager.onMousePressed(info.src);
+ buttonPressed[index] = true;
+ clickCount[index] = (!deltaExceeded(index, info) &&
+ ((time - lastPressTime[index]) <= clickInterval)) ?
+ clickCount[index] + 1 : 1;
+ lastPressTime[index] = time;
+ lastPressPos[index] = info.position;
+ } else {
+ mouseGrabManager.onMouseReleased(info.src);
+ // set cursor back on synthetic mouse grab end:
+// BEGIN android-changed: AWT components not supported
+// setCursor(findComponentUnderPointer().src);
+// END android-changed
+ if (buttonPressed[index]) {
+ buttonPressed[index] = false;
+ clickRequired = !deltaExceeded(index, info);
+ } else {
+ clickCount[index] = 0;
+ }
+ }
+ if (info.src.isIndirectlyEnabled()) {
+ final Point pos = info.position;
+ final int mod = event.getInputModifiers();
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(info.src, id, time, mod, pos.x,
+ pos.y, clickCount[index],
+ event.getTrigger(), button));
+ if (clickRequired) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(info.src,
+ MouseEvent.MOUSE_CLICKED,
+ time, mod, pos.x, pos.y,
+ clickCount[index], false,
+ button));
+ }
+ }
+ }
+
+ private boolean deltaExceeded(int index, PointerInfo info) {
+ final Point lastPos = lastPressPos[index];
+ if (lastPos == null) {
+ return true;
+ }
+ return ((Math.abs(lastPos.x - info.position.x) > clickDelta) ||
+ (Math.abs(lastPos.y - info.position.y) > clickDelta));
+ }
+
+ private void dispatchMotionEvent(PointerInfo info, NativeEvent event) {
+ propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK,
+ MouseMotionListener.class, false);
+ final Point pos = info.position;
+ if ((lastUnderMotion != info.src) ||
+ !lastLocalPos.equals(pos)) {
+
+ lastUnderMotion = info.src;
+ lastLocalPos = pos;
+
+ if (info.src.isIndirectlyEnabled()) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(info.src, event.getEventId(),
+ event.getTime(),
+ event.getInputModifiers(),
+ pos.x, pos.y, 0, false));
+ }
+ }
+ }
+
+ MouseWheelEvent createWheelEvent(Component src, NativeEvent event,
+ Point where) {
+
+ Integer scrollAmountProperty =
+ (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$
+ int amount = 1;
+ int type = MouseWheelEvent.WHEEL_UNIT_SCROLL;
+
+ if (scrollAmountProperty != null) {
+ amount = scrollAmountProperty.intValue();
+ if (amount == -1) {
+ type = MouseWheelEvent.WHEEL_BLOCK_SCROLL;
+ amount = 1;
+ }
+ }
+ return new MouseWheelEvent(src, event.getEventId(),
+ event.getTime(), event.getInputModifiers(),
+ where.x, where.y, 0, false, type, amount,
+ event.getWheelRotation());
+ }
+
+// BEGIN android-changed: AWT components not supported
+// private void dispatchWheelEvent(Component src, NativeEvent event) {
+// PointerInfo info = findComponentUnderPointer();
+//
+// if (info.src == null) {
+// info.src = src;
+// info.position = event.getLocalPos();
+// }
+//
+// propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK,
+// MouseWheelListener.class, true);
+// if ((info.src != null) && info.src.isIndirectlyEnabled()) {
+// toolkit.getSystemEventQueueImpl().postEvent(
+// createWheelEvent(info.src, event, info.position));
+// }
+// }
+// END android-changed
+
+ private PointerInfo propagateEvent(PointerInfo info, long mask,
+ Class<? extends EventListener> type, boolean pierceHW) {
+ Component src = info.src;
+ while ((src != null) &&
+ (src.isLightweight() || pierceHW) &&
+ !(src.isMouseEventEnabled(mask) ||
+ (src.getListeners(type).length > 0))) {
+
+ info.position.translate(src.x, src.y);
+// BEGIN android-changed: AWT components not supported
+// src = src.parent;
+// END android-changed
+ info.src = src;
+ }
+
+ return info;
+ }
+
+// BEGIN android-changed: AWT components not supported
+// Window findWindowAt(Point p) {
+// NativeWindow nativeWindow =
+// toolkit.getWindowFactory().getWindowFromPoint(p);
+//
+// Window window = null;
+// if (nativeWindow != null) {
+// Component comp = toolkit.getComponentById(nativeWindow.getId());
+//
+// if (comp != null) {
+// window = comp.getWindowAncestor();
+// }
+// }
+// return window;
+// }
+// END android-changed
+
+ private class PointerInfo {
+
+ Component src;
+ Point position;
+
+ PointerInfo(Component src, Point position) {
+ this.src = src;
+ this.position = position;
+ }
+
+ }
+
+}
diff --git a/awt/java/awt/Paint.java b/awt/java/awt/Paint.java
new file mode 100644
index 0000000..f8732c8
--- /dev/null
+++ b/awt/java/awt/Paint.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+/**
+ * The Paint interface provides possibility of generating
+ * color patterns in device space for fill, draw, or stroke operations
+ * in a Graphics2D.
+ */
+public interface Paint extends Transparency {
+
+ /**
+ * Creates the PaintContext which is used to generate color
+ * patterns for rendering operations of Graphics2D.
+ *
+ * @param cm the ColorModel object, or null.
+ * @param deviceBounds the Rectangle represents the bounding box of
+ * device space for the graphics rendering operations.
+ * @param userBounds the Rectangle represents bounding box of
+ * user space for the graphics rendering operations.
+ * @param xform the AffineTransform for translation from user space
+ * to device space.
+ * @param hints the RenderingHints preferences.
+ *
+ * @return the PaintContext for generating color patterns.
+ */
+ PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+ Rectangle2D userBounds, AffineTransform xform,
+ RenderingHints hints);
+}
diff --git a/awt/java/awt/PaintContext.java b/awt/java/awt/PaintContext.java
new file mode 100644
index 0000000..647de8b
--- /dev/null
+++ b/awt/java/awt/PaintContext.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+/**
+ * The PaintContext interface determines the specific environment for
+ * generating color patterns in device space for fill, draw, or stroke
+ * rendering operations using Graphics2D. This interface provides colors
+ * through the Raster object associated with the specific ColorModel
+ * for Graphics2D rendering operations.
+ */
+public interface PaintContext {
+
+ /**
+ * Releases the resources allocated for the operation.
+ */
+ void dispose();
+
+ /**
+ * Gets the color model.
+ *
+ * @return the ColorModel object.
+ */
+ ColorModel getColorModel();
+
+ /**
+ * Gets the Raster which defines the colors of the specified rectangular
+ * area for Graphics2D rendering operations.
+ *
+ * @param x the X coordinate of the device space area for which
+ * colors are generated.
+ * @param y the Y coordinate of the device space area for which
+ * colors are generated.
+ * @param w the width of the device space area for which
+ * colors are generated.
+ * @param h the height of the device space area for which
+ * colors are generated.
+ *
+ * @return the Raster object which contains the colors of the specified
+ * rectangular area for Graphics2D rendering operations.
+ */
+ Raster getRaster(int x, int y, int w, int h);
+}
diff --git a/awt/java/awt/Point.java b/awt/java/awt/Point.java
new file mode 100644
index 0000000..99418ed
--- /dev/null
+++ b/awt/java/awt/Point.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.Point2D;
+import java.io.Serializable;
+
+/**
+ * The Point class represents a point location with coordinates X, Y in
+ * current coordinate system.
+ */
+public class Point extends Point2D implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -5276940640259749850L;
+
+ /** The X coordinate of Point. */
+ public int x;
+
+ /** The Y coordinate of Point. */
+ public int y;
+
+ /**
+ * Instantiates a new point with (0, O) coordinates, the origin of
+ * coordinate system.
+ */
+ public Point() {
+ setLocation(0, 0);
+ }
+
+ /**
+ * Instantiates a new point with (x, y) coordinates.
+ *
+ * @param x the X coordinate of Point.
+ * @param y the Y coordinate of Point.
+ */
+ public Point(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Instantiates a new point, giving it the same locaion as
+ * the parameter p.
+ *
+ * @param p the Point object giving the coordinates of the new point.
+ */
+ public Point(Point p) {
+ setLocation(p.x, p.y);
+ }
+
+ /**
+ * Compares current Point with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the Object being compared is a Point
+ * whose coordinates are equal to the coordinates of this
+ * Point, otherwise false.
+ *
+ * @see java.awt.geom.Point2D#equals(Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Point) {
+ Point p = (Point)obj;
+ return x == p.x && y == p.y;
+ }
+ return false;
+ }
+
+ /**
+ * Returns string representation of the current Point object.
+ *
+ * @return a string representation of the current Point object.
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Gets X coordinate of Point as a double.
+ *
+ * @return X coordinate of the point as a double.
+ *
+ * @see java.awt.geom.Point2D#getX()
+ */
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * Gets Y coordinate of Point as a double.
+ *
+ * @return Y coordinate of the point as a double.
+ *
+ * @see java.awt.geom.Point2D#getY()
+ */
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Gets the location of the Point as a new Point object.
+ *
+ * @return a copy of the Point.
+ */
+ public Point getLocation() {
+ return new Point(x, y);
+ }
+
+ /**
+ * Sets the location of the Point to the same coordinates as p.
+ *
+ * @param p the Point that gives the new location.
+ */
+ public void setLocation(Point p) {
+ setLocation(p.x, p.y);
+ }
+
+ /**
+ * Sets the location of the Point to the coordinates X, Y.
+ *
+ * @param x the X coordinate of the Point's new location.
+ * @param y the Y coordinate of the Point's new location.
+ */
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Sets the location of Point to the specified double coordinates.
+ *
+ * @param x the X the Point's new location.
+ * @param y the Y the Point's new location.
+ *
+ * @see java.awt.geom.Point2D#setLocation(double, double)
+ */
+ @Override
+ public void setLocation(double x, double y) {
+ x = x < Integer.MIN_VALUE ? Integer.MIN_VALUE : x > Integer.MAX_VALUE ? Integer.MAX_VALUE : x;
+ y = y < Integer.MIN_VALUE ? Integer.MIN_VALUE : y > Integer.MAX_VALUE ? Integer.MAX_VALUE : y;
+ setLocation((int)Math.round(x), (int)Math.round(y));
+ }
+
+ /**
+ * Moves the Point to the specified (x, y) location.
+ *
+ * @param x the X coordinate of the new location.
+ * @param y the Y coordinate of the new location.
+ */
+ public void move(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Translates current Point moving it from the position (x, y)
+ * to the new position given by (x+dx, x+dy) coordinates.
+ *
+ * @param dx the horizontal delta - the Point is moved to this distance along
+ * X axis.
+ * @param dy the vertical delta - the Point is moved to this distance along
+ * Y axis.
+ */
+ public void translate(int dx, int dy) {
+ x += dx;
+ y += dy;
+ }
+
+}
+
diff --git a/awt/java/awt/Polygon.java b/awt/java/awt/Polygon.java
new file mode 100644
index 0000000..6f3fc97
--- /dev/null
+++ b/awt/java/awt/Polygon.java
@@ -0,0 +1,494 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.*;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Polygon class defines an closed area specified by n vertices and
+ * n edges. The coordinates of the vertices are specified by x, y arrays.
+ * The edges are the line segments from the point (x[i], y[i]) to the point
+ * (x[i+1], y[i+1]), for -1 < i < (n-1) plus the line segment from
+ * the point (x[n-1], y[n-1]) to the point (x[0], y[0]) point.
+ * The Polygon is empty if the number of vertices is zero.
+ */
+public class Polygon implements Shape, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -6460061437900069969L;
+
+ /** The points buffer capacity. */
+ private static final int BUFFER_CAPACITY = 4;
+
+ /** The number of Polygon vertices.*/
+ public int npoints;
+
+ /** The array of X coordinates of the vertices. */
+ public int[] xpoints;
+
+ /** The array of Y coordinates of the vertices. */
+ public int[] ypoints;
+
+ /**
+ * The smallest Rectangle that completely contains this Polygon.
+ */
+ protected Rectangle bounds;
+
+ /*
+ * Polygon path iterator
+ */
+ /**
+ * The internal Class Iterator.
+ */
+ class Iterator implements PathIterator {
+
+ /** The source Polygon object. */
+ public Polygon p;
+
+ /** The path iterator transformation. */
+ public AffineTransform t;
+
+ /** The current segmenet index. */
+ public int index;
+
+ /**
+ * Constructs a new Polygon.Iterator for the given polygon and transformation
+ *
+ * @param at - the AffineTransform object to apply rectangle path
+ * @param p the p
+ */
+ public Iterator(AffineTransform at, Polygon p) {
+ this.p = p;
+ this.t = at;
+ if (p.npoints == 0) {
+ index = 1;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_EVEN_ODD;
+ }
+
+ public boolean isDone() {
+ return index > p.npoints;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.110=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
+ }
+ if (index == p.npoints) {
+ return SEG_CLOSE;
+ }
+ coords[0] = p.xpoints[index];
+ coords[1] = p.ypoints[index];
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return index == 0 ? SEG_MOVETO : SEG_LINETO;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.110=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
+ }
+ if (index == p.npoints) {
+ return SEG_CLOSE;
+ }
+ coords[0] = p.xpoints[index];
+ coords[1] = p.ypoints[index];
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return index == 0 ? SEG_MOVETO : SEG_LINETO;
+ }
+ }
+
+ /**
+ * Instantiates a new empty polygon.
+ */
+ public Polygon() {
+ xpoints = new int[BUFFER_CAPACITY];
+ ypoints = new int[BUFFER_CAPACITY];
+ }
+
+ /**
+ * Instantiates a new polygon with the specified number of vertices,
+ * and the given arrays of x, y vertex coordinates. The length of
+ * each coordinate array may not be less than the specified number of
+ * vertices but may be greater. Only the first n elements are used from
+ * each coordinate array.
+ *
+ * @param xpoints the array of X vertex coordinates.
+ * @param ypoints the array of Y vertex coordinates.
+ * @param npoints the number vertices of the polygon.
+ * @throws IndexOutOfBoundsException if the length of xpoints or ypoints
+ * is less than n.
+ * @throws NegativeArraySizeException if n is negative.
+ */
+ public Polygon(int[] xpoints, int[] ypoints, int npoints) {
+ if (npoints > xpoints.length || npoints > ypoints.length) {
+ // awt.111=Parameter npoints is greater than array length
+ throw new IndexOutOfBoundsException(Messages.getString("awt.111")); //$NON-NLS-1$
+ }
+ if (npoints < 0) {
+ // awt.112=Negative number of points
+ throw new NegativeArraySizeException(Messages.getString("awt.112")); //$NON-NLS-1$
+ }
+ this.npoints = npoints;
+ this.xpoints = new int[npoints];
+ this.ypoints = new int[npoints];
+ System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
+ System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
+ }
+
+ /**
+ * Resets the current Polygon to an empty Polygon. More precisely,
+ * the number of Polygon vertices is set to zero, but x, y coordinates
+ * arrays are not affected.
+ */
+ public void reset() {
+ npoints = 0;
+ bounds = null;
+ }
+
+ /**
+ * Invalidates the data that depends on the vertex coordinates.
+ * This method should be called after direct manipulations
+ * of the x, y vertex coordinates arrays to avoid unpredictable
+ * results of methods which rely on the bounding box.
+ */
+ public void invalidate() {
+ bounds = null;
+ }
+
+ /**
+ * Adds the point to the Polygon and updates the bounding box
+ * accordingly.
+ *
+ * @param px the X coordinate of the added vertex.
+ * @param py the Y coordinate of the added vertex.
+ */
+ public void addPoint(int px, int py) {
+ if (npoints == xpoints.length) {
+ int[] tmp;
+
+ tmp = new int[xpoints.length + BUFFER_CAPACITY];
+ System.arraycopy(xpoints, 0, tmp, 0, xpoints.length);
+ xpoints = tmp;
+
+ tmp = new int[ypoints.length + BUFFER_CAPACITY];
+ System.arraycopy(ypoints, 0, tmp, 0, ypoints.length);
+ ypoints = tmp;
+ }
+
+ xpoints[npoints] = px;
+ ypoints[npoints] = py;
+ npoints++;
+
+ if (bounds != null) {
+ bounds.setFrameFromDiagonal(
+ Math.min(bounds.getMinX(), px),
+ Math.min(bounds.getMinY(), py),
+ Math.max(bounds.getMaxX(), px),
+ Math.max(bounds.getMaxY(), py));
+ }
+ }
+
+ /**
+ * Gets the bounding rectangle of the Polygon. The bounding rectangle
+ * is the smallest rectangle which contains the Polygon.
+ *
+ * @return the bounding rectangle of the Polygon.
+ *
+ * @see java.awt.Shape#getBounds()
+ */
+ public Rectangle getBounds() {
+ if (bounds != null) {
+ return bounds;
+ }
+ if (npoints == 0) {
+ return new Rectangle();
+ }
+
+ int bx1 = xpoints[0];
+ int by1 = ypoints[0];
+ int bx2 = bx1;
+ int by2 = by1;
+
+ for (int i = 1; i < npoints; i++) {
+ int x = xpoints[i];
+ int y = ypoints[i];
+ if (x < bx1) {
+ bx1 = x;
+ } else if (x > bx2) {
+ bx2 = x;
+ }
+ if (y < by1) {
+ by1 = y;
+ } else if (y > by2) {
+ by2 = y;
+ }
+ }
+
+ return bounds = new Rectangle(bx1, by1, bx2 - bx1, by2 - by1);
+ }
+
+ /**
+ * Gets the bounding rectangle of the Polygon. The bounding rectangle
+ * is the smallest rectangle which contains the Polygon.
+ *
+ * @return the bounding rectangle of the Polygon.
+ *
+ * @deprecated Use getBounds() method.
+ */
+ @Deprecated
+ public Rectangle getBoundingBox() {
+ return getBounds();
+ }
+
+ /**
+ * Gets the Rectangle2D which represents Polygon bounds.
+ * The bounding rectangle is the smallest rectangle which contains
+ * the Polygon.
+ *
+ * @return the bounding rectangle of the Polygon.
+ *
+ * @see java.awt.Shape#getBounds2D()
+ */
+ public Rectangle2D getBounds2D() {
+ return getBounds().getBounds2D();
+ }
+
+ /**
+ * Translates all vertices of Polygon the specified distances
+ * along X, Y axis.
+ *
+ * @param mx the distance to translate horizontally.
+ * @param my the distance to translate vertically.
+ */
+ public void translate(int mx, int my) {
+ for (int i = 0; i < npoints; i++) {
+ xpoints[i] += mx;
+ ypoints[i] += my;
+ }
+ if (bounds != null) {
+ bounds.translate(mx, my);
+ }
+ }
+
+ /**
+ * Checks whether or not the point given by the coordinates x, y lies inside
+ * the Polygon.
+ *
+ * @param x the X coordinate of the point to check.
+ * @param y the Y coordinate of the point to check.
+ *
+ * @return true, if the specified point lies inside the Polygon,
+ * otherwise false.
+ *
+ * @deprecated Use contains(int, int) method.
+ */
+ @Deprecated
+ public boolean inside(int x, int y) {
+ return contains((double) x, (double) y);
+ }
+
+ /**
+ * Checks whether or not the point given by the coordinates x, y lies inside
+ * the Polygon.
+ *
+ * @param x the X coordinate of the point to check.
+ * @param y the Y coordinate of the point to check.
+ *
+ * @return true, if the specified point lies inside the Polygon,
+ * otherwise false.
+ */
+ public boolean contains(int x, int y) {
+ return contains((double) x, (double) y);
+ }
+
+ /**
+ * Checks whether or not the point with specified double coordinates
+ * lies inside the Polygon.
+ *
+ * @param x the X coordinate of the point to check.
+ * @param y the Y coordinate of the point to check.
+ *
+ * @return true, if the point given by the double coordinates
+ * lies inside the Polygon, otherwise false.
+ *
+ * @see java.awt.Shape#contains(double, double)
+ */
+ public boolean contains(double x, double y) {
+ return Crossing.isInsideEvenOdd(Crossing.crossShape(this, x, y));
+ }
+
+ /**
+ * Checks whether or not the rectangle determined by the parameters
+ * [x, y, width, height] lies inside the Polygon.
+ *
+ * @param x the X coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param y the Y coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param width the width of rectangle as a double.
+ * @param width the height of rectangle as a double.
+ *
+ * @return true, if the specified rectangle lies inside the Polygon,
+ * otherwise false.
+ *
+ * @see java.awt.Shape#contains(double, double, double, double)
+ */
+ public boolean contains(double x, double y, double width, double height) {
+ int cross = Crossing.intersectShape(this, x, y, width, height);
+ return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+ }
+
+ /**
+ * Checks whether or not the rectangle determined by the parameters
+ * [x, y, width, height] intersects the interior of
+ * the Polygon.
+ *
+ * @param x the X coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param y the Y coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param width the width of rectangle as a double.
+ * @param width the height of rectangle as a double.
+ *
+ * @return true, if the specified rectangle intersects the interior of
+ * the Polygon, otherwise false.
+ *
+ * @see java.awt.Shape#intersects(double, double, double, double)
+ */
+ public boolean intersects(double x, double y, double width, double height) {
+ int cross = Crossing.intersectShape(this, x, y, width, height);
+ return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+ }
+
+ /**
+ * Checks whether or not the specified rectangle lies inside the Polygon.
+ *
+ * @param rect the Rectangle2D object.
+ *
+ * @return true, if the specified rectangle lies inside the Polygon,
+ * otherwise false.
+ *
+ * @see java.awt.Shape#contains(java.awt.geom.Rectangle2D)
+ */
+ public boolean contains(Rectangle2D rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ /**
+ * Checks whether or not the specified Point lies inside the Polygon.
+ *
+ * @param point the Point object.
+ *
+ * @return true, if the specified Point lies inside the Polygon,
+ * otherwise false.
+ */
+ public boolean contains(Point point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ /**
+ * Checks whether or not the specified Point2D lies inside the Polygon.
+ *
+ * @param point the Point2D object.
+ *
+ * @return true, if the specified Point2D lies inside the Polygon,
+ * otherwise false.
+ *
+ * @see java.awt.Shape#contains(java.awt.geom.Point2D)
+ */
+ public boolean contains(Point2D point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ /**
+ * Checks whether or not the interior of rectangle specified by
+ * the Rectangle2D object intersects the interior of the Polygon.
+ *
+ * @param rect the Rectangle2D object.
+ *
+ * @return true, if the Rectangle2D intersects the interior of
+ * the Polygon, otherwise false.
+ *
+ * @see java.awt.Shape#intersects(java.awt.geom.Rectangle2D)
+ */
+ public boolean intersects(Rectangle2D rect) {
+ return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ /**
+ * Gets the PathIterator object which gives the coordinates of
+ * the polygon, transformed according to the specified AffineTransform.
+ *
+ * @param t the specified AffineTransform object, or null.
+ *
+ * @return PathIterator object for the Polygon.
+ *
+ * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform)
+ */
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(t, this);
+ }
+
+ /**
+ * Gets the PathIterator object which gives the coordinates of
+ * the polygon, transformed according to the specified AffineTransform.
+ * The flatness parameter is ignored.
+ *
+ * @param t the specified AffineTransform object, or null.
+ * @param flatness the maximum number of the control points for
+ * a given curve which varies from colinear before a subdivided curve
+ * is replaced by a straight line connecting the endpoints.
+ * This parameter is ignored for the Polygon class.
+ *
+ * @return PathIterator object for the Polygon.
+ *
+ * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform, double)
+ */
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new Iterator(t, this);
+ }
+
+}
+
diff --git a/awt/java/awt/Rectangle.java b/awt/java/awt/Rectangle.java
new file mode 100644
index 0000000..86c4dfc
--- /dev/null
+++ b/awt/java/awt/Rectangle.java
@@ -0,0 +1,686 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+
+/**
+ * The Rectangle class defines the rectangular area in terms of its
+ * upper left corner coordinates [x,y], its width, and its height.
+ * A Rectangle specified by [x, y, width, height] parameters has an
+ * outline path with corners at [x, y], [x + width,y], [x + width,y + height],
+ * and [x, y + height].
+ * <br><br>
+ * The rectangle is empty if the width or height is negative or zero.
+ * In this case the isEmpty method returns true.
+ */
+public class Rectangle extends Rectangle2D implements Shape, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4345857070255674764L;
+
+ /** The X coordinate of the rectangle's left upper corner. */
+ public int x;
+
+ /** The Y coordinate of the rectangle's left upper corner. */
+ public int y;
+
+ /** The width of rectangle. */
+ public int width;
+
+ /** The height of rectangle. */
+ public int height;
+
+ /**
+ * Instantiates a new rectangle with [0, 0] upper left corner coordinates,
+ * the width and the height are zero.
+ */
+ public Rectangle() {
+ setBounds(0, 0, 0, 0);
+ }
+
+ /**
+ * Instantiates a new rectangle whose upper left corner coordinates are
+ * given by the Point object (p.X and p.Y), and the width and
+ * the height are zero.
+ *
+ * @param p the Point specifies the upper left corner coordinates of
+ * the rectangle.
+ */
+ public Rectangle(Point p) {
+ setBounds(p.x, p.y, 0, 0);
+ }
+
+ /**
+ * Instantiates a new rectangle whose upper left corner coordinates are
+ * given by the Point object (p.X and p.Y), and the width and the height
+ * are given by Dimension object (d.width and d.height).
+ *
+ * @param p the Point specifies the upper left corner coordinates of
+ * the rectangle.
+ * @param d the Dimention specifies the width and the height of the rectangle.
+ */
+ public Rectangle(Point p, Dimension d) {
+ setBounds(p.x, p.y, d.width, d.height);
+ }
+
+ /**
+ * Instantiates a new rectangle determined by the upper left corner
+ * coordinates (x, y), width and height.
+ *
+ * @param x the X upper left corner coordinate of the rectangle.
+ * @param y the Y upper left corner coordinate of the rectangle.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public Rectangle(int x, int y, int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Instantiates a new rectangle with [0, 0] as its upper left
+ * corner coordinates and the specified width and height.
+ *
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public Rectangle(int width, int height) {
+ setBounds(0, 0, width, height);
+ }
+
+ /**
+ * Instantiates a new rectangle with the same coordinates
+ * as the given source rectangle.
+ *
+ * @param r the Rectangle object which parameters will be used for
+ * instantiating a new Rectangle.
+ */
+ public Rectangle(Rectangle r) {
+ setBounds(r.x, r.y, r.width, r.height);
+ }
+/*
+ public Rectangle(Dimension d) {
+ setBounds(0, 0, d.width, d.height);
+ }
+*/
+ /**
+ * Gets the X coordinate of bound as a double.
+ *
+ * @return the X coordinate of bound as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getX()
+ */
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * Gets the Y coordinate of bound as a double.
+ *
+ * @return the Y coordinate of bound as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getY()
+ */
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Gets the height of the rectangle as a double.
+ *
+ * @return the height of the rectangle as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getHeight()
+ */
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the width of the rectangle as a double.
+ *
+ * @return the width of the rectangle as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getWidth()
+ */
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ /**
+ * Determines whether or not the rectangle is empty. The rectangle is empty if
+ * its width or height is negative or zero.
+ *
+ * @return true, if the rectangle is empty, otherwise false.
+ *
+ * @see java.awt.geom.RectangularShape#isEmpty()
+ */
+ @Override
+ public boolean isEmpty() {
+ return width <= 0 || height <= 0;
+ }
+
+ /**
+ * Gets the size of a Rectangle as Dimention object.
+ *
+ * @return a Dimention object which represents size of the rectangle.
+ */
+ public Dimension getSize() {
+ return new Dimension(width, height);
+ }
+
+ /**
+ * Sets the size of the Rectangle.
+ *
+ * @param width the new width of the rectangle.
+ * @param height the new height of the rectangle.
+ */
+ public void setSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the size of a Rectangle specified as Dimension object.
+ *
+ * @param d a Dimension object which represents new size of a rectangle.
+ */
+ public void setSize(Dimension d) {
+ setSize(d.width, d.height);
+ }
+
+ /**
+ * Gets the location of a rectangle's upper left corner as a Point object.
+ *
+ * @return the Point object with coordinates equal to the upper left corner
+ * of the rectangle.
+ */
+ public Point getLocation() {
+ return new Point(x, y);
+ }
+
+ /**
+ * Sets the location of the rectangle in terms of its upper left
+ * corner coordinates X and Y.
+ *
+ * @param x the X coordinate of the rectangle's upper left corner.
+ * @param y the Y coordinate of the rectangle's upper left corner.
+ */
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Sets the location of a rectangle using a Point object to give the
+ * coordinates of the upper left corner.
+ *
+ * @param p the Point object which represents the new upper left corner
+ * coordinates of rectangle.
+ */
+ public void setLocation(Point p) {
+ setLocation(p.x, p.y);
+ }
+
+ /**
+ * Moves a rectangle to the new location by moving its upper left corner
+ * to the point with coordinates X and Y.
+ *
+ * @param x the new X coordinate of the rectangle's upper left corner.
+ * @param y the new Y coordinate of the rectangle's upper left corner.
+ *
+ * @deprecated Use setLocation(int, int) method.
+ */
+ @Deprecated
+ public void move(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Sets the rectangle to be the nearest rectangle with integer coordinates
+ * bounding the rectangle defined by the double-valued parameters.
+ *
+ * @param x the X coordinate of the upper left corner of the double-valued
+ * rectangle to be bounded.
+ * @param y the Y coordinate of the upper left corner of the double-valued
+ * rectangle to be bounded.
+ * @param width the width of the rectangle to be bounded.
+ * @param height the height of the rectangle to be bounded.
+ *
+ * @see java.awt.geom.Rectangle2D#setRect(double, double, double, double)
+ */
+ @Override
+ public void setRect(double x, double y, double width, double height) {
+ int x1 = (int)Math.floor(x);
+ int y1 = (int)Math.floor(y);
+ int x2 = (int)Math.ceil(x + width);
+ int y2 = (int)Math.ceil(y + height);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Sets a new size for the rectangle.
+ *
+ * @param width the rectangle's new width.
+ * @param height the rectangle's new height.
+ *
+ * @deprecated use the setSize(int, int) method.
+ */
+ @Deprecated
+ public void resize(int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Resets the bounds of a rectangle to the specified x, y, width and height
+ * parameters.
+ *
+ * @param x the new X coordinate of the upper left corner.
+ * @param y the new Y coordinate of the upper left corner.
+ * @param width the new width of rectangle.
+ * @param height the new height of rectangle.
+ *
+ * @deprecated use setBounds(int, int, int, int) method
+ */
+ @Deprecated
+ public void reshape(int x, int y, int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Gets bounds of the rectangle as a new Rectangle object.
+ *
+ * @return the Rectangle object with the same bounds as
+ * the original rectangle.
+ *
+ * @see java.awt.geom.RectangularShape#getBounds()
+ */
+ @Override
+ public Rectangle getBounds() {
+ return new Rectangle(x, y, width, height);
+ }
+
+ /**
+ * Gets the bounds of the original rectangle as a Rectangle2D object.
+ *
+ * @return the Rectangle2D object which represents the bounds of
+ * the original rectangle.
+ *
+ * @see java.awt.geom.Rectangle2D#getBounds2D()
+ */
+ @Override
+ public Rectangle2D getBounds2D() {
+ return getBounds();
+ }
+
+ /**
+ * Sets the bounds of a rectangle to the specified x, y, width, and height
+ * parameters.
+ *
+ * @param x the X coordinate of the upper left corner.
+ * @param y the Y coordinate of the upper left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public void setBounds(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.height = height;
+ this.width = width;
+ }
+
+ /**
+ * Sets the bounds of the rectangle to match the bounds of the
+ * Rectangle object sent as a parameter.
+ *
+ * @param r the Rectangle object which specifies the new bounds.
+ */
+ public void setBounds(Rectangle r) {
+ setBounds(r.x, r.y, r.width, r.height);
+ }
+
+ /**
+ * Enlarges the rectangle by moving each corner outward from the
+ * center by a distance of dx horizonally and a distance of dy
+ * vertically. Specifically, changes a rectangle with
+ * [x, y, width, height] parameters to
+ * a rectangle with [x-dx, y-dy, width+2*dx, height+2*dy]
+ * parameters.
+ *
+ * @param dx the horizontal distance to move each corner coordinate.
+ * @param dy the vertical distance to move each corner coordinate.
+ */
+ public void grow(int dx, int dy) {
+ x -= dx;
+ y -= dy;
+ width += dx + dx;
+ height += dy + dy;
+ }
+
+ /**
+ * Moves a rectangle a distance of mx along the x coordinate axis
+ * and a distance of my along y coordinate axis.
+ *
+ * @param mx the horizontal translation increment.
+ * @param my the vertical translation increment.
+ */
+ public void translate(int mx, int my) {
+ x += mx;
+ y += my;
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified point.
+ *
+ * @param px the X coordinate of the new point to be covered by the rectangle.
+ * @param py the Y coordinate of the new point to be covered by the rectangle.
+ */
+ public void add(int px, int py) {
+ int x1 = Math.min(x, px);
+ int x2 = Math.max(x + width, px);
+ int y1 = Math.min(y, py);
+ int y2 = Math.max(y + height, py);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified point with the
+ * new point given as a Point object.
+ *
+ * @param p the Point object that specifies the new point to
+ * be covered by the rectangle.
+ */
+ public void add(Point p) {
+ add(p.x, p.y);
+ }
+
+ /**
+ * Adds a new rectangle to the original rectangle, the result is an union of
+ * the specified specified rectangle and original rectangle.
+ *
+ * @param r the Rectangle which is added to the original rectangle.
+ */
+ public void add(Rectangle r) {
+ int x1 = Math.min(x, r.x);
+ int x2 = Math.max(x + width, r.x + r.width);
+ int y1 = Math.min(y, r.y);
+ int y2 = Math.max(y + height, r.y + r.height);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Determines whether or not the point with specified coordinates [px, py]
+ * is within the bounds of the rectangle.
+ *
+ * @param px the X coordinate of point.
+ * @param py the Y coordinate of point.
+ *
+ * @return true, if the point with specified coordinates [px, py] is
+ * within the bounds of the rectangle, otherwise false.
+ */
+ public boolean contains(int px, int py) {
+ if (isEmpty()) {
+ return false;
+ }
+ if (px < x || py < y) {
+ return false;
+ }
+ px -= x;
+ py -= y;
+ return px < width && py < height;
+ }
+
+ /**
+ * Determines whether or not the point given as a Point object
+ * is within the bounds of the rectangle.
+ *
+ * @param p the Point object
+ *
+ * @return true, if the point p is within the bounds of the
+ * rectangle, otherwise false.
+ */
+ public boolean contains(Point p) {
+ return contains(p.x, p.y);
+ }
+
+ /**
+ * Determines whether or not the rectangle specified by [rx, ry, rw, rh]
+ * parameters is located inside the original rectangle.
+ *
+ * @param rx the X coordinate of the rectangle to compare.
+ * @param ry the Y coordinate of the rectangle to compare.
+ * @param rw the width of the rectangle to compare.
+ * @param rh the height of the rectangle to compare.
+ *
+ * @return true, if a rectangle with [rx, ry, rw, rh] parameters is entirely
+ * contained in the original rectangle, otherwise false.
+ */
+ public boolean contains(int rx, int ry, int rw, int rh) {
+ return contains(rx, ry) && contains(rx + rw - 1, ry + rh - 1);
+ }
+
+ /**
+ * Compares whether or not the rectangle specified by the Rectangle object
+ * is located inside the original rectangle.
+ *
+ * @param r the Rectangle object.
+ *
+ * @return true, if the rectangle specified by Rectangle object is entirely
+ * contained in the original rectangle, otherwise false.
+ */
+ public boolean contains(Rectangle r) {
+ return contains(r.x, r.y, r.width, r.height);
+ }
+
+ /**
+ * Compares whether or not a point with specified coordinates [px, py] belongs
+ * to a rectangle.
+ *
+ * @param px the X coordinate of a point.
+ * @param py the Y coordinate of a point.
+ *
+ * @return true, if a point with specified coordinates [px, py] belongs
+ * to a rectangle, otherwise false.
+ *
+ * @deprecated use contains(int, int) method.
+ */
+ @Deprecated
+ public boolean inside(int px, int py) {
+ return contains(px, py);
+ }
+
+ /**
+ * Returns the intersection of the original rectangle with the
+ * specified Rectangle2D.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return the Rectangle2D object that is the result of intersecting
+ * the original rectangle with the specified Rectangle2D.
+ *
+ * @see java.awt.geom.Rectangle2D#createIntersection(java.awt.geom.Rectangle2D)
+ */
+ @Override
+ public Rectangle2D createIntersection(Rectangle2D r) {
+ if (r instanceof Rectangle) {
+ return intersection((Rectangle) r);
+ }
+ Rectangle2D dst = new Rectangle2D.Double();
+ Rectangle2D.intersect(this, r, dst);
+ return dst;
+ }
+
+ /**
+ * Returns the intersection of the original rectangle with the
+ * specified rectangle. An empty rectangle is returned if there is no
+ * intersection.
+ *
+ * @param r the Rectangle object.
+ *
+ * @return the Rectangle object is result of the original rectangle with the
+ * specified rectangle.
+ */
+ public Rectangle intersection(Rectangle r) {
+ int x1 = Math.max(x, r.x);
+ int y1 = Math.max(y, r.y);
+ int x2 = Math.min(x + width, r.x + r.width);
+ int y2 = Math.min(y + height, r.y + r.height);
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Determines whether or not the original rectangle intersects
+ * the specified rectangle.
+ *
+ * @param r the Rectangle object.
+ *
+ * @return true, if the two rectangles overlap; otherwise false.
+ */
+ public boolean intersects(Rectangle r) {
+ return !intersection(r).isEmpty();
+ }
+
+ /**
+ * Determines where the specified Point is located with respect to
+ * the rectangle. This method computes whether the point is to the
+ * right or to the left of the rectangle and whether it is above
+ * or below the rectangle, and packs the result into an int by
+ * using a binary OR operation with the following masks:
+ * <ul>
+ *<li>Rectangle2D.OUT_LEFT</li>
+ *<li>Rectangle2D.OUT_TOP</li>
+ *<li>Rectangle2D.OUT_RIGHT</li>
+ *<li>Rectangle2D.OUT_BOTTOM</li>
+ *</ul>
+ *
+ * If the rectangle is empty, all masks are set, and if the
+ * point is inside the rectangle, none are set.
+ *
+ * @param px the X coordinate of the specified point.
+ * @param py the Y coordinate of the specified point.
+ *
+ * @return the location of the Point relative to the rectangle
+ * as the result of logical OR operation with all out masks.
+ *
+ * @see java.awt.geom.Rectangle2D#outcode(double, double)
+ */
+ @Override
+ public int outcode(double px, double py) {
+ int code = 0;
+
+ if (width <= 0) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else
+ if (px < x) {
+ code |= OUT_LEFT;
+ } else
+ if (px > x + width) {
+ code |= OUT_RIGHT;
+ }
+
+ if (height <= 0) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else
+ if (py < y) {
+ code |= OUT_TOP;
+ } else
+ if (py > y + height) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified Rectangle2D.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return the union of the original and the specified Rectangle2D.
+ *
+ * @see java.awt.geom.Rectangle2D#createUnion(java.awt.geom.Rectangle2D)
+ */
+ @Override
+ public Rectangle2D createUnion(Rectangle2D r) {
+ if (r instanceof Rectangle) {
+ return union((Rectangle)r);
+ }
+ Rectangle2D dst = new Rectangle2D.Double();
+ Rectangle2D.union(this, r, dst);
+ return dst;
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified rectangle.
+ *
+ * @param r the Rectangle.
+ *
+ * @return the union of the original and the specified rectangle.
+ */
+ public Rectangle union(Rectangle r) {
+ Rectangle dst = new Rectangle(this);
+ dst.add(r);
+ return dst;
+ }
+
+ /**
+ * Compares the original Rectangle with the specified object.
+ *
+ * @param obj the specified Object for comparison.
+ *
+ * @return true, if the specified Object is a rectangle with the
+ * same dimensions as the original rectangle, otherwise false.
+ *
+ * @see java.awt.geom.Rectangle2D#equals(Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Rectangle) {
+ Rectangle r = (Rectangle)obj;
+ return r.x == x && r.y == y && r.width == width && r.height == height;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string representation of the rectangle; the string contains
+ * [x, y, width, height] parameters of the rectangle.
+ *
+ * @return the string representation of the rectangle.
+ */
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Rectangle().toString())
+ return getClass().getName() + "[x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$
+ ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+}
+
diff --git a/awt/java/awt/RenderingHints.java b/awt/java/awt/RenderingHints.java
new file mode 100644
index 0000000..4957884
--- /dev/null
+++ b/awt/java/awt/RenderingHints.java
@@ -0,0 +1,601 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The RenderingHints class represents preferences for the rendering algorithms.
+ * The preferences are arbitrary and can be specified by Map objects or by
+ * key-value pairs.
+ */
+public class RenderingHints implements Map<Object, Object>, Cloneable {
+
+ /**
+ * The Constant KEY_ALPHA_INTERPOLATION - alpha interpolation rendering
+ * hint key.
+ */
+ public static final Key KEY_ALPHA_INTERPOLATION = new KeyImpl(1);
+
+ /**
+ * The Constant VALUE_ALPHA_INTERPOLATION_DEFAULT - alpha interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT = new KeyValue(KEY_ALPHA_INTERPOLATION);
+
+ /**
+ * The Constant VALUE_ALPHA_INTERPOLATION_SPEED - alpha interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_ALPHA_INTERPOLATION_SPEED = new KeyValue(KEY_ALPHA_INTERPOLATION);
+
+ /**
+ * The Constant VALUE_ALPHA_INTERPOLATION_QUALITY - alpha interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY = new KeyValue(KEY_ALPHA_INTERPOLATION);
+
+ /**
+ * The Constant KEY_ANTIALIASING - antialiasing rendering
+ * hint key.
+ */
+ public static final Key KEY_ANTIALIASING = new KeyImpl(2);
+
+ /**
+ * The Constant VALUE_ANTIALIAS_DEFAULT - antialiasing
+ * rendering hint value.
+ */
+ public static final Object VALUE_ANTIALIAS_DEFAULT = new KeyValue(KEY_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_ANTIALIAS_ON - antialiasing
+ * rendering hint value.
+ */
+ public static final Object VALUE_ANTIALIAS_ON = new KeyValue(KEY_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_ANTIALIAS_OFF - antialiasing
+ * rendering hint value.
+ */
+ public static final Object VALUE_ANTIALIAS_OFF = new KeyValue(KEY_ANTIALIASING);
+
+ /**
+ * The Constant KEY_COLOR_RENDERING - color rendering
+ * hint key.
+ */
+ public static final Key KEY_COLOR_RENDERING = new KeyImpl(3);
+
+ /**
+ * The Constant VALUE_COLOR_RENDER_DEFAULT - color
+ * rendering hint value.
+ */
+ public static final Object VALUE_COLOR_RENDER_DEFAULT = new KeyValue(KEY_COLOR_RENDERING);
+
+ /**
+ * The Constant VALUE_COLOR_RENDER_SPEED - color
+ * rendering hint value.
+ */
+ public static final Object VALUE_COLOR_RENDER_SPEED = new KeyValue(KEY_COLOR_RENDERING);
+
+ /**
+ * The Constant VALUE_COLOR_RENDER_QUALITY - color
+ * rendering hint value.
+ */
+ public static final Object VALUE_COLOR_RENDER_QUALITY = new KeyValue(KEY_COLOR_RENDERING);
+
+ /**
+ * The Constant KEY_DITHERING - dithering
+ * rendering hint key.
+ */
+ public static final Key KEY_DITHERING = new KeyImpl(4);
+
+ /**
+ * The Constant VALUE_DITHER_DEFAULT - dithering
+ * rendering hint value.
+ */
+ public static final Object VALUE_DITHER_DEFAULT = new KeyValue(KEY_DITHERING);
+
+ /**
+ * The Constant VALUE_DITHER_DISABLE - dithering
+ * rendering hint value.
+ */
+ public static final Object VALUE_DITHER_DISABLE = new KeyValue(KEY_DITHERING);
+
+ /**
+ * The Constant VALUE_DITHER_DISABLE - dithering
+ * rendering hint value.
+ */
+ public static final Object VALUE_DITHER_ENABLE = new KeyValue(KEY_DITHERING);
+
+ /**
+ * The Constant KEY_FRACTIONALMETRICS - fractional metrics
+ * rendering hint key.
+ */
+ public static final Key KEY_FRACTIONALMETRICS = new KeyImpl(5);
+
+ /**
+ * The Constant VALUE_FRACTIONALMETRICS_DEFAULT - fractional metrics
+ * rendering hint value.
+ */
+ public static final Object VALUE_FRACTIONALMETRICS_DEFAULT = new KeyValue(KEY_FRACTIONALMETRICS);
+
+ /**
+ * The Constant VALUE_FRACTIONALMETRICS_ON - fractional metrics
+ * rendering hint value.
+ */
+ public static final Object VALUE_FRACTIONALMETRICS_ON = new KeyValue(KEY_FRACTIONALMETRICS);
+
+ /**
+ * The Constant VALUE_FRACTIONALMETRICS_OFF - fractional metrics
+ * rendering hint value.
+ */
+ public static final Object VALUE_FRACTIONALMETRICS_OFF = new KeyValue(KEY_FRACTIONALMETRICS);
+
+ /**
+ * The Constant KEY_INTERPOLATION - interpolation
+ * rendering hint key.
+ */
+ public static final Key KEY_INTERPOLATION = new KeyImpl(6);
+
+ /**
+ * The Constant VALUE_INTERPOLATION_BICUBIC - interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_INTERPOLATION_BICUBIC = new KeyValue(KEY_INTERPOLATION);
+
+ /**
+ * The Constant VALUE_INTERPOLATION_BILINEAR - interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_INTERPOLATION_BILINEAR = new KeyValue(KEY_INTERPOLATION);
+
+ /** The Constant VALUE_INTERPOLATION_NEAREST_NEIGHBOR - interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR = new KeyValue(KEY_INTERPOLATION);
+
+ /**
+ * The Constant KEY_RENDERING - rendering hint key.
+ */
+ public static final Key KEY_RENDERING = new KeyImpl(7);
+
+ /**
+ * The Constant VALUE_RENDER_DEFAULT - rendering hint value.
+ */
+ public static final Object VALUE_RENDER_DEFAULT = new KeyValue(KEY_RENDERING);
+
+ /**
+ * The Constant VALUE_RENDER_SPEED - rendering hint value.
+ */
+ public static final Object VALUE_RENDER_SPEED = new KeyValue(KEY_RENDERING);
+
+ /**
+ * The Constant VALUE_RENDER_QUALITY - rendering hint value.
+ */
+ public static final Object VALUE_RENDER_QUALITY = new KeyValue(KEY_RENDERING);
+
+ /**
+ * The Constant KEY_STROKE_CONTROL - stroke control hint key.
+ */
+ public static final Key KEY_STROKE_CONTROL = new KeyImpl(8);
+
+ /**
+ * The Constant VALUE_STROKE_DEFAULT - stroke hint value.
+ */
+ public static final Object VALUE_STROKE_DEFAULT = new KeyValue(KEY_STROKE_CONTROL);
+
+ /**
+ * The Constant VALUE_STROKE_NORMALIZE - stroke hint value.
+ */
+ public static final Object VALUE_STROKE_NORMALIZE = new KeyValue(KEY_STROKE_CONTROL);
+
+ /**
+ * The Constant VALUE_STROKE_PURE - stroke hint value.
+ */
+ public static final Object VALUE_STROKE_PURE = new KeyValue(KEY_STROKE_CONTROL);
+
+ /**
+ * The Constant KEY_TEXT_ANTIALIASING - text antialiasing hint key.
+ */
+ public static final Key KEY_TEXT_ANTIALIASING = new KeyImpl(9);
+
+ /**
+ * The Constant VALUE_TEXT_ANTIALIAS_DEFAULT - text antialiasing hint key.
+ */
+ public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_TEXT_ANTIALIAS_ON - text antialiasing hint key.
+ */
+ public static final Object VALUE_TEXT_ANTIALIAS_ON = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_TEXT_ANTIALIAS_OFF - text antialiasing hint key.
+ */
+ public static final Object VALUE_TEXT_ANTIALIAS_OFF = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+ /** The map. */
+ private HashMap<Object, Object> map = new HashMap<Object, Object>();
+
+ /**
+ * Instantiates a new rendering hints object from specified Map object with defined
+ * key/value pairs or null for empty RenderingHints.
+ *
+ * @param map the Map object with defined key/value pairs or null for
+ * empty RenderingHints.
+ */
+ public RenderingHints(Map<Key, ?> map) {
+ super();
+ if (map != null) {
+ putAll(map);
+ }
+ }
+
+ /**
+ * Instantiates a new rendering hints object with the specified key/value pair.
+ *
+ * @param key the key of hint property.
+ * @param value the value of hint property.
+ */
+ public RenderingHints(Key key, Object value) {
+ super();
+ put(key, value);
+ }
+
+ /**
+ * Adds the properties represented by key/value pairs from the specified
+ * RenderingHints object to current object.
+ *
+ * @param hints the RenderingHints to be added.
+ */
+ public void add(RenderingHints hints) {
+ map.putAll(hints.map);
+ }
+
+ /**
+ * Puts the specified value to the specified key. Neither the key nor
+ * the value can be null.
+ *
+ * @param key the rendering hint key.
+ * @param value the rendering hint value.
+ *
+ * @return the previous rendering hint value assigned to the key or null.
+ *
+ */
+ public Object put(Object key, Object value) {
+ if (!((Key)key).isCompatibleValue(value)) {
+ throw new IllegalArgumentException();
+ }
+
+ return map.put(key, value);
+ }
+
+ /**
+ * Removes the specified key and corresponding value from
+ * the RenderingHints object.
+ *
+ * @param key the specified hint key to be removed.
+ *
+ * @return the object of previous rendering hint value which is
+ * assigned to the specified key, or null.
+ */
+ public Object remove(Object key) {
+ return map.remove(key);
+ }
+
+ /**
+ * Gets the value assigned to the specified key.
+ *
+ * @param key the rendering hint key.
+ *
+ * @return the object assigned to the specified key.
+ */
+ public Object get(Object key) {
+ return map.get(key);
+ }
+
+ /**
+ * Returns a set of rendering hints keys for current RenderingHints object.
+ *
+ * @return the set of rendering hints keys.
+ */
+ public Set<Object> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * Returns a set of Map.Entry objects which contain current RenderingHint
+ * key/value pairs.
+ *
+ * @return the a set of mapped RenderingHint key/value pairs.
+ */
+ public Set<Map.Entry<Object, Object>> entrySet() {
+ return map.entrySet();
+ }
+
+ /**
+ * Puts all of the preferences from the specified Map into
+ * the current RenderingHints object. These mappings replace
+ * all existing preferences.
+ *
+ * @param m the specified Map of preferences.
+ */
+ public void putAll(Map<?, ?> m) {
+ if (m instanceof RenderingHints) {
+ map.putAll(((RenderingHints) m).map);
+ } else {
+ Set<?> entries = m.entrySet();
+
+ if (entries != null){
+ Iterator<?> it = entries.iterator();
+ while (it.hasNext()) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
+ Key key = (Key) entry.getKey();
+ Object val = entry.getValue();
+ put(key, val);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a Collection of values contained in current RenderingHints object.
+ *
+ * @return the Collection of RenderingHints's values.
+ */
+ public Collection<Object> values() {
+ return map.values();
+ }
+
+ /**
+ * Checks whether or not current RenderingHints object contains at least one
+ * the value which is equal to the specified Object.
+ *
+ * @param value the specified Object.
+ *
+ * @return true, if the specified object is assigned to at least one
+ * RenderingHint's key, false otherwise.
+ */
+ public boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ /**
+ * Checks whether or not current RenderingHints object contains the key
+ * which is equal to the specified Object.
+ *
+ * @param key the specified Object.
+ *
+ * @return true, if the RenderingHints object contains the specified Object
+ * as a key, false otherwise.
+ *
+ */
+ public boolean containsKey(Object key) {
+ if (key == null) {
+ throw new NullPointerException();
+ }
+
+ return map.containsKey(key);
+ }
+
+ /**
+ * Checks whether or not the RenderingHints object contains any
+ * key/value pairs.
+ *
+ * @return true, if the RenderingHints object is empty, false otherwise.
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Clears the RenderingHints of all key/value pairs.
+ */
+ public void clear() {
+ map.clear();
+ }
+
+ /**
+ * Returns the number of key/value pairs in the RenderingHints.
+ *
+ * @return the number of key/value pairs.
+ */
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Compares the RenderingHints object with the specified object.
+ *
+ * @param o the specified Object to be compaired.
+ *
+ * @return true, if the Object is a Map whose key/value pairs
+ * match this RenderingHints' key/value pairs,
+ * false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Map)) {
+ return false;
+ }
+
+ Map<?, ?> m = (Map<?, ?>)o;
+ Set<?> keys = keySet();
+ if (!keys.equals(m.keySet())) {
+ return false;
+ }
+
+ Iterator<?> it = keys.iterator();
+ while (it.hasNext()) {
+ Key key = (Key)it.next();
+ Object v1 = get(key);
+ Object v2 = m.get(key);
+ if (!(v1==null?v2==null:v1.equals(v2))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the hash code for this RenderingHints object.
+ *
+ * @return the hash code for this RenderingHints object.
+ */
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ /**
+ * Returns the clone of the RenderingHints object with the same contents.
+ *
+ * @return the clone of the RenderingHints instance.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone() {
+ RenderingHints clone = new RenderingHints(null);
+ clone.map = (HashMap<Object, Object>)this.map.clone();
+ return clone;
+ }
+
+ /**
+ * Returns the string representation of the RenderingHints object.
+ *
+ * @return the String object which represents RenderingHints object.
+ */
+ @Override
+ public String toString() {
+ return "RenderingHints["+map.toString()+"]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * The RenderingHints.Key class is abstract and defines a base type for
+ * all RenderingHints keys.
+ */
+ public abstract static class Key {
+
+ /** The key. */
+ private final int key;
+
+ /**
+ * Instantiates a new key with unique int identifier.
+ * No two objects of the same subclass with the same integer key
+ * can be instantiated.
+ *
+ * @param key the unique key.
+ */
+ protected Key(int key) {
+ this.key = key;
+ }
+
+ /**
+ * Compares the Key object with the specified object.
+ *
+ * @param o the specified Object to be compaired.
+ *
+ * @return true, if the Key is equal to the specified object,
+ * false otherwise.
+ */
+ @Override
+ public final boolean equals(Object o) {
+ return this == o;
+ }
+
+ /**
+ * Returns the hash code for this Key object.
+ *
+ * @return the hash code for this Key object.
+ */
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ /**
+ * Returns int unique key with which this Key object has been
+ * instantiated.
+ *
+ * @return the int unique key with which this Key object has been
+ * instantiated.
+ */
+ protected final int intKey() {
+ return key;
+ }
+
+ /**
+ * Checks whether or not specified value is compatible with the Key.
+ *
+ * @param val the Object.
+ *
+ * @return true, if the specified value is compatible with the Key,
+ * false otherwise.
+ */
+ public abstract boolean isCompatibleValue(Object val);
+ }
+
+ /**
+ * Private implementation of Key class.
+ */
+ private static class KeyImpl extends Key {
+
+ /**
+ * Instantiates a new key impl.
+ *
+ * @param key the key
+ */
+ protected KeyImpl(int key) {
+ super(key);
+ }
+
+ @Override
+ public boolean isCompatibleValue(Object val) {
+ if (!(val instanceof KeyValue)) {
+ return false;
+ }
+
+ return ((KeyValue)val).key == this;
+ }
+ }
+
+ /**
+ * Private class KeyValue is used as value for Key class instance.
+ */
+ private static class KeyValue {
+
+ /** The key. */
+ private final Key key;
+
+ /**
+ * Instantiates a new key value.
+ *
+ * @param key the key
+ */
+ protected KeyValue(Key key) {
+ this.key = key;
+ }
+ }
+}
diff --git a/awt/java/awt/Shape.java b/awt/java/awt/Shape.java
new file mode 100644
index 0000000..3dbad25
--- /dev/null
+++ b/awt/java/awt/Shape.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The Shape interface defines a geometric shape defined by a boundary
+ * (outline) path. The path outline can be accessed through a
+ * PathIterator object. The Shape
+ * interface provides methods for obtaining the bounding box (which is
+ * the smallest rectangle containing the shape and for obtaining a PathIterator
+ * object for current Shape, as well as utility methods which
+ * determine if the Shape contains or intersects a Rectangle or contains a Point.
+ */
+public interface Shape {
+
+ /**
+ * Checks whether or not the point with specified coordinates lies inside
+ * the Shape.
+ *
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ *
+ * @return true, if the specified coordinates lie inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(double x, double y);
+
+ /**
+ * Checks whether or not the rectangle with specified
+ * [x, y, width, height] parameters lies inside the Shape.
+ *
+ * @param x the X double coordinate of the rectangle's upper left
+ * corner.
+ * @param y the Y double coordinate of the rectangle's upper left
+ * corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ *
+ * @return true, if the specified rectangle lies inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(double x, double y, double w, double h);
+
+ /**
+ * Checks whether or not the specified Point2D lies inside the Shape.
+ *
+ * @param point the Point2D object.
+ *
+ * @return true, if the specified Point2D lies inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(Point2D point);
+
+ /**
+ * Checks whether or not the specified rectangle lies inside the Shape.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return true, if the specified rectangle lies inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(Rectangle2D r);
+
+ /**
+ * Gets the bounding rectangle of the Shape. The bounding rectangle
+ * is the smallest rectangle which contains the Shape.
+ *
+ * @return the bounding rectangle of the Shape.
+ */
+ public Rectangle getBounds();
+
+ /**
+ * Gets the Rectangle2D which represents Shape bounds.
+ * The bounding rectangle is the smallest rectangle which contains
+ * the Shape.
+ *
+ * @return the bounding rectangle of the Shape.
+ */
+ public Rectangle2D getBounds2D();
+
+ /**
+ * Gets the PathIterator object of the Shape which provides
+ * access to the shape's boundary modified
+ * by the specified AffineTransform.
+ *
+ * @param at the specified AffineTransform object, or null.
+ *
+ * @return PathIterator object for the Shape.
+ */
+ public PathIterator getPathIterator(AffineTransform at);
+
+ /**
+ * Gets the PathIterator object of the Shape which provides
+ * access to the coordinates of the shapes boundary modified
+ * by the specified AffineTransform. The flatness parameter
+ * defines the amount of subdivision of the curved segments and
+ * specifies the maximum distance which every point on the
+ * unflattened transformed curve can deviate from the returned
+ * flattened path segments.
+ *
+ * @param at the specified AffineTransform object, or null.
+ * @param flatness the maximum number of the control points for
+ * a given curve which varies from colinear before a subdivided
+ * curve is replaced by a straight line connecting the endpoints.
+ *
+ * @return PathIterator object for the Shape.
+ */
+ public PathIterator getPathIterator(AffineTransform at, double flatness);
+
+ /**
+ * Checks whether or not the interior of rectangular specified by
+ * [x, y, width, height] parameters intersects the interior of
+ * the Shape.
+ *
+ * @param x the X double coordinate of the rectangle's upper left
+ * corner.
+ * @param y the Y double coordinate of the rectangle's upper left
+ * corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ *
+ * @return true, if the rectangle specified by
+ * [x, y, width, height] parameters intersects the interior of
+ * the Shape, otherwise false.
+ *
+ */
+ public boolean intersects(double x, double y, double w, double h);
+
+ /**
+ * Checks whether or not the interior of rectangl specified by
+ * Rectangle2D object intersects the interior of the Shape.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return true, if the Rectangle2D intersects the interior of
+ * the Shape, otherwise false.
+ */
+ public boolean intersects(Rectangle2D r);
+}
diff --git a/awt/java/awt/Stroke.java b/awt/java/awt/Stroke.java
new file mode 100644
index 0000000..e6d683d
--- /dev/null
+++ b/awt/java/awt/Stroke.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The Stroke interface gives a pen style to be used by the
+ * Graphics2D interface. It provides a means for getting a stroked version
+ * of a shape, which is the version that is suitable for drawing via
+ * the Graphics2D interface. Stroking a shape gives the shape's outline
+ * a width or drawing style.
+ * <p>
+ * The Draw methods from Graphics2D interface should use the Stroke object for
+ * rendering the shape's outline. The stroke should be set by
+ * setStroke(java.awt.Stroke) method of the Graphics2D interface.
+ * @see java.awt.Graphics2D#setStroke(java.awt.Stroke)
+ */
+public interface Stroke {
+
+ /**
+ * Creates the stroked shape, which is the version that is suitable for drawing via
+ * the Graphics2D interface. Stroking a shape gives the shape's outline
+ * a width or drawing style.
+ *
+ * @param p the original shape.
+ *
+ * @return the stroked shape.
+ */
+ public Shape createStrokedShape(Shape p);
+}
diff --git a/awt/java/awt/Toolkit.java b/awt/java/awt/Toolkit.java
new file mode 100644
index 0000000..0c066b2
--- /dev/null
+++ b/awt/java/awt/Toolkit.java
@@ -0,0 +1,1338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.event.AWTEventListener;
+import java.awt.event.AWTEventListenerProxy;
+import java.awt.event.InputEvent;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.FontPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.awt.ChoiceStyle;
+import org.apache.harmony.awt.ComponentInternals;
+import org.apache.harmony.awt.ContextStorage;
+import org.apache.harmony.awt.ReadOnlyIterator;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.CreationParams;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeCursor;
+
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.NativeEventThread;
+import org.apache.harmony.awt.wtk.ShutdownWatchdog;
+import org.apache.harmony.awt.wtk.Synchronizer;
+import org.apache.harmony.awt.wtk.WTK;
+
+/**
+ * The Toolkit class is the representation of the platform-specific
+ * Abstract Window Toolkit implementation. Toolkit's subclasses
+ * are used to bind the various components to particular native
+ * toolkit implementations.
+ */
+public abstract class Toolkit {
+
+ /** The Constant RECOURCE_PATH. */
+ private static final String RECOURCE_PATH = "org.apache.harmony.awt.resources.AWTProperties"; //$NON-NLS-1$
+
+ /** The Constant properties. */
+ private static final ResourceBundle properties = loadResources(RECOURCE_PATH);
+
+ /** The dispatcher. */
+ Dispatcher dispatcher;
+
+ /** The system event queue core. */
+ private EventQueueCore systemEventQueueCore;
+
+ /** The dispatch thread. */
+ EventDispatchThread dispatchThread;
+
+ /** The native thread. */
+ NativeEventThread nativeThread;
+
+ /** The awt events manager. */
+ protected AWTEventsManager awtEventsManager;
+
+ /**
+ * The Class AWTTreeLock.
+ */
+ private class AWTTreeLock {
+ }
+
+ /** The awt tree lock. */
+ final Object awtTreeLock = new AWTTreeLock();
+
+ /** The synchronizer. */
+ private final Synchronizer synchronizer = ContextStorage.getSynchronizer();
+
+ /** The shutdown watchdog. */
+ final ShutdownWatchdog shutdownWatchdog = new ShutdownWatchdog();
+
+ /** The auto number. */
+ final AutoNumber autoNumber = new AutoNumber();
+
+ /** The event type lookup. */
+ final AWTEvent.EventTypeLookup eventTypeLookup = new AWTEvent.EventTypeLookup();
+
+ /** The b dynamic layout set. */
+ private boolean bDynamicLayoutSet = true;
+
+ /** The set of desktop properties that user set directly. */
+ private final HashSet<String> userPropSet = new HashSet<String>();
+
+ /** The desktop properties. */
+ protected Map<String, Object> desktopProperties;
+
+ /** The desktop props support. */
+ protected PropertyChangeSupport desktopPropsSupport;
+
+ /**
+ * For this component the native window is being created
+ * It is used in the callback-driven window creation
+ * (e.g. on Windows in the handler of WM_CREATE event)
+ * to establish the connection between this component
+ * and its native window.
+ */
+ private Object recentNativeWindowComponent;
+
+ /** The wtk. */
+ private WTK wtk;
+
+ /**
+ * The Class ComponentInternalsImpl.
+ */
+ protected final class ComponentInternalsImpl extends ComponentInternals {
+
+ /**
+ * Shutdown.
+ */
+ @Override
+ public void shutdown() {
+ dispatchThread.shutdown();
+ }
+
+ /**
+ * Sets the desktop property to the specified value and fires a property
+ * change event.
+ *
+ * @param name the name of property.
+ * @param value the new value of property.
+ */
+ @Override
+ public void setDesktopProperty(String name, Object value) {
+ Toolkit.this.setDesktopProperty(name, value);
+ }
+ }
+
+
+ /**
+ * A lot of methods must throw HeadlessException
+ * if <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
+ *
+ * @throws HeadlessException the headless exception
+ */
+ static void checkHeadless() throws HeadlessException {
+ if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance())
+ throw new HeadlessException();
+ }
+
+ /**
+ * Lock awt.
+ */
+ final void lockAWT() {
+ synchronizer.lock();
+ }
+
+ /**
+ * Static lock awt.
+ */
+ static final void staticLockAWT() {
+ ContextStorage.getSynchronizer().lock();
+ }
+
+ /**
+ * Unlock awt.
+ */
+ final void unlockAWT() {
+ synchronizer.unlock();
+ }
+
+ /**
+ * Static unlock awt.
+ */
+ static final void staticUnlockAWT() {
+ ContextStorage.getSynchronizer().unlock();
+ }
+
+ /**
+ * InvokeAndWait under AWT lock. W/o this method system can hang up.
+ * Added to support modality (Dialog.show() & PopupMenu.show()) from
+ * not event dispatch thread. Use in other cases is not recommended.
+ *
+ * Still can be called only for whole API methods that
+ * cannot be called from other classes API methods.
+ * Examples:
+ * show() for modal dialogs - correct, only user can call it,
+ * directly or through setVisible(true)
+ * setBounds() for components - incorrect, setBounds()
+ * can be called from layoutContainer()
+ * for layout managers
+ *
+ * @param runnable the runnable
+ *
+ * @throws InterruptedException the interrupted exception
+ * @throws InvocationTargetException the invocation target exception
+ */
+ final void unsafeInvokeAndWait(Runnable runnable) throws InterruptedException,
+ InvocationTargetException {
+ synchronizer.storeStateAndFree();
+ try {
+ EventQueue.invokeAndWait(runnable);
+ } finally {
+ synchronizer.lockAndRestoreState();
+ }
+ }
+
+ /**
+ * Gets the synchronizer.
+ *
+ * @return the synchronizer
+ */
+ final Synchronizer getSynchronizer() {
+ return synchronizer;
+ }
+
+ /**
+ * Gets the wTK.
+ *
+ * @return the wTK
+ */
+ final WTK getWTK() {
+ return wtk;
+ }
+
+ /**
+ * Gets the property with the specified key and default value.
+ * This method returns the defValue if the property is not found.
+ *
+ * @param propName the name of property.
+ * @param defVal the default value.
+ *
+ * @return the property value.
+ */
+ public static String getProperty(String propName, String defVal) {
+ if (propName == null) {
+ // awt.7D=Property name is null
+ throw new NullPointerException(Messages.getString("awt.7D")); //$NON-NLS-1$
+ }
+ staticLockAWT();
+ try {
+ String retVal = null;
+ if (properties != null) {
+ try {
+ retVal = properties.getString(propName);
+ } catch (MissingResourceException e) {
+ } catch (ClassCastException e) {
+ }
+ }
+ return (retVal == null) ? defVal : retVal;
+ } finally {
+ staticUnlockAWT();
+ }
+ }
+
+ /**
+ * Gets the default Toolkit.
+ *
+ * @return the default Toolkit
+ */
+ public static Toolkit getDefaultToolkit() {
+ synchronized (ContextStorage.getContextLock()) {
+ if (ContextStorage.shutdownPending()) {
+ return null;
+ }
+ Toolkit defToolkit = ContextStorage.getDefaultToolkit();
+ if (defToolkit != null) {
+ return defToolkit;
+ }
+ staticLockAWT();
+ try {
+ defToolkit = GraphicsEnvironment.isHeadless() ?
+ new HeadlessToolkit() : new ToolkitImpl();
+ ContextStorage.setDefaultToolkit(defToolkit);
+ return defToolkit;
+ } finally {
+ staticUnlockAWT();
+ }
+ //TODO: read system property named awt.toolkit
+ //and create an instance of the specified class,
+ //by default use ToolkitImpl
+ }
+ }
+
+ /**
+ * Gets the default Font.
+ *
+ * @return the derault Font for Toolkit.
+ */
+ Font getDefaultFont() {
+ return wtk.getSystemProperties().getDefaultFont();
+ }
+
+ /**
+ * Load resources.
+ *
+ * @param path the path
+ *
+ * @return the resource bundle
+ */
+ private static ResourceBundle loadResources(String path) {
+ try {
+ return ResourceBundle.getBundle(path);
+ } catch (MissingResourceException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the wTK class name.
+ *
+ * @return the wTK class name
+ */
+ private static String getWTKClassName() {
+ return "com.android.internal.awt.AndroidWTK";
+ }
+
+ /**
+ * Gets the component by id.
+ *
+ * @param id the id
+ *
+ * @return the component by id
+ */
+ Component getComponentById(long id) {
+ if (id == 0) {
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the GraphicsFactory.
+ *
+ * @return the GraphicsFactory object.
+ */
+ public GraphicsFactory getGraphicsFactory() {
+ return wtk.getGraphicsFactory();
+ }
+
+ /**
+ * Instantiates a new toolkit.
+ */
+ public Toolkit() {
+ init();
+ }
+
+ /**
+ * Inits AWT.
+ */
+ protected void init() {
+ lockAWT();
+ try {
+ ComponentInternals.setComponentInternals(new ComponentInternalsImpl());
+ new EventQueue(this); // create the system EventQueue
+ dispatcher = new Dispatcher(this);
+ final String className = getWTKClassName();
+ desktopProperties = new HashMap<String, Object>();
+ desktopPropsSupport = new PropertyChangeSupport(this);
+ awtEventsManager = new AWTEventsManager();
+ dispatchThread = new EventDispatchThread(this, dispatcher);
+ nativeThread = new NativeEventThread();
+ NativeEventThread.Init init = new NativeEventThread.Init() {
+ public WTK init() {
+ wtk = createWTK(className);
+ wtk.getNativeEventQueue().setShutdownWatchdog(shutdownWatchdog);
+ synchronizer.setEnvironment(wtk, dispatchThread);
+ ContextStorage.setWTK(wtk);
+ return wtk;
+ }
+ };
+ nativeThread.start(init);
+ dispatchThread.start();
+ wtk.getNativeEventQueue().awake();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Synchronizes this toolkit's graphics.
+ */
+ public abstract void sync();
+
+ /**
+ * Returns the construction status of a specified image that is being created.
+ *
+ * @param a0 the image to be checked.
+ * @param a1 the width of scaled image for which the status is being checked, or -1.
+ * @param a2 the height of scaled image for which the status is being checked, or -1.
+ * @param a3 the ImageObserver object to be notified while
+ * the image is being prepared.
+ *
+ * @return the ImageObserver flags which give the current state of the image data.
+ */
+ public abstract int checkImage(Image a0, int a1, int a2, ImageObserver a3);
+
+ /**
+ * Creates the image with the specified ImageProducer.
+ *
+ * @param a0 the ImageProducer to be used for image creation.
+ *
+ * @return the image with the specified ImageProducer.
+ */
+ public abstract Image createImage(ImageProducer a0);
+
+ /**
+ * Creates the image from the specified byte array, offset and length.
+ * The byte array should contain data with image format supported by
+ * Toolkit such as JPEG, GIF, or PNG.
+ *
+ * @param a0 the byte array with the image data.
+ * @param a1 the offset of the beggining the image data in the byte array.
+ * @param a2 the length of the image data in the byte array.
+ *
+ * @return the created Image.
+ */
+ public abstract Image createImage(byte[] a0, int a1, int a2);
+
+ /**
+ * Creates the image using image data from the specified URL.
+ *
+ * @param a0 the URL for extracting image data.
+ *
+ * @return the Image.
+ */
+ public abstract Image createImage(URL a0);
+
+ /**
+ * Creates the image using image data from the specified file.
+ *
+ * @param a0 the file name which contains image data of supported format.
+ *
+ * @return the Image.
+ */
+ public abstract Image createImage(String a0);
+
+ /**
+ * Gets the color model.
+ *
+ * @return the ColorModel of Toolkit's screen.
+ *
+ * @throws HeadlessException if the
+ * GraphicsEnvironment.isHeadless() method returns true.
+ */
+ public abstract ColorModel getColorModel() throws HeadlessException;
+
+ /**
+ * Gets the screen device metrics for the specified font.
+ *
+ * @param font the Font.
+ *
+ * @return the FontMetrics for the specified Font.
+ *
+ * @deprecated Use getLineMetrics method from Font class.
+ */
+
+ @Deprecated
+ public abstract FontMetrics getFontMetrics(Font font);
+
+ /**
+ * Prepares the specified image for rendering on the screen with the
+ * specified size.
+ *
+ * @param a0 the Image to be prepared.
+ * @param a1 the width of the screen representation or -1 for the current screen.
+ * @param a2 the height of the screen representation or -1 for the current screen.
+ * @param a3 the ImageObserver object to be notified as soon as
+ * the image is prepared.
+ *
+ * @return true, if image is fully prepared; false otherwise.
+ */
+ public abstract boolean prepareImage(Image a0, int a1, int a2, ImageObserver a3);
+
+ /**
+ * Creates an audio beep.
+ */
+ public abstract void beep();
+
+ /**
+ * Returns the array of font names which are available in this Toolkit.
+ *
+ * @return the array of font names which are available in this Toolkit.
+ *
+ * @deprecated use GraphicsEnvironment.getAvailableFontFamilyNames() method.
+ */
+ @Deprecated
+ public abstract String[] getFontList();
+
+ /**
+ * Gets the the Font implementation using the specified peer
+ * interface.
+ *
+ * @param a0 the Font name to be implemented.
+ * @param a1 the the font style: PLAIN, BOLD, ITALIC.
+ *
+ * @return the FontPeer implementation of the specified Font.
+ *
+ * @deprecated use java.awt.GraphicsEnvironment.getAllFonts method.
+ */
+
+ @Deprecated
+ protected abstract FontPeer getFontPeer(String a0, int a1);
+
+ /**
+ * Gets the image from the specified file which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG); this method
+ * should return the same Image for multiple calls of this method with
+ * the same image file name.
+ *
+ * @param a0 the file name which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG).
+ *
+ * @return the Image.
+ */
+ public abstract Image getImage(String a0);
+
+ /**
+ * Gets the image from the specified URL which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG); this method
+ * should return the same Image for multiple calls of this method with
+ * the same image URL.
+ *
+ * @param a0 the URL which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG).
+ *
+ * @return the Image.
+ */
+ public abstract Image getImage(URL a0);
+
+ /**
+ * Gets the screen resolution.
+ *
+ * @return the screen resolution.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public abstract int getScreenResolution() throws HeadlessException;
+
+ /**
+ * Gets the screen size.
+ *
+ * @return a Dimension object containing the width and height of
+ * the screen.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public abstract Dimension getScreenSize() throws HeadlessException;
+
+ /**
+ * Gets the EventQueue instance without checking access.
+ *
+ * @return the system EventQueue.
+ */
+ protected abstract EventQueue getSystemEventQueueImpl();
+
+ /**
+ * Returns a map of text attributes for the abstract level description
+ * of the specified input method highlight, or null if no mapping is found.
+ *
+ * @param highlight the InputMethodHighlight.
+ *
+ * @return the Map<java.awt.font. text attribute,?>
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public abstract Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+ InputMethodHighlight highlight) throws HeadlessException;
+
+ /**
+ * Map input method highlight impl.
+ *
+ * @param highlight the highlight
+ *
+ * @return the map<java.awt.font. text attribute,?>
+ *
+ * @throws HeadlessException the headless exception
+ */
+ Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(
+ InputMethodHighlight highlight) throws HeadlessException {
+ HashMap<java.awt.font.TextAttribute, ?> map = new HashMap<java.awt.font.TextAttribute, Object>();
+ wtk.getSystemProperties().mapInputMethodHighlight(highlight, map);
+ return Collections.<java.awt.font.TextAttribute, Object> unmodifiableMap(map);
+ }
+
+ /**
+ * Adds the specified PropertyChangeListener listener for the specified
+ * property.
+ *
+ * @param propName the property name for which the specified PropertyChangeListener
+ * will be added.
+ * @param l the PropertyChangeListener object.
+ */
+ public void addPropertyChangeListener(String propName, PropertyChangeListener l) {
+ lockAWT();
+ try {
+ if (desktopProperties.isEmpty()) {
+ initializeDesktopProperties();
+ }
+ } finally {
+ unlockAWT();
+ }
+ if (l != null) { // there is no guarantee that null listener will not be added
+ desktopPropsSupport.addPropertyChangeListener(propName, l);
+ }
+ }
+
+ /**
+ * Returns an array of the property change listeners registered with
+ * this Toolkit.
+ *
+ * @return an array of the property change listeners registered with
+ * this Toolkit.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners() {
+ return desktopPropsSupport.getPropertyChangeListeners();
+ }
+
+ /**
+ * Returns an array of the property change listeners registered with
+ * this Toolkit for notification regarding the specified property.
+ *
+ * @param propName the property name for which the PropertyChangeListener
+ * was registered.
+ *
+ * @return the array of PropertyChangeListeners registered for the specified
+ * property name.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners(String propName) {
+ return desktopPropsSupport.getPropertyChangeListeners(propName);
+ }
+
+ /**
+ * Removes the specified property change listener registered for the
+ * specified property name.
+ *
+ * @param propName the property name.
+ * @param l the PropertyChangeListener registered for the specified property name.
+ */
+ public void removePropertyChangeListener(String propName, PropertyChangeListener l) {
+ desktopPropsSupport.removePropertyChangeListener(propName, l);
+ }
+
+ /**
+ * Creates a custom cursor with the specified Image, hot spot, and cursor
+ * description.
+ *
+ * @param img the image of activated cursor.
+ * @param hotSpot the Point giving the coordinates of the cursor's hot spot.
+ * @param name the cursor description.
+ *
+ * @return the cursor with the specified Image, hot spot, and cursor
+ * description.
+ *
+ * @throws IndexOutOfBoundsException if the hot spot values are outside
+ * the bounds of the cursor.
+ * @throws HeadlessException if isHeadless() method of GraphicsEnvironment
+ * class returns true.
+ */
+ public Cursor createCustomCursor(Image img, Point hotSpot, String name)
+ throws IndexOutOfBoundsException, HeadlessException {
+ lockAWT();
+ try {
+ int w = img.getWidth(null), x = hotSpot.x;
+ int h = img.getHeight(null), y = hotSpot.y;
+ if (x < 0 || x >= w || y < 0 || y >= h) {
+ // awt.7E=invalid hotSpot
+ throw new IndexOutOfBoundsException(Messages.getString("awt.7E")); //$NON-NLS-1$
+ }
+ return new Cursor(name, img, hotSpot);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the supported cursor dimension which is closest to the
+ * specified width and height. If the Toolkit only supports a single
+ * cursor size, this method should return the supported cursor size.
+ * If custom cursor is not supported, a dimension of 0, 0 should be
+ * returned.
+ *
+ * @param prefWidth the preffered cursor width.
+ * @param prefHeight the preffered cursor height.
+ *
+ * @return the supported cursor dimension which is closest to the
+ * specified width and height.
+ *
+ * @throws HeadlessException if GraphicsEnvironment.isHeadless()
+ * returns true.
+ */
+ public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException {
+ lockAWT();
+ try {
+ return wtk.getCursorFactory().getBestCursorSize(prefWidth, prefHeight);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the value for the specified desktop property.
+ *
+ * @param propName the property name.
+ *
+ * @return the Object that is the property's value.
+ */
+ public final Object getDesktopProperty(String propName) {
+ lockAWT();
+ try {
+ if (desktopProperties.isEmpty()) {
+ initializeDesktopProperties();
+ }
+ if (propName.equals("awt.dynamicLayoutSupported")) { //$NON-NLS-1$
+ // dynamicLayoutSupported is special case
+ return Boolean.valueOf(isDynamicLayoutActive());
+ }
+ Object val = desktopProperties.get(propName);
+ if (val == null) {
+ // try to lazily load prop value
+ // just for compatibility, our lazilyLoad is empty
+ val = lazilyLoadDesktopProperty(propName);
+ }
+ return val;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the locking key state for the specified key.
+ *
+ * @param a0 the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK,
+ * or VK_KANA_LOCK.
+ *
+ * @return true if the specified key code is in the locked state,
+ * false otherwise.
+ *
+ * @throws UnsupportedOperationException if the state of this key
+ * can't be retrieved, or if the keyboard doesn't have this key.
+ * @throws NotImplementedException if this method is not implemented.
+ */
+ public boolean getLockingKeyState(int a0) throws UnsupportedOperationException, org.apache.harmony.luni.util.NotImplementedException {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+ }
+ return true;
+ }
+
+ /**
+ * Returns the maximum number of colors which the Toolkit supports for
+ * custom cursor.
+ *
+ * @return the maximum cursor colors.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public int getMaximumCursorColors() throws HeadlessException {
+ lockAWT();
+ try {
+ return wtk.getCursorFactory().getMaximumCursorColors();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the menu shortcut key mask.
+ *
+ * @return the menu shortcut key mask.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public int getMenuShortcutKeyMask() throws HeadlessException {
+ lockAWT();
+ try {
+ return InputEvent.CTRL_MASK;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the screen insets.
+ *
+ * @param gc the GraphicsConfiguration.
+ *
+ * @return the insets of this toolkit.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException {
+ if (gc == null) {
+ throw new NullPointerException();
+ }
+ lockAWT();
+ try {
+ return new Insets(0, 0, 0, 0); //TODO: get real screen insets
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the system EventQueue instance.
+ * If the default implementation of checkAwtEventQueueAccess is used,
+ * then this results of a call to the security manager's checkPermission
+ * method with an AWTPermission("accessEventQueue") permission.
+ *
+ * @return the system EventQueue instance.
+ */
+ public final EventQueue getSystemEventQueue() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkAwtEventQueueAccess();
+ }
+ return getSystemEventQueueImpl();
+ }
+
+ /**
+ * Gets the system event queue core.
+ *
+ * @return the system event queue core
+ */
+ EventQueueCore getSystemEventQueueCore() {
+ return systemEventQueueCore;
+ }
+
+ /**
+ * Sets the system event queue core.
+ *
+ * @param core the new system event queue core
+ */
+ void setSystemEventQueueCore(EventQueueCore core) {
+ systemEventQueueCore = core;
+ }
+
+ /**
+ * Initialize the desktop properties.
+ */
+ protected void initializeDesktopProperties() {
+ lockAWT();
+ try {
+ wtk.getSystemProperties().init(desktopProperties);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if dynamic layout of Containers is active or not.
+ *
+ * @return true, if is dynamic layout of Containers is active,
+ * false otherwise.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public boolean isDynamicLayoutActive() throws HeadlessException {
+ lockAWT();
+ try {
+ // always return true
+ return true;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+
+ /**
+ * Returns if the layout of Containers is checked dynamically during resizing,
+ * or statically after resizing is completed.
+ *
+ * @return true, if if the layout of Containers is checked dynamically during
+ * resizing; false, if the layout of Containers is checked statically after
+ * resizing is completed.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ protected boolean isDynamicLayoutSet() throws HeadlessException {
+ lockAWT();
+ try {
+ return bDynamicLayoutSet;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if the specified frame state is supported by Toolkit or not.
+ *
+ * @param state the frame state.
+ *
+ * @return true, if frame state is supported; false othrwise.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public boolean isFrameStateSupported(int state) throws HeadlessException {
+ lockAWT();
+ try {
+ return wtk.getWindowFactory().isWindowStateSupported(state);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Loads the value of the desktop property with the specified property name.
+ *
+ * @param propName the property name.
+ *
+ * @return the desktop property values.
+ */
+ protected Object lazilyLoadDesktopProperty(String propName) {
+ return null;
+ }
+
+ /**
+ * Loads the current system color values to the specified array.
+ *
+ * @param colors the array where the current system color values
+ * are written by this method.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ protected void loadSystemColors(int[] colors) throws HeadlessException {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the value of the desktop property with the specified name.
+ *
+ * @param propName the property's name.
+ * @param value the property's value.
+ */
+ protected final void setDesktopProperty(String propName, Object value) {
+ Object oldVal;
+ lockAWT();
+ try {
+ oldVal = getDesktopProperty(propName);
+ userPropSet.add(propName);
+ desktopProperties.put(propName, value);
+ } finally {
+ unlockAWT();
+ }
+ desktopPropsSupport.firePropertyChange(propName, oldVal, value);
+ }
+
+ /**
+ * Sets the layout state, whether the Container layout is checked
+ * dynamically during resizing, or statically after resizing is completed.
+ *
+ * @param dynamic the new dynamic layout state - if true the layout of
+ * Containers is checked dynamically during resizing, if false -
+ * statically after resizing is completed.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public void setDynamicLayout(boolean dynamic) throws HeadlessException {
+ lockAWT();
+ try {
+ bDynamicLayoutSet = dynamic;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the locking key state for the specified key code.
+ *
+ * @param a0 the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK,
+ * or VK_KANA_LOCK.
+ * @param a1 the state - true to set the specified key code to the locked state,
+ * false - to unlock it.
+ *
+ * @throws UnsupportedOperationException if the state of this key
+ * can't be set, or if the keyboard doesn't have this key.
+ * @throws NotImplementedException if this method is not implemented.
+ */
+ public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException, org.apache.harmony.luni.util.NotImplementedException {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+ }
+ return;
+ }
+
+
+ /**
+ * On queue empty.
+ */
+ void onQueueEmpty() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ /**
+ * Creates the wtk.
+ *
+ * @param clsName the cls name
+ *
+ * @return the wTK
+ */
+ private WTK createWTK(String clsName) {
+ WTK newWTK = null;
+ try {
+ newWTK = (WTK) Class.forName(clsName).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return newWTK;
+ }
+
+ /**
+ * Connect the component to its native window
+ * @param winId - id of native window just created
+ */
+ boolean onWindowCreated(long winId) {
+ return false;
+ }
+
+ /**
+ * Gets the native event queue.
+ *
+ * @return the native event queue
+ */
+ NativeEventQueue getNativeEventQueue() {
+ return wtk.getNativeEventQueue();
+ }
+
+ /**
+ * Returns a shared instance of implementation of org.apache.harmony.awt.wtk.NativeCursor
+ * for current platform for
+ *
+ * @param type - Java Cursor type
+ *
+ * @return new instance of implementation of NativeCursor
+ */
+ NativeCursor createNativeCursor(int type) {
+ return wtk.getCursorFactory().getCursor(type);
+ }
+
+ /**
+ * Returns a shared instance of implementation of org.apache.harmony.awt.wtk.NativeCursor
+ * for current platform for custom cursor
+ *
+ * @param img the img
+ * @param hotSpot the hot spot
+ * @param name the name
+ *
+ * @return new instance of implementation of NativeCursor
+ */
+ NativeCursor createCustomNativeCursor(Image img, Point hotSpot, String name) {
+ return wtk.getCursorFactory().createCustomCursor(img, hotSpot.x, hotSpot.y);
+ }
+
+ /**
+ * Adds an AWTEventListener to the Toolkit to listen for events
+ * of types corresponding to bits in the specified event mask.
+ * Event masks are defined in AWTEvent class.
+ *
+ * @param listener the AWTEventListener.
+ * @param eventMask he bitmask of event types.
+ */
+ public void addAWTEventListener(AWTEventListener listener, long eventMask) {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ awtEventsManager.addAWTEventListener(listener, eventMask);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Removes the specified awt event listener.
+ *
+ * @param listener the AWTEventListener to be removed.
+ */
+ public void removeAWTEventListener(AWTEventListener listener) {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ awtEventsManager.removeAWTEventListener(listener);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the array of all AWT event listeners registered with this Toolkit.
+ *
+ * @return the array of all AWT event listeners registered with this Toolkit.
+ */
+ public AWTEventListener[] getAWTEventListeners() {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ return awtEventsManager.getAWTEventListeners();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the array of the AWT event listeners registered with this Toolkit
+ * for the event types corresponding to the specified event mask.
+ *
+ * @param eventMask the bit mask of event type.
+ *
+ * @return the array of the AWT event listeners registered in this Toolkit
+ * for the event types corresponding to the specified event mask.
+ */
+ public AWTEventListener[] getAWTEventListeners(long eventMask) {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ return awtEventsManager.getAWTEventListeners(eventMask);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Dispatch awt event.
+ *
+ * @param event the event
+ */
+ void dispatchAWTEvent(AWTEvent event) {
+ awtEventsManager.dispatchAWTEvent(event);
+ }
+
+ /**
+ * The Class AWTEventsManager.
+ */
+ final class AWTEventsManager {
+
+ /** The permission. */
+ AWTPermission permission = new AWTPermission("listenToAllAWTEvents"); //$NON-NLS-1$
+
+ /** The listeners. */
+ private final AWTListenerList<AWTEventListenerProxy> listeners = new AWTListenerList<AWTEventListenerProxy>();
+
+ /**
+ * Adds the awt event listener.
+ *
+ * @param listener the listener
+ * @param eventMask the event mask
+ */
+ void addAWTEventListener(AWTEventListener listener, long eventMask) {
+ if (listener != null) {
+ listeners.addUserListener(new AWTEventListenerProxy(eventMask, listener));
+ }
+ }
+
+ /**
+ * Removes the awt event listener.
+ *
+ * @param listener the listener
+ */
+ void removeAWTEventListener(AWTEventListener listener) {
+ if (listener != null) {
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ if (listener == proxy.getListener()) {
+ listeners.removeUserListener(proxy);
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the aWT event listeners.
+ *
+ * @return the aWT event listeners
+ */
+ AWTEventListener[] getAWTEventListeners() {
+ HashSet<EventListener> listenersSet = new HashSet<EventListener>();
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ listenersSet.add(proxy.getListener());
+ }
+ return listenersSet.toArray(new AWTEventListener[listenersSet.size()]);
+ }
+
+ /**
+ * Gets the aWT event listeners.
+ *
+ * @param eventMask the event mask
+ *
+ * @return the aWT event listeners
+ */
+ AWTEventListener[] getAWTEventListeners(long eventMask) {
+ HashSet<EventListener> listenersSet = new HashSet<EventListener>();
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ if ((proxy.getEventMask() & eventMask) == eventMask) {
+ listenersSet.add(proxy.getListener());
+ }
+ }
+ return listenersSet.toArray(new AWTEventListener[listenersSet.size()]);
+ }
+
+ /**
+ * Dispatch awt event.
+ *
+ * @param event the event
+ */
+ void dispatchAWTEvent(AWTEvent event) {
+ AWTEvent.EventDescriptor descriptor = eventTypeLookup.getEventDescriptor(event);
+ if (descriptor == null) {
+ return;
+ }
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ if ((proxy.getEventMask() & descriptor.eventMask) != 0) {
+ proxy.eventDispatched(event);
+ }
+ }
+ }
+ }
+
+ /**
+ * The Class AutoNumber.
+ */
+ static final class AutoNumber {
+
+ /** The next component. */
+ int nextComponent = 0;
+
+ /** The next canvas. */
+ int nextCanvas = 0;
+
+ /** The next panel. */
+ int nextPanel = 0;
+
+ /** The next window. */
+ int nextWindow = 0;
+
+ /** The next frame. */
+ int nextFrame = 0;
+
+ /** The next dialog. */
+ int nextDialog = 0;
+
+ /** The next button. */
+ int nextButton = 0;
+
+ /** The next menu component. */
+ int nextMenuComponent = 0;
+
+ /** The next label. */
+ int nextLabel = 0;
+
+ /** The next check box. */
+ int nextCheckBox = 0;
+
+ /** The next scrollbar. */
+ int nextScrollbar = 0;
+
+ /** The next scroll pane. */
+ int nextScrollPane = 0;
+
+ /** The next list. */
+ int nextList = 0;
+
+ /** The next choice. */
+ int nextChoice = 0;
+
+ /** The next file dialog. */
+ int nextFileDialog = 0;
+
+ /** The next text area. */
+ int nextTextArea = 0;
+
+ /** The next text field. */
+ int nextTextField = 0;
+ }
+
+ private class Lock {
+ }
+
+ /** The lock. */
+ private final Object lock = new Lock();
+
+}
diff --git a/awt/java/awt/ToolkitImpl.java b/awt/java/awt/ToolkitImpl.java
new file mode 100644
index 0000000..5015aef
--- /dev/null
+++ b/awt/java/awt/ToolkitImpl.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.*;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.Map;
+import org.apache.harmony.awt.gl.image.*;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+class ToolkitImpl extends Toolkit {
+
+ static final Hashtable<Serializable, Image> imageCache = new Hashtable<Serializable, Image>();
+
+ @Override
+ public void sync() {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public int checkImage(Image image, int width, int height, ImageObserver observer) {
+ lockAWT();
+ try {
+ if (width == 0 || height == 0) {
+ return ImageObserver.ALLBITS;
+ }
+ if (!(image instanceof OffscreenImage)) {
+ return ImageObserver.ALLBITS;
+ }
+ OffscreenImage oi = (OffscreenImage) image;
+ return oi.checkImage(observer);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(ImageProducer producer) {
+ lockAWT();
+ try {
+ return new OffscreenImage(producer);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(byte[] imagedata, int imageoffset, int imagelength) {
+ lockAWT();
+ try {
+ return new OffscreenImage(new ByteArrayDecodingImageSource(imagedata, imageoffset,
+ imagelength));
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(URL url) {
+ lockAWT();
+ try {
+ return new OffscreenImage(new URLDecodingImageSource(url));
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(String filename) {
+ lockAWT();
+ try {
+ return new OffscreenImage(new FileDecodingImageSource(filename));
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ lockAWT();
+ try {
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
+ .getDefaultConfiguration().getColorModel();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ public FontMetrics getFontMetrics(Font font) {
+ lockAWT();
+ try {
+ GraphicsFactory gf = getGraphicsFactory();
+ return gf.getFontMetrics(font);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public boolean prepareImage(Image image, int width, int height, ImageObserver observer) {
+ lockAWT();
+ try {
+ if (width == 0 || height == 0) {
+ return true;
+ }
+ if (!(image instanceof OffscreenImage)) {
+ return true;
+ }
+ OffscreenImage oi = (OffscreenImage) image;
+ return oi.prepareImage(observer);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public void beep() {
+ lockAWT();
+ try {
+ // ???AWT: is there nothing to be implemented here?
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ public String[] getFontList() {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ return null;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ protected FontPeer getFontPeer(String a0, int a1) {
+ lockAWT();
+ try {
+ return null;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image getImage(String filename) {
+ return getImage(filename, this);
+ }
+
+ static Image getImage(String filename, Toolkit toolkit) {
+ synchronized (imageCache) {
+ Image im = (filename == null ? null : imageCache.get(filename));
+
+ if (im == null) {
+ try {
+ im = toolkit.createImage(filename);
+ imageCache.put(filename, im);
+ } catch (Exception e) {
+ }
+ }
+
+ return im;
+ }
+ }
+
+ @Override
+ public Image getImage(URL url) {
+ return getImage(url, this);
+ }
+
+ static Image getImage(URL url, Toolkit toolkit) {
+ synchronized (imageCache) {
+ Image im = imageCache.get(url);
+ if (im == null) {
+ try {
+ im = toolkit.createImage(url);
+ imageCache.put(url, im);
+ } catch (Exception e) {
+ }
+ }
+ return im;
+ }
+ }
+
+ @Override
+ public int getScreenResolution() throws HeadlessException {
+ lockAWT();
+ try {
+ return 62;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Dimension getScreenSize() {
+ lockAWT();
+ try {
+ DisplayMode dm = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDisplayMode();
+ return new Dimension(dm.getWidth(), dm.getHeight());
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+ InputMethodHighlight highlight) throws HeadlessException {
+ lockAWT();
+ try {
+ return mapInputMethodHighlightImpl(highlight);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ protected EventQueue getSystemEventQueueImpl() {
+ return getSystemEventQueueCore().getActiveEventQueue();
+ }
+}
diff --git a/awt/java/awt/Transparency.java b/awt/java/awt/Transparency.java
new file mode 100644
index 0000000..9793114
--- /dev/null
+++ b/awt/java/awt/Transparency.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The Transparency interface defines transparency's general modes.
+ */
+public interface Transparency {
+
+ /** The Constant OPAQUE represents completely opaque data,
+ * all pixels have an alpha value of 1.0.
+ */
+ public static final int OPAQUE = 1;
+
+ /** The Constant BITMASK represents data which can be either
+ * completely opaque, with an alpha value of 1.0, or completely
+ * transparent, with an alpha value of 0.0.
+ */
+ public static final int BITMASK = 2;
+
+ /** The Constant TRANSLUCENT represents data which alpha value
+ * can vary between and including 0.0 and 1.0. */
+ public static final int TRANSLUCENT = 3;
+
+ /**
+ * Gets the transparency mode.
+ *
+ * @return the transparency mode: OPAQUE, BITMASK or TRANSLUCENT.
+ */
+ public int getTransparency();
+
+}
+
diff --git a/awt/java/awt/color/CMMException.java b/awt/java/awt/color/CMMException.java
new file mode 100644
index 0000000..16fe76e
--- /dev/null
+++ b/awt/java/awt/color/CMMException.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The CMMException is thrown as soon as a native CMM error
+ * occures.
+ */
+public class CMMException extends java.lang.RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 5775558044142994965L;
+
+ /**
+ * Instantiates a new CMM exception with detail message.
+ *
+ * @param s the String - detail message.
+ */
+ public CMMException (String s) {
+ super (s);
+ }
+}
diff --git a/awt/java/awt/color/ColorSpace.java b/awt/java/awt/color/ColorSpace.java
new file mode 100644
index 0000000..f961514
--- /dev/null
+++ b/awt/java/awt/color/ColorSpace.java
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import java.io.Serializable;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ColorSpace class defines a color space type for a Color and provides methods
+ * for arrays of color component operations.
+ */
+public abstract class ColorSpace implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -409452704308689724L;
+
+ /** The Constant TYPE_XYZ indicates XYZ color space type. */
+ public static final int TYPE_XYZ = 0;
+
+ /** The Constant TYPE_Lab indicates Lab color space type. */
+ public static final int TYPE_Lab = 1;
+
+ /** The Constant TYPE_Luv indicates Luv color space type. */
+ public static final int TYPE_Luv = 2;
+
+ /** The Constant TYPE_YCbCr indicates YCbCr color space type. */
+ public static final int TYPE_YCbCr = 3;
+
+ /** The Constant TYPE_Yxy indicates Yxy color space type. */
+ public static final int TYPE_Yxy = 4;
+
+ /** The Constant TYPE_RGB indicates RGB color space type. */
+ public static final int TYPE_RGB = 5;
+
+ /** The Constant TYPE_GRAY indicates Gray color space type. */
+ public static final int TYPE_GRAY = 6;
+
+ /** The Constant TYPE_HSV indicates HSV color space type. */
+ public static final int TYPE_HSV = 7;
+
+ /** The Constant TYPE_HLS indicates HLS color space type. */
+ public static final int TYPE_HLS = 8;
+
+ /** The Constant TYPE_CMYK indicates CMYK color space type. */
+ public static final int TYPE_CMYK = 9;
+
+ /** The Constant TYPE_CMY indicates CMY color space type. */
+ public static final int TYPE_CMY = 11;
+
+ /** The Constant TYPE_2CLR indicates color spaces with 2 components. */
+ public static final int TYPE_2CLR = 12;
+
+ /** The Constant TYPE_3CLR indicates color spaces with 3 components. */
+ public static final int TYPE_3CLR = 13;
+
+ /** The Constant TYPE_4CLR indicates color spaces with 4 components. */
+ public static final int TYPE_4CLR = 14;
+
+ /** The Constant TYPE_5CLR indicates color spaces with 5 components. */
+ public static final int TYPE_5CLR = 15;
+
+ /** The Constant TYPE_6CLR indicates color spaces with 6 components. */
+ public static final int TYPE_6CLR = 16;
+
+ /** The Constant TYPE_7CLR indicates color spaces with 7 components. */
+ public static final int TYPE_7CLR = 17;
+
+ /** The Constant TYPE_8CLR indicates color spaces with 8 components. */
+ public static final int TYPE_8CLR = 18;
+
+ /** The Constant TYPE_9CLR indicates color spaces with 9 components. */
+ public static final int TYPE_9CLR = 19;
+
+ /** The Constant TYPE_ACLR indicates color spaces with 10 components. */
+ public static final int TYPE_ACLR = 20;
+
+ /** The Constant TYPE_BCLR indicates color spaces with 11 components. */
+ public static final int TYPE_BCLR = 21;
+
+ /** The Constant TYPE_CCLR indicates color spaces with 12 components. */
+ public static final int TYPE_CCLR = 22;
+
+ /** The Constant TYPE_DCLR indicates color spaces with 13 components. */
+ public static final int TYPE_DCLR = 23;
+
+ /** The Constant TYPE_ECLR indicates color spaces with 14 components. */
+ public static final int TYPE_ECLR = 24;
+
+ /** The Constant TYPE_FCLR indicates color spaces with 15 components. */
+ public static final int TYPE_FCLR = 25;
+
+ /** The Constant CS_sRGB indicates standard RGB color space.*/
+ public static final int CS_sRGB = 1000;
+
+ /** The Constant CS_LINEAR_RGB indicates linear RGB color space. */
+ public static final int CS_LINEAR_RGB = 1004;
+
+ /** The Constant CS_CIEXYZ indicates CIEXYZ conversion color space. */
+ public static final int CS_CIEXYZ = 1001;
+
+ /** The Constant CS_PYCC indicates Photo YCC conversion color space. */
+ public static final int CS_PYCC = 1002;
+
+ /** The Constant CS_GRAY indicates linear gray scale color space. */
+ public static final int CS_GRAY = 1003;
+
+ /** The cs_ gray. */
+ private static ColorSpace cs_Gray = null;
+
+ /** The cs_ pycc. */
+ private static ColorSpace cs_PYCC = null;
+
+ /** The cs_ ciexyz. */
+ private static ColorSpace cs_CIEXYZ = null;
+
+ /** The cs_ lrgb. */
+ private static ColorSpace cs_LRGB = null;
+
+ /** The cs_s rgb. */
+ private static ColorSpace cs_sRGB = null;
+
+ /** The type. */
+ private int type;
+
+ /** The num components. */
+ private int numComponents;
+
+ /**
+ * Instantiates a ColorSpace with the specified
+ * ColorSpace type and number of components.
+ *
+ * @param type the type of color space.
+ * @param numcomponents the number of components.
+ */
+ protected ColorSpace(int type, int numcomponents) {
+ this.numComponents = numcomponents;
+ this.type = type;
+ }
+
+ /**
+ * Gets the name of the component for the specified component index.
+ *
+ * @param idx the index of the component.
+ *
+ * @return the name of the component.
+ */
+ public String getName(int idx) {
+ if (idx < 0 || idx > numComponents - 1) {
+ // awt.16A=Invalid component index: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.16A", idx)); //$NON-NLS-1$
+ }
+
+ return "Unnamed color component #" + idx; //$NON-NLS-1$
+ }
+
+ /**
+ * Perform transformation a color from this ColorSpace
+ * into the RGB color space.
+ *
+ * @param colorvalue the color value in this ColorSpace.
+ *
+ * @return the float array with color components in the
+ * RGB color space.
+ */
+ public abstract float[] toRGB(float[] colorvalue);
+
+ /**
+ * Perform transformation a color from this ColorSpace
+ * into the CS_CIEXYZ color space.
+ *
+ * @param colorvalue the color value in this ColorSpace.
+ *
+ * @return the float array with color components in the
+ * CS_CIEXYZ color space.
+ */
+ public abstract float[] toCIEXYZ(float[] colorvalue);
+
+ /**
+ * Performs color transformation from the RGB color space
+ * into this ColorSpace.
+ *
+ * @param rgbvalue a float array in the RGB color space.
+ *
+ * @return the float[] an array of transformed color
+ * components.
+ */
+ public abstract float[] fromRGB(float[] rgbvalue);
+
+ /**
+ * Performs color transformation from the CS_CIEXYZ color space
+ * into this ColorSpace.
+ *
+ * @param colorvalue a float array in the CS_CIEXYZ color space.
+ *
+ * @return the float[] an array of transformed color
+ * components.
+ */
+ public abstract float[] fromCIEXYZ(float[] colorvalue);
+
+ /**
+ * Gets the minimum normalized color component value for
+ * the specified component.
+ *
+ * @param component the component.
+ *
+ * @return the miniimum normalized value of the component.
+ */
+ public float getMinValue(int component) {
+ if (component < 0 || component > numComponents - 1) {
+ // awt.16A=Invalid component index: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the maximum normalized color component value for
+ * the specified component.
+ *
+ * @param component the component.
+ *
+ * @return the maximum normalized value of the component.
+ */
+ public float getMaxValue(int component) {
+ if (component < 0 || component > numComponents - 1) {
+ // awt.16A=Invalid component index: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$
+ }
+ return 1;
+ }
+
+ /**
+ * Checks if this ColorSpace has CS_sRGB type or not.
+ *
+ * @return true, if this ColorSpace has CS_sRGB type,
+ * false otherwise.
+ */
+ public boolean isCS_sRGB() {
+ // If our color space is sRGB, then cs_sRGB
+ // is already initialized
+ return (this == cs_sRGB);
+ }
+
+ /**
+ * Gets the type of the ColorSpace.
+ *
+ * @return the type of the ColorSpace.
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Gets the number of components for this ColorSpace.
+ *
+ * @return the number of components.
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+
+ /**
+ * Gets the single instance of ColorSpace with the specified
+ * ColorSpace: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY,
+ * or CS_PYCC.
+ *
+ * @param colorspace the identifier of the specified Colorspace.
+ *
+ * @return the single instance of the desired ColorSpace.
+ */
+ public static ColorSpace getInstance(int colorspace) {
+ switch (colorspace) {
+ case CS_sRGB:
+ if (cs_sRGB == null) {
+ cs_sRGB = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_sRGB));
+ LUTColorConverter.sRGB_CS = cs_sRGB;
+ //ICC_Profile.getInstance (CS_sRGB));
+ }
+ return cs_sRGB;
+ case CS_CIEXYZ:
+ if (cs_CIEXYZ == null) {
+ cs_CIEXYZ = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_CIEXYZ));
+ //ICC_Profile.getInstance (CS_CIEXYZ));
+ }
+ return cs_CIEXYZ;
+ case CS_GRAY:
+ if (cs_Gray == null) {
+ cs_Gray = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_GRAY));
+ LUTColorConverter.LINEAR_GRAY_CS = cs_Gray;
+ //ICC_Profile.getInstance (CS_GRAY));
+ }
+ return cs_Gray;
+ case CS_PYCC:
+ if (cs_PYCC == null) {
+ cs_PYCC = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_PYCC));
+ //ICC_Profile.getInstance (CS_PYCC));
+ }
+ return cs_PYCC;
+ case CS_LINEAR_RGB:
+ if (cs_LRGB == null) {
+ cs_LRGB = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_LINEAR_RGB));
+ LUTColorConverter.LINEAR_GRAY_CS = cs_Gray;
+ //ICC_Profile.getInstance (CS_LINEAR_RGB));
+ }
+ return cs_LRGB;
+ default:
+ }
+
+ // Unknown argument passed
+ // awt.16B=Not a predefined colorspace
+ throw new IllegalArgumentException(Messages.getString("Not a predefined colorspace")); //$NON-NLS-1$
+ }
+
+} \ No newline at end of file
diff --git a/awt/java/awt/color/ICC_ColorSpace.java b/awt/java/awt/color/ICC_ColorSpace.java
new file mode 100644
index 0000000..5ece2ef
--- /dev/null
+++ b/awt/java/awt/color/ICC_ColorSpace.java
@@ -0,0 +1,379 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import org.apache.harmony.awt.gl.color.ColorConverter;
+import org.apache.harmony.awt.gl.color.ColorScaler;
+import org.apache.harmony.awt.gl.color.ICC_Transform;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import java.io.*;
+
+/**
+ * ICC_ColorSpace class implements ColorSpace abstract class and
+ * represents device independent and device dependent color spaces.
+ * This color space is based on the International Color Consortium
+ * Specification (ICC) File Format for Color Profiles:
+ * <a href="http://www.color.org">http://www.color.org</a>
+ */
+public class ICC_ColorSpace extends ColorSpace {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 3455889114070431483L;
+
+ // Need to keep compatibility with serialized form
+ /** The Constant serialPersistentFields. */
+ private static final ObjectStreamField[]
+ serialPersistentFields = {
+ new ObjectStreamField("thisProfile", ICC_Profile.class), //$NON-NLS-1$
+ new ObjectStreamField("minVal", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("maxVal", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("diffMinMax", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("invDiffMinMax", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("needScaleInit", Boolean.TYPE) //$NON-NLS-1$
+ };
+
+
+ /**
+ * According to ICC specification (from http://www.color.org)
+ * "For the CIEXYZ encoding, each component (X, Y, and Z)
+ * is encoded as a u1Fixed15Number".
+ * This means that max value for this encoding is 1 + (32767/32768)
+ */
+ private static final float MAX_XYZ = 1f + (32767f/32768f);
+
+ /** The Constant MAX_SHORT. */
+ private static final float MAX_SHORT = 65535f;
+
+ /** The Constant INV_MAX_SHORT. */
+ private static final float INV_MAX_SHORT = 1f/MAX_SHORT;
+
+ /** The Constant SHORT2XYZ_FACTOR. */
+ private static final float SHORT2XYZ_FACTOR = MAX_XYZ/MAX_SHORT;
+
+ /** The Constant XYZ2SHORT_FACTOR. */
+ private static final float XYZ2SHORT_FACTOR = MAX_SHORT/MAX_XYZ;
+
+ /** The profile. */
+ private ICC_Profile profile = null;
+
+ /** The min values. */
+ private float minValues[] = null;
+
+ /** The max values. */
+ private float maxValues[] = null;
+
+ // cache transforms here - performance gain
+ /** The to rgb transform. */
+ private ICC_Transform toRGBTransform = null;
+
+ /** The from rgb transform. */
+ private ICC_Transform fromRGBTransform = null;
+
+ /** The to xyz transform. */
+ private ICC_Transform toXYZTransform = null;
+
+ /** The from xyz transform. */
+ private ICC_Transform fromXYZTransform = null;
+
+ /** The converter. */
+ private final ColorConverter converter = new ColorConverter();
+
+ /** The scaler. */
+ private final ColorScaler scaler = new ColorScaler();
+
+ /** The scaling data loaded. */
+ private boolean scalingDataLoaded = false;
+
+ /** The resolved deserialized inst. */
+ private ICC_ColorSpace resolvedDeserializedInst;
+
+ /**
+ * Instantiates a new ICC color space from an ICC_Profile object.
+ *
+ * @param pf the ICC_Profile object.
+ */
+ public ICC_ColorSpace(ICC_Profile pf) {
+ super(pf.getColorSpaceType(), pf.getNumComponents());
+
+ int pfClass = pf.getProfileClass();
+
+ switch (pfClass) {
+ case ICC_Profile.CLASS_COLORSPACECONVERSION:
+ case ICC_Profile.CLASS_DISPLAY:
+ case ICC_Profile.CLASS_OUTPUT:
+ case ICC_Profile.CLASS_INPUT:
+ break; // OK, it is color conversion profile
+ default:
+ // awt.168=Invalid profile class.
+ throw new IllegalArgumentException(Messages.getString("awt.168")); //$NON-NLS-1$
+ }
+
+ profile = pf;
+ fillMinMaxValues();
+ }
+
+ /**
+ * Returns the ICC_Profile for this ICC_ColorSpace.
+ *
+ * @return the ICC_Profile for this ICC_ColorSpace.
+ */
+ public ICC_Profile getProfile() {
+ if (profile instanceof ICC_ProfileStub) {
+ profile = ((ICC_ProfileStub) profile).loadProfile();
+ }
+
+ return profile;
+ }
+
+ @Override
+ public float[] toRGB(float[] colorvalue) {
+ if (toRGBTransform == null) {
+ ICC_Profile sRGBProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile();
+ ICC_Profile[] profiles = {getProfile(), sRGBProfile};
+ toRGBTransform = new ICC_Transform(profiles);
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+ }
+
+ short[] data = new short[getNumComponents()];
+
+ scaler.scale(colorvalue, data, 0);
+
+ short[] converted =
+ converter.translateColor(toRGBTransform, data, null);
+
+ // unscale to sRGB
+ float[] res = new float[3];
+
+ res[0] = ((converted[0] & 0xFFFF)) * INV_MAX_SHORT;
+ res[1] = ((converted[1] & 0xFFFF)) * INV_MAX_SHORT;
+ res[2] = ((converted[2] & 0xFFFF)) * INV_MAX_SHORT;
+
+ return res;
+ }
+
+ @Override
+ public float[] toCIEXYZ(float[] colorvalue) {
+ if (toXYZTransform == null) {
+ ICC_Profile xyzProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile();
+ ICC_Profile[] profiles = {getProfile(), xyzProfile};
+ try {
+ int[] intents = {
+ ICC_Profile.icRelativeColorimetric,
+ ICC_Profile.icPerceptual};
+ toXYZTransform = new ICC_Transform(profiles, intents);
+ } catch (CMMException e) { // No such tag, use what we can
+ toXYZTransform = new ICC_Transform(profiles);
+ }
+
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+ }
+
+ short[] data = new short[getNumComponents()];
+
+ scaler.scale(colorvalue, data, 0);
+
+ short[] converted =
+ converter.translateColor(toXYZTransform, data, null);
+
+ // unscale to XYZ
+ float[] res = new float[3];
+
+ res[0] = ((converted[0] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+ res[1] = ((converted[1] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+ res[2] = ((converted[2] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+
+ return res;
+ }
+
+ @Override
+ public float[] fromRGB(float[] rgbvalue) {
+ if (fromRGBTransform == null) {
+ ICC_Profile sRGBProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile();
+ ICC_Profile[] profiles = {sRGBProfile, getProfile()};
+ fromRGBTransform = new ICC_Transform(profiles);
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+ }
+
+ // scale rgb value to short
+ short[] scaledRGBValue = new short[3];
+ scaledRGBValue[0] = (short)(rgbvalue[0] * MAX_SHORT + 0.5f);
+ scaledRGBValue[1] = (short)(rgbvalue[1] * MAX_SHORT + 0.5f);
+ scaledRGBValue[2] = (short)(rgbvalue[2] * MAX_SHORT + 0.5f);
+
+ short[] converted =
+ converter.translateColor(fromRGBTransform, scaledRGBValue, null);
+
+ float[] res = new float[getNumComponents()];
+
+ scaler.unscale(res, converted, 0);
+
+ return res;
+ }
+
+ @Override
+ public float[] fromCIEXYZ(float[] xyzvalue) {
+ if (fromXYZTransform == null) {
+ ICC_Profile xyzProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile();
+ ICC_Profile[] profiles = {xyzProfile, getProfile()};
+ try {
+ int[] intents = {
+ ICC_Profile.icPerceptual,
+ ICC_Profile.icRelativeColorimetric};
+ fromXYZTransform = new ICC_Transform(profiles, intents);
+ } catch (CMMException e) { // No such tag, use what we can
+ fromXYZTransform = new ICC_Transform(profiles);
+ }
+
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+
+ }
+
+ // scale xyz value to short
+ short[] scaledXYZValue = new short[3];
+ scaledXYZValue[0] = (short)(xyzvalue[0] * XYZ2SHORT_FACTOR + 0.5f);
+ scaledXYZValue[1] = (short)(xyzvalue[1] * XYZ2SHORT_FACTOR + 0.5f);
+ scaledXYZValue[2] = (short)(xyzvalue[2] * XYZ2SHORT_FACTOR + 0.5f);
+
+ short[] converted =
+ converter.translateColor(fromXYZTransform, scaledXYZValue, null);
+
+ float[] res = new float[getNumComponents()];
+
+ scaler.unscale(res, converted, 0);
+
+ return res;
+ }
+
+ @Override
+ public float getMinValue(int component) {
+ if ((component < 0) || (component > this.getNumComponents() - 1)) {
+ // awt.169=Component index out of range
+ throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$
+ }
+
+ return minValues[component];
+ }
+
+ @Override
+ public float getMaxValue(int component) {
+ if ((component < 0) || (component > this.getNumComponents() - 1)) {
+ // awt.169=Component index out of range
+ throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$
+ }
+
+ return maxValues[component];
+ }
+
+ /**
+ * Fill min max values.
+ */
+ private void fillMinMaxValues() {
+ int n = getNumComponents();
+ maxValues = new float[n];
+ minValues = new float[n];
+ switch (getType()) {
+ case ColorSpace.TYPE_XYZ:
+ minValues[0] = 0;
+ minValues[1] = 0;
+ minValues[2] = 0;
+ maxValues[0] = MAX_XYZ;
+ maxValues[1] = MAX_XYZ;
+ maxValues[2] = MAX_XYZ;
+ break;
+ case ColorSpace.TYPE_Lab:
+ minValues[0] = 0;
+ minValues[1] = -128;
+ minValues[2] = -128;
+ maxValues[0] = 100;
+ maxValues[1] = 127;
+ maxValues[2] = 127;
+ break;
+ default:
+ for(int i=0; i<n; i++) {
+ minValues[i] = 0;
+ maxValues[i] = 1;
+ }
+ }
+ }
+
+ /**
+ * Write object.
+ *
+ * @param out the out
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ ObjectOutputStream.PutField fields = out.putFields();
+
+ fields.put("thisProfile", profile); //$NON-NLS-1$
+ fields.put("minVal", null); //$NON-NLS-1$
+ fields.put("maxVal", null); //$NON-NLS-1$
+ fields.put("diffMinMax", null); //$NON-NLS-1$
+ fields.put("invDiffMinMax", null); //$NON-NLS-1$
+ fields.put("needScaleInit", true); //$NON-NLS-1$
+
+ out.writeFields();
+ }
+
+ /**
+ * Read object.
+ *
+ * @param in the in
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ClassNotFoundException the class not found exception
+ */
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField fields = in.readFields();
+ resolvedDeserializedInst =
+ new ICC_ColorSpace((ICC_Profile) fields.get("thisProfile", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Read resolve.
+ *
+ * @return the object
+ *
+ * @throws ObjectStreamException the object stream exception
+ */
+ Object readResolve() throws ObjectStreamException {
+ return resolvedDeserializedInst;
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_Profile.java b/awt/java/awt/color/ICC_Profile.java
new file mode 100644
index 0000000..ad704e0
--- /dev/null
+++ b/awt/java/awt/color/ICC_Profile.java
@@ -0,0 +1,1231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.gl.color.ICC_ProfileHelper;
+import org.apache.harmony.awt.gl.color.NativeCMM;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ICC_Profile class represents a color profile data for color spaces
+ * based on the International Color Consortium Specification ICC.1:2001-12,
+ * File Format for Color Profiles.
+ */
+public class ICC_Profile implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -3938515861990936766L;
+
+ // NOTE: Constant field values are noted in 1.5 specification.
+
+ /**
+ * The Constant CLASS_INPUT indicates that profile class is input.
+ */
+ public static final int CLASS_INPUT = 0;
+
+ /**
+ * The Constant CLASS_DISPLAY indicates that profile class is display.
+ */
+ public static final int CLASS_DISPLAY = 1;
+
+ /**
+ * The Constant CLASS_OUTPUT indicates that profile class is output.
+ */
+ public static final int CLASS_OUTPUT = 2;
+
+ /**
+ * The Constant CLASS_DEVICELINK indicates that profile class
+ * is device link.
+ */
+ public static final int CLASS_DEVICELINK = 3;
+
+ /**
+ * The Constant CLASS_COLORSPACECONVERSION indicates that profile class
+ * is color space conversion.
+ */
+ public static final int CLASS_COLORSPACECONVERSION = 4;
+
+ /** The Constant CLASS_ABSTRACT indicates that profile class is abstract. */
+ public static final int CLASS_ABSTRACT = 5;
+
+ /**
+ * The Constant CLASS_NAMEDCOLOR indicates that profile class
+ * is named color.
+ */
+ public static final int CLASS_NAMEDCOLOR = 6;
+
+ /** The Constant icSigXYZData - ICC Profile Color Space Type Signature. */
+ public static final int icSigXYZData = 1482250784;
+
+ /** The Constant icSigLabData - ICC Profile Color Space Type Signature. */
+ public static final int icSigLabData = 1281450528;
+
+ /** The Constant icSigLuvData - ICC Profile Color Space Type Signature. */
+ public static final int icSigLuvData = 1282766368;
+
+ /** The Constant icSigYCbCrData - ICC Profile Color Space Type Signature. */
+ public static final int icSigYCbCrData = 1497588338;
+
+ /** The Constant icSigYxyData - ICC Profile Color Space Type Signature. */
+ public static final int icSigYxyData = 1501067552;
+
+ /** The Constant icSigRgbData - ICC Profile Color Space Type Signature. */
+ public static final int icSigRgbData = 1380401696;
+
+ /** The Constant icSigGrayData - ICC Profile Color Space Type Signature. */
+ public static final int icSigGrayData = 1196573017;
+
+ /** The Constant icSigHsvData - ICC Profile Color Space Type Signature. */
+ public static final int icSigHsvData = 1213421088;
+
+ /** The Constant icSigHlsData - ICC Profile Color Space Type Signature. */
+ public static final int icSigHlsData = 1212961568;
+
+ /** The Constant icSigCmykData - ICC Profile Color Space Type Signature. */
+ public static final int icSigCmykData = 1129142603;
+
+ /** The Constant icSigCmyData - ICC Profile Color Space Type Signature. */
+ public static final int icSigCmyData = 1129142560;
+
+ /** The Constant icSigSpace2CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace2CLR = 843271250;
+
+ /** The Constant icSigSpace3CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace3CLR = 860048466;
+
+ /** The Constant icSigSpace4CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace4CLR = 876825682;
+
+ /** The Constant icSigSpace5CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace5CLR = 893602898;
+
+ /** The Constant icSigSpace6CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace6CLR = 910380114;
+
+ /** The Constant icSigSpace7CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace7CLR = 927157330;
+
+ /** The Constant icSigSpace8CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace8CLR = 943934546;
+
+ /** The Constant icSigSpace9CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace9CLR = 960711762;
+
+ /** The Constant icSigSpaceACLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceACLR = 1094929490;
+
+ /** The Constant icSigSpaceBCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceBCLR = 1111706706;
+
+ /** The Constant icSigSpaceCCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceCCLR = 1128483922;
+
+ /** The Constant icSigSpaceDCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceDCLR = 1145261138;
+
+ /** The Constant icSigSpaceECLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceECLR = 1162038354;
+
+ /** The Constant icSigSpaceFCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceFCLR = 1178815570;
+
+ /** The Constant icSigInputClass - ICC Profile Class Signature. */
+ public static final int icSigInputClass = 1935896178;
+
+ /** The Constant icSigDisplayClass - ICC Profile Class Signature. */
+ public static final int icSigDisplayClass = 1835955314;
+
+ /** The Constant icSigOutputClass - ICC Profile Class Signature. */
+ public static final int icSigOutputClass = 1886549106;
+
+ /** The Constant icSigLinkClass - ICC Profile Class Signature. */
+ public static final int icSigLinkClass = 1818848875;
+
+ /** The Constant icSigAbstractClass - ICC Profile Class Signature. */
+ public static final int icSigAbstractClass = 1633842036;
+
+ /** The Constant icSigColorantOrderTag - ICC Profile Tag Signature. */
+ public static final int icSigColorantOrderTag = 1668051567;
+
+ /** The Constant icSigColorantTableTag - ICC Profile Tag Signature. */
+ public static final int icSigColorantTableTag = 1668051572;
+
+ /** The Constant icSigColorSpaceClass - ICC Profile Tag Signature. */
+ public static final int icSigColorSpaceClass = 1936744803;
+
+ /** The Constant icSigNamedColorClass - ICC Profile Tag Signature. */
+ public static final int icSigNamedColorClass = 1852662636;
+
+ /** The Constant icPerceptual - ICC Profile Rendering Intent. */
+ public static final int icPerceptual = 0;
+
+ /** The Constant icRelativeColorimetric - ICC Profile Rendering Intent. */
+ public static final int icRelativeColorimetric = 1;
+
+ /** The Constant icSaturation - ICC Profile Rendering Intent. */
+ public static final int icSaturation = 2;
+
+ /** The Constant icAbsoluteColorimetric - ICC Profile Rendering Intent. */
+ public static final int icAbsoluteColorimetric = 3;
+
+ /** The Constant icSigHead - ICC Profile Tag Signature. */
+ public static final int icSigHead = 1751474532;
+
+ /** The Constant icSigAToB0Tag - ICC Profile Tag Signature. */
+ public static final int icSigAToB0Tag = 1093812784;
+
+ /** The Constant icSigAToB1Tag - ICC Profile Tag Signature. */
+ public static final int icSigAToB1Tag = 1093812785;
+
+ /** The Constant icSigAToB2Tag - ICC Profile Tag Signature. */
+ public static final int icSigAToB2Tag = 1093812786;
+
+ /** The Constant icSigBlueColorantTag - ICC Profile Tag Signature. */
+ public static final int icSigBlueColorantTag = 1649957210;
+
+ /** The Constant icSigBlueMatrixColumnTag - ICC Profile Tag Signature. */
+ public static final int icSigBlueMatrixColumnTag = 1649957210;
+
+ /** The Constant icSigBlueTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigBlueTRCTag = 1649693251;
+
+ /** The Constant icSigBToA0Tag - ICC Profile Tag Signature. */
+ public static final int icSigBToA0Tag = 1110589744;
+
+ /** The Constant icSigBToA1Tag - ICC Profile Tag Signature. */
+ public static final int icSigBToA1Tag = 1110589745;
+
+ /** The Constant icSigBToA2Tag - ICC Profile Tag Signature. */
+ public static final int icSigBToA2Tag = 1110589746;
+
+ /** The Constant icSigCalibrationDateTimeTag - ICC Profile Tag Signature. */
+ public static final int icSigCalibrationDateTimeTag = 1667329140;
+
+ /** The Constant icSigCharTargetTag - ICC Profile Tag Signature. */
+ public static final int icSigCharTargetTag = 1952543335;
+
+ /** The Constant icSigCopyrightTag - ICC Profile Tag Signature. */
+ public static final int icSigCopyrightTag = 1668313716;
+
+ /** The Constant icSigCrdInfoTag - ICC Profile Tag Signature. */
+ public static final int icSigCrdInfoTag = 1668441193;
+
+ /** The Constant icSigDeviceMfgDescTag - ICC Profile Tag Signature. */
+ public static final int icSigDeviceMfgDescTag = 1684893284;
+
+ /** The Constant icSigDeviceModelDescTag - ICC Profile Tag Signature. */
+ public static final int icSigDeviceModelDescTag = 1684890724;
+
+ /** The Constant icSigDeviceSettingsTag - ICC Profile Tag Signature. */
+ public static final int icSigDeviceSettingsTag = 1684371059;
+
+ /** The Constant icSigGamutTag - ICC Profile Tag Signature. */
+ public static final int icSigGamutTag = 1734438260;
+
+ /** The Constant icSigGrayTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigGrayTRCTag = 1800688195;
+
+ /** The Constant icSigGreenColorantTag - ICC Profile Tag Signature. */
+ public static final int icSigGreenColorantTag = 1733843290;
+
+ /** The Constant icSigGreenMatrixColumnTag - ICC Profile Tag Signature. */
+ public static final int icSigGreenMatrixColumnTag = 1733843290;
+
+ /** The Constant icSigGreenTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigGreenTRCTag = 1733579331;
+
+ /** The Constant icSigLuminanceTag - ICC Profile Tag Signature. */
+ public static final int icSigLuminanceTag = 1819635049;
+
+ /** The Constant icSigMeasurementTag - ICC Profile Tag Signature. */
+ public static final int icSigMeasurementTag = 1835360627;
+
+ /** The Constant icSigMediaBlackPointTag - ICC Profile Tag Signature. */
+ public static final int icSigMediaBlackPointTag = 1651208308;
+
+ /** The Constant icSigMediaWhitePointTag - ICC Profile Tag Signature. */
+ public static final int icSigMediaWhitePointTag = 2004119668;
+
+ /** The Constant icSigNamedColor2Tag - ICC Profile Tag Signature. */
+ public static final int icSigNamedColor2Tag = 1852009522;
+
+ /** The Constant icSigOutputResponseTag - ICC Profile Tag Signature. */
+ public static final int icSigOutputResponseTag = 1919251312;
+
+ /** The Constant icSigPreview0Tag - ICC Profile Tag Signature. */
+ public static final int icSigPreview0Tag = 1886545200;
+
+ /** The Constant icSigPreview1Tag - ICC Profile Tag Signature. */
+ public static final int icSigPreview1Tag = 1886545201;
+
+ /** The Constant icSigPreview2Tag - ICC Profile Tag Signature. */
+ public static final int icSigPreview2Tag = 1886545202;
+
+ /** The Constant icSigProfileDescriptionTag - ICC Profile Tag Signature. */
+ public static final int icSigProfileDescriptionTag = 1684370275;
+
+ /** The Constant icSigProfileSequenceDescTag - ICC Profile Tag Signature. */
+ public static final int icSigProfileSequenceDescTag = 1886610801;
+
+ /** The Constant icSigPs2CRD0Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD0Tag = 1886610480;
+
+ /** The Constant icSigPs2CRD1Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD1Tag = 1886610481;
+
+ /** The Constant icSigPs2CRD2Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD2Tag = 1886610482;
+
+ /** The Constant icSigPs2CRD3Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD3Tag = 1886610483;
+
+ /** The Constant icSigPs2CSATag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CSATag = 1886597747;
+
+ /** The Constant icSigPs2RenderingIntentTag - ICC Profile Tag Signature. */
+ public static final int icSigPs2RenderingIntentTag = 1886597737;
+
+ /** The Constant icSigRedColorantTag - ICC Profile Tag Signature. */
+ public static final int icSigRedColorantTag = 1918392666;
+
+ /** The Constant icSigRedMatrixColumnTag - ICC Profile Tag Signature. */
+ public static final int icSigRedMatrixColumnTag = 1918392666;
+
+ /** The Constant icSigRedTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigRedTRCTag = 1918128707;
+
+ /** The Constant icSigScreeningDescTag - ICC Profile Tag Signature. */
+ public static final int icSigScreeningDescTag = 1935897188;
+
+ /** The Constant icSigScreeningTag - ICC Profile Tag Signature. */
+ public static final int icSigScreeningTag = 1935897198;
+
+ /** The Constant icSigTechnologyTag - ICC Profile Tag Signature. */
+ public static final int icSigTechnologyTag = 1952801640;
+
+ /** The Constant icSigUcrBgTag - ICC Profile Tag Signature. */
+ public static final int icSigUcrBgTag = 1650877472;
+
+ /** The Constant icSigViewingCondDescTag - ICC Profile Tag Signature. */
+ public static final int icSigViewingCondDescTag = 1987405156;
+
+ /** The Constant icSigViewingConditionsTag - ICC Profile Tag Signature. */
+ public static final int icSigViewingConditionsTag = 1986618743;
+
+ /** The Constant icSigChromaticAdaptationTag - ICC Profile Tag Signature. */
+ public static final int icSigChromaticAdaptationTag = 1667785060;
+
+ /** The Constant icSigChromaticityTag - ICC Profile Tag Signature. */
+ public static final int icSigChromaticityTag = 1667789421;
+
+ /** The Constant icHdrSize - ICC Profile Header Location. */
+ public static final int icHdrSize = 0;
+
+ /** The Constant icHdrCmmId - ICC Profile Header Location. */
+ public static final int icHdrCmmId = 4;
+
+ /** The Constant icHdrVersion - ICC Profile Header Location. */
+ public static final int icHdrVersion = 8;
+
+ /** The Constant icHdrDeviceClass - ICC Profile Header Location. */
+ public static final int icHdrDeviceClass = 12;
+
+ /** The Constant icHdrColorSpace - ICC Profile Header Location. */
+ public static final int icHdrColorSpace = 16;
+
+ /** The Constant icHdrPcs - ICC Profile Header Location. */
+ public static final int icHdrPcs = 20;
+
+ /** The Constant icHdrDate - ICC Profile Header Location. */
+ public static final int icHdrDate = 24;
+
+ /** The Constant icHdrMagic - ICC Profile Header Location. */
+ public static final int icHdrMagic = 36;
+
+ /** The Constant icHdrPlatform - ICC Profile Header Location. */
+ public static final int icHdrPlatform = 40;
+
+ /** The Constant icHdrProfileID - ICC Profile Header Location. */
+ public static final int icHdrProfileID = 84;
+
+ /** The Constant icHdrFlags - ICC Profile Header Location. */
+ public static final int icHdrFlags = 44;
+
+ /** The Constant icHdrManufacturer - ICC Profile Header Location. */
+ public static final int icHdrManufacturer = 48;
+
+ /** The Constant icHdrModel - ICC Profile Header Location. */
+ public static final int icHdrModel = 52;
+
+ /** The Constant icHdrAttributes - ICC Profile Header Location. */
+ public static final int icHdrAttributes = 56;
+
+ /** The Constant icHdrRenderingIntent - ICC Profile Header Location. */
+ public static final int icHdrRenderingIntent = 64;
+
+ /** The Constant icHdrIlluminant - ICC Profile Header Location. */
+ public static final int icHdrIlluminant = 68;
+
+ /** The Constant icHdrCreator - ICC Profile Header Location. */
+ public static final int icHdrCreator = 80;
+
+ /** The Constant icICCAbsoluteColorimetric - ICC Profile Rendering Intent. */
+ public static final int icICCAbsoluteColorimetric = 3;
+
+ /** The Constant icMediaRelativeColorimetric - ICC Profile Rendering Intent. */
+ public static final int icMediaRelativeColorimetric = 1;
+
+ /** The Constant icTagType - ICC Profile Constant. */
+ public static final int icTagType = 0;
+
+ /** The Constant icTagReserved - ICC Profile Constant. */
+ public static final int icTagReserved = 4;
+
+ /** The Constant icCurveCount - ICC Profile Constant. */
+ public static final int icCurveCount = 8;
+
+ /** The Constant icCurveData - ICC Profile Constant. */
+ public static final int icCurveData = 12;
+
+ /** The Constant icXYZNumberX - ICC Profile Constant. */
+ public static final int icXYZNumberX = 8;
+
+ /** Size of a profile header. */
+ private static final int headerSize = 128;
+
+ /** header magic number. */
+ private static final int headerMagicNumber = 0x61637370;
+
+ // Cache of predefined profiles
+ /** The s rgb profile. */
+ private static ICC_Profile sRGBProfile;
+
+ /** The xyz profile. */
+ private static ICC_Profile xyzProfile;
+
+ /** The gray profile. */
+ private static ICC_Profile grayProfile;
+
+ /** The pycc profile. */
+ private static ICC_Profile pyccProfile;
+
+ /** The linear rgb profile. */
+ private static ICC_Profile linearRGBProfile;
+
+ /** Handle to the current profile. */
+ private transient long profileHandle = 0;
+
+ /** If handle is used by another class this object is not responsible for closing profile. */
+ private transient boolean handleStolen = false;
+
+ /** Cached header data. */
+ private transient byte[] headerData = null;
+
+ /** Serialization support. */
+ private transient ICC_Profile openedProfileObject;
+
+ /**
+ * Instantiates a new iC c_ profile.
+ *
+ * @param data the data
+ */
+ private ICC_Profile(byte[] data) {
+ profileHandle = NativeCMM.cmmOpenProfile(data);
+ NativeCMM.addHandle(this, profileHandle);
+ }
+
+ /**
+ * Used to instantiate dummy ICC_ProfileStub objects.
+ */
+ ICC_Profile() {
+ }
+
+ /**
+ * Used to instantiate subclasses (ICC_ProfileGrey and ICC_ProfileRGB).
+ *
+ * @param profileHandle - should be valid handle to opened color profile
+ */
+ ICC_Profile(long profileHandle) {
+ this.profileHandle = profileHandle;
+ // A new object reference, need to add it.
+ NativeCMM.addHandle(this, profileHandle);
+ }
+
+ /**
+ * Writes the ICC_Profile to a file with the specified name.
+ *
+ * @param fileName the file name.
+ *
+ * @throws IOException signals that an I/O exception has occurred during
+ * writing or opening the file.
+ */
+ public void write(String fileName) throws IOException {
+ FileOutputStream oStream = new FileOutputStream(fileName);
+ oStream.write(getData());
+ oStream.close();
+ }
+
+ /**
+ * Serializable implementation.
+ *
+ * @param s the s
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void writeObject(ObjectOutputStream s) throws IOException {
+ s.defaultWriteObject();
+ s.writeObject(null);
+ s.writeObject(getData());
+ }
+
+ /**
+ * Serializable implementation.
+ *
+ * @param s the s
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ClassNotFoundException the class not found exception
+ */
+ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+ s.defaultReadObject();
+ String colorSpaceStr = (String)s.readObject();
+ byte[] data = (byte[])s.readObject();
+
+ if (colorSpaceStr != null) {
+ if (colorSpaceStr.equals("CS_sRGB")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_sRGB);
+ } else if (colorSpaceStr.equals("CS_GRAY")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_GRAY);
+ } else if (colorSpaceStr.equals("CS_LINEAR_RGB")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_LINEAR_RGB);
+ } else if (colorSpaceStr.equals("CS_CIEXYZ")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_CIEXYZ);
+ } else if (colorSpaceStr.equals("CS_PYCC")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_PYCC);
+ } else {
+ openedProfileObject = ICC_Profile.getInstance(data);
+ }
+ } else {
+ openedProfileObject = ICC_Profile.getInstance(data);
+ }
+ }
+
+ /**
+ * Resolves instances being deserialized into instances registered with CMM.
+ *
+ * @return ICC_Profile object for profile registered with CMM.
+ *
+ * @throws ObjectStreamException if there is an error in the serialized
+ * files or during the process of reading them.
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ return openedProfileObject;
+ }
+
+ /**
+ * Writes the ICC_Profile to an OutputStream.
+ *
+ * @param s the OutputStream.
+ *
+ * @throws IOException signals that an I/O exception has occurred during
+ * writing or opening OutputStream.
+ */
+ public void write(OutputStream s) throws IOException {
+ s.write(getData());
+ }
+
+ /**
+ * Sets a tagged data element in the profile from a byte array.
+ *
+ * @param tagSignature the ICC tag signature for the data element to be set.
+ * @param tagData the data to be set for the specified tag signature.
+ */
+ public void setData(int tagSignature, byte[] tagData) {
+ NativeCMM.cmmSetProfileElement(profileHandle, tagSignature, tagData);
+ // Remove cached header data if header is modified
+ if (tagSignature == icSigHead) {
+ headerData = null;
+ }
+ }
+
+ /**
+ * Gets a tagged data element from the profile as a byte array.
+ * Elements are identified by tag signatures as defined in
+ * the ICC specification.
+ *
+ * @param tagSignature the ICC tag signature for the data element to get.
+ *
+ * @return a byte array that contains the tagged data element.
+ */
+ public byte[] getData(int tagSignature) {
+ int tagSize = 0;
+ try {
+ tagSize = NativeCMM.cmmGetProfileElementSize(
+ profileHandle,
+ tagSignature
+ );
+ } catch (CMMException e) {
+ // We'll get this exception if there's no element with
+ // the specified tag signature
+ return null;
+ }
+
+ byte[] data = new byte[tagSize];
+ NativeCMM.cmmGetProfileElement(profileHandle, tagSignature, data);
+ return data;
+ }
+
+ /**
+ * Gets a data byte array of this ICC_Profile.
+ *
+ * @return a byte array that contains the ICC Profile data.
+ */
+ public byte[] getData() {
+ int profileSize = NativeCMM.cmmGetProfileSize(profileHandle);
+ byte[] data = new byte[profileSize];
+ NativeCMM.cmmGetProfile(profileHandle, data);
+ return data;
+ }
+
+ /**
+ * Frees the resources associated with an ICC_Profile object.
+ */
+ @Override
+ protected void finalize() {
+ if (profileHandle!=0 && !handleStolen) {
+ NativeCMM.cmmCloseProfile(profileHandle);
+ }
+
+ // Always remove because key no more exist
+ // when object is destroyed
+ NativeCMM.removeHandle(this);
+ }
+
+ /**
+ * Gets the profile class.
+ *
+ * @return the profile class constant.
+ */
+ public int getProfileClass() {
+ int deviceClassSignature = getIntFromHeader(icHdrDeviceClass);
+
+ switch (deviceClassSignature) {
+ case icSigColorSpaceClass:
+ return CLASS_COLORSPACECONVERSION;
+ case icSigDisplayClass:
+ return CLASS_DISPLAY;
+ case icSigOutputClass:
+ return CLASS_OUTPUT;
+ case icSigInputClass:
+ return CLASS_INPUT;
+ case icSigLinkClass:
+ return CLASS_DEVICELINK;
+ case icSigAbstractClass:
+ return CLASS_ABSTRACT;
+ case icSigNamedColorClass:
+ return CLASS_NAMEDCOLOR;
+ default:
+ }
+
+ // Not an ICC profile class
+ // awt.15F=Profile class does not comply with ICC specification
+ throw new IllegalArgumentException(Messages.getString("awt.15F")); //$NON-NLS-1$
+
+ }
+
+ /**
+ * Returns the color space type of the Profile Connection Space (PCS).
+ *
+ * @return the PCS type.
+ */
+ public int getPCSType() {
+ return csFromSignature(getIntFromHeader(icHdrPcs));
+ }
+
+ /**
+ * Gets the number of components of this ICC Profile.
+ *
+ * @return the number of components of this ICC Profile.
+ */
+ public int getNumComponents() {
+ switch (getIntFromHeader(icHdrColorSpace)) {
+ // The most common cases go first to increase speed
+ case icSigRgbData:
+ case icSigXYZData:
+ case icSigLabData:
+ return 3;
+ case icSigCmykData:
+ return 4;
+ // Then all other
+ case icSigGrayData:
+ return 1;
+ case icSigSpace2CLR:
+ return 2;
+ case icSigYCbCrData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHlsData:
+ case icSigHsvData:
+ case icSigCmyData:
+ case icSigSpace3CLR:
+ return 3;
+ case icSigSpace4CLR:
+ return 4;
+ case icSigSpace5CLR:
+ return 5;
+ case icSigSpace6CLR:
+ return 6;
+ case icSigSpace7CLR:
+ return 7;
+ case icSigSpace8CLR:
+ return 8;
+ case icSigSpace9CLR:
+ return 9;
+ case icSigSpaceACLR:
+ return 10;
+ case icSigSpaceBCLR:
+ return 11;
+ case icSigSpaceCCLR:
+ return 12;
+ case icSigSpaceDCLR:
+ return 13;
+ case icSigSpaceECLR:
+ return 14;
+ case icSigSpaceFCLR:
+ return 15;
+ default:
+ }
+
+ // awt.160=Color space doesn't comply with ICC specification
+ throw new ProfileDataException(Messages.getString("awt.160") //$NON-NLS-1$
+ );
+ }
+
+ /**
+ * Gets the minor version of this ICC profile.
+ *
+ * @return the minor version of this ICC profile.
+ */
+ public int getMinorVersion() {
+ return getByteFromHeader(icHdrVersion+1);
+ }
+
+ /**
+ * Gets the major version of this ICC profile.
+ *
+ * @return the major version of this ICC profile.
+ */
+ public int getMajorVersion() {
+ return getByteFromHeader(icHdrVersion);
+ }
+
+ /**
+ * Gets the color space type of this ICC_Profile.
+ *
+ * @return the color space type.
+ */
+ public int getColorSpaceType() {
+ return csFromSignature(getIntFromHeader(icHdrColorSpace));
+ }
+
+ /**
+ * Tries to open file at the specified path. Path entries can be
+ * divided by a separator character.
+ *
+ * @param path the path
+ * @param fileName the file name
+ *
+ * @return the file input stream
+ */
+ private static FileInputStream tryPath(String path, String fileName) {
+ FileInputStream fiStream = null;
+
+ if (path == null) {
+ return null;
+ }
+
+ StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
+
+ while (st.hasMoreTokens()) {
+ String pathEntry = st.nextToken();
+ try {
+ fiStream = new FileInputStream(pathEntry + File.separatorChar + fileName);
+ if (fiStream != null) {
+ return fiStream;
+ }
+ } catch (FileNotFoundException e) {}
+ }
+
+ return fiStream;
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile from data in the specified file.
+ *
+ * @param fileName the specified name of file with ICC profile data.
+ *
+ * @return single instance of ICC_Profile.
+ *
+ * @throws IOException signals that an I/O error occured while reading the file
+ * or the file doesn't exist.
+ */
+ public static ICC_Profile getInstance(String fileName) throws IOException {
+ final String fName = fileName; // to use in the privileged block
+
+ FileInputStream fiStream = (FileInputStream) AccessController.doPrivileged(
+ new PrivilegedAction<FileInputStream>() {
+ public FileInputStream run() {
+ FileInputStream fiStream = null;
+
+ // Open absolute path
+ try {
+ fiStream = new FileInputStream(fName);
+ if (fiStream != null) {
+ return fiStream;
+ }
+ } catch (FileNotFoundException e) {}
+
+ // Check java.iccprofile.path entries
+ fiStream = tryPath(System.getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$
+ if (fiStream != null) {
+ return fiStream;
+ }
+
+ // Check java.class.path entries
+ fiStream = tryPath(System.getProperty("java.class.path"), fName); //$NON-NLS-1$
+ if (fiStream != null) {
+ return fiStream;
+ }
+
+ // Check directory with java sample profiles
+ String home = System.getProperty("java.home"); //$NON-NLS-1$
+ if (home != null) {
+ fiStream = tryPath(
+ home + File.separatorChar +
+ "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$
+ );
+ }
+
+ return fiStream;
+ }
+ });
+
+ if (fiStream == null) {
+ // awt.161=Unable to open file {0}
+ throw new IOException(Messages.getString("awt.161", fileName)); //$NON-NLS-1$
+ }
+
+ ICC_Profile pf = getInstance(fiStream);
+ fiStream.close();
+ return pf;
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile with data in
+ * the specified InputStream.
+ *
+ * @param s the InputStream with ICC profile data.
+ *
+ * @return single instance of ICC_Profile.
+ *
+ * @throws IOException if an I/O exception has occurred during reading
+ * from InputStream.
+ * @throws IllegalArgumentException if the file does not contain valid
+ * ICC Profile data.
+ */
+ public static ICC_Profile getInstance(InputStream s) throws IOException {
+ byte[] header = new byte[headerSize];
+ // awt.162=Invalid ICC Profile Data
+ String invalidDataMessage = Messages.getString("awt.162"); //$NON-NLS-1$
+
+ // Get header from the input stream
+ if (s.read(header) != headerSize) {
+ throw new IllegalArgumentException(invalidDataMessage);
+ }
+
+ // Check the profile data for consistency
+ if (
+ ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) !=
+ headerMagicNumber
+ ) {
+ throw new IllegalArgumentException(invalidDataMessage);
+ }
+
+ // Get profile size from header, create an array for profile data
+ int profileSize = ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrSize);
+ byte[] profileData = new byte[profileSize];
+
+ // Copy header into it
+ System.arraycopy(header, 0, profileData, 0, headerSize);
+
+ // Read the profile itself
+ if (
+ s.read(profileData, headerSize, profileSize - headerSize) !=
+ profileSize - headerSize
+ ) {
+ throw new IllegalArgumentException(invalidDataMessage);
+ }
+
+ return getInstance(profileData);
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile from the specified data in
+ * a byte array.
+ *
+ * @param data the byte array of ICC profile.
+ *
+ * @return single instance of ICC_Profile from the specified data in
+ * a byte array.
+ *
+ * @throws IllegalArgumentException if the file does not contain valid
+ * ICC Profile data.
+ */
+ public static ICC_Profile getInstance(byte[] data) {
+ ICC_Profile res = null;
+
+ try {
+ res = new ICC_Profile(data);
+ } catch (CMMException e) {
+ // awt.162=Invalid ICC Profile Data
+ throw new IllegalArgumentException(Messages.getString("awt.162")); //$NON-NLS-1$
+ }
+
+ if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ if ( res.getColorSpaceType () == ColorSpace.TYPE_RGB &&
+ res.getDataSize(icSigMediaWhitePointTag) > 0 &&
+ res.getDataSize(icSigRedColorantTag) > 0 &&
+ res.getDataSize(icSigGreenColorantTag) > 0 &&
+ res.getDataSize(icSigBlueColorantTag) > 0 &&
+ res.getDataSize(icSigRedTRCTag) > 0 &&
+ res.getDataSize(icSigGreenTRCTag) > 0 &&
+ res.getDataSize(icSigBlueTRCTag) > 0
+ ) {
+ res = new ICC_ProfileRGB(res.getProfileHandle());
+ } else if ( res.getColorSpaceType () == ColorSpace.TYPE_GRAY &&
+ res.getDataSize(icSigMediaWhitePointTag) > 0 &&
+ res.getDataSize(icSigGrayTRCTag) > 0
+ ) {
+ res = new ICC_ProfileGray (res.getProfileHandle());
+ }
+
+ } catch (CMMException e) { /* return res in this case */ }
+ }
+
+ return res;
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile with the specific color space
+ * defined by the ColorSpace class: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ,
+ * CS_PYCC, CS_GRAY.
+ *
+ * @param cspace the type of color space defined in the ColorSpace class.
+ *
+ * @return single instance of ICC_Profile.
+ *
+ * @throws IllegalArgumentException is not one of the defined color
+ * space types.
+ */
+ public static ICC_Profile getInstance(int cspace) {
+ try {
+ switch (cspace) {
+
+ case ColorSpace.CS_sRGB:
+ if (sRGBProfile == null) {
+ sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$
+ }
+ return sRGBProfile;
+
+ case ColorSpace.CS_CIEXYZ:
+ if (xyzProfile == null) {
+ xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$
+ }
+ return xyzProfile;
+
+ case ColorSpace.CS_GRAY:
+ if (grayProfile == null) {
+ grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$
+ }
+ return grayProfile;
+
+ case ColorSpace.CS_PYCC:
+ if (pyccProfile == null) {
+ pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$
+ }
+ return pyccProfile;
+
+ case ColorSpace.CS_LINEAR_RGB:
+ if (linearRGBProfile == null) {
+ linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$
+ }
+ return linearRGBProfile;
+ }
+
+ } catch (IOException e) {
+ // awt.163=Can't open color profile
+ throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$
+ }
+
+ // awt.164=Not a predefined color space
+ throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$
+ }
+
+ /**
+ * Reads an integer from the profile header at the specified position.
+ *
+ * @param idx - offset in bytes from the beginning of the header
+ *
+ * @return the int from header
+ */
+ private int getIntFromHeader(int idx) {
+ if (headerData == null) {
+ headerData = getData(icSigHead);
+ }
+
+ return ((headerData[idx] & 0xFF) << 24)|
+ ((headerData[idx+1] & 0xFF) << 16)|
+ ((headerData[idx+2] & 0xFF) << 8) |
+ ((headerData[idx+3] & 0xFF));
+ }
+
+ /**
+ * Reads byte from the profile header at the specified position.
+ *
+ * @param idx - offset in bytes from the beginning of the header
+ *
+ * @return the byte from header
+ */
+ private byte getByteFromHeader(int idx) {
+ if (headerData == null) {
+ headerData = getData(icSigHead);
+ }
+
+ return headerData[idx];
+ }
+
+ /**
+ * Converts ICC color space signature to the java predefined
+ * color space type.
+ *
+ * @param signature the signature
+ *
+ * @return the int
+ */
+ private int csFromSignature(int signature) {
+ switch (signature) {
+ case icSigRgbData:
+ return ColorSpace.TYPE_RGB;
+ case icSigXYZData:
+ return ColorSpace.TYPE_XYZ;
+ case icSigCmykData:
+ return ColorSpace.TYPE_CMYK;
+ case icSigLabData:
+ return ColorSpace.TYPE_Lab;
+ case icSigGrayData:
+ return ColorSpace.TYPE_GRAY;
+ case icSigHlsData:
+ return ColorSpace.TYPE_HLS;
+ case icSigLuvData:
+ return ColorSpace.TYPE_Luv;
+ case icSigYCbCrData:
+ return ColorSpace.TYPE_YCbCr;
+ case icSigYxyData:
+ return ColorSpace.TYPE_Yxy;
+ case icSigHsvData:
+ return ColorSpace.TYPE_HSV;
+ case icSigCmyData:
+ return ColorSpace.TYPE_CMY;
+ case icSigSpace2CLR:
+ return ColorSpace.TYPE_2CLR;
+ case icSigSpace3CLR:
+ return ColorSpace.TYPE_3CLR;
+ case icSigSpace4CLR:
+ return ColorSpace.TYPE_4CLR;
+ case icSigSpace5CLR:
+ return ColorSpace.TYPE_5CLR;
+ case icSigSpace6CLR:
+ return ColorSpace.TYPE_6CLR;
+ case icSigSpace7CLR:
+ return ColorSpace.TYPE_7CLR;
+ case icSigSpace8CLR:
+ return ColorSpace.TYPE_8CLR;
+ case icSigSpace9CLR:
+ return ColorSpace.TYPE_9CLR;
+ case icSigSpaceACLR:
+ return ColorSpace.TYPE_ACLR;
+ case icSigSpaceBCLR:
+ return ColorSpace.TYPE_BCLR;
+ case icSigSpaceCCLR:
+ return ColorSpace.TYPE_CCLR;
+ case icSigSpaceDCLR:
+ return ColorSpace.TYPE_DCLR;
+ case icSigSpaceECLR:
+ return ColorSpace.TYPE_ECLR;
+ case icSigSpaceFCLR:
+ return ColorSpace.TYPE_FCLR;
+ default:
+ }
+
+ // awt.165=Color space doesn't comply with ICC specification
+ throw new IllegalArgumentException (Messages.getString("awt.165")); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the profile handle.
+ *
+ * @return the profile handle
+ */
+ private long getProfileHandle() {
+ handleStolen = true;
+ return profileHandle;
+ }
+
+ /**
+ * Gets the data size.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the data size
+ */
+ private int getDataSize(int tagSignature) {
+ return NativeCMM.cmmGetProfileElementSize(
+ profileHandle,
+ tagSignature
+ );
+ }
+
+ /**
+ * Reads XYZ value from the tag data.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the XYZ value
+ */
+ float[] getXYZValue(int tagSignature) {
+ float[] res = new float[3];
+ byte[] data = getData(tagSignature);
+
+ // Convert from ICC s15Fixed16Number type
+ // 1 (float) = 0x10000 (s15Fixed16Number),
+ // hence dividing by 0x10000
+ res[0] = ICC_ProfileHelper.getIntFromByteArray(data, 0) / 65536.f;
+ res[1] = ICC_ProfileHelper.getIntFromByteArray(data, 4) / 65536.f;
+ res[2] = ICC_ProfileHelper.getIntFromByteArray(data, 8) / 65536.f;
+
+ return res;
+ }
+
+ /**
+ * Gets the media white point.
+ *
+ * @return the media white point
+ */
+ float[] getMediaWhitePoint() {
+ return getXYZValue(icSigMediaWhitePointTag);
+ }
+
+ /**
+ * If TRC is not a table returns gamma via return value
+ * and sets dataTRC to null. If TRC is a table returns 0
+ * and fills dataTRC with values.
+ *
+ * @param tagSignature the tag signature
+ * @param dataTRC the data trc
+ *
+ * @return - gamma or zero if TRC is a table
+ */
+ private float getGammaOrTRC(int tagSignature, short[] dataTRC) {
+ byte[] data = getData(tagSignature);
+ int trcSize = ICC_ProfileHelper.getIntFromByteArray(data, icCurveCount);
+
+ dataTRC = null;
+
+ if (trcSize == 0) {
+ return 1.0f;
+ }
+
+ if (trcSize == 1) {
+ // Cast from ICC u8Fixed8Number to float
+ return ICC_ProfileHelper.getShortFromByteArray(data, icCurveData) / 256.f;
+ }
+
+ // TRC is a table
+ dataTRC = new short[trcSize];
+ for (int i = 0, pos = icCurveData; i < trcSize; i++, pos += 2) {
+ dataTRC[i] = ICC_ProfileHelper.getShortFromByteArray(data, pos);
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the gamma.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the gamma
+ */
+ float getGamma(int tagSignature) {
+ short[] dataTRC = null;
+ float gamma = getGammaOrTRC(tagSignature, dataTRC);
+
+ if (dataTRC == null) {
+ return gamma;
+ }
+ // awt.166=TRC is not a simple gamma value.
+ throw new ProfileDataException(Messages.getString("awt.166")); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the tRC.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the tRC
+ */
+ short[] getTRC(int tagSignature) {
+ short[] dataTRC = null;
+ getGammaOrTRC(tagSignature, dataTRC);
+
+ if (dataTRC == null) {
+ // awt.167=TRC is a gamma value, not a table.
+ throw new ProfileDataException(Messages.getString("awt.167")); //$NON-NLS-1$
+ }
+ return dataTRC;
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileGray.java b/awt/java/awt/color/ICC_ProfileGray.java
new file mode 100644
index 0000000..f009b18
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileGray.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The ICC_ProfileGray class represent profiles with TYPE_GRAY color space type,
+ * and includes the grayTRCTag and mediaWhitePointTag tags.
+ *
+ * The gray component can be transformed from a GRAY device profile color space
+ * to the CIEXYZ Profile through the tone reproduction curve (TRC):
+ * <p>PCSY = grayTRC[deviceGray]
+ */
+public class ICC_ProfileGray extends ICC_Profile {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1124721290732002649L;
+
+ /**
+ * Instantiates a new iC c_ profile gray.
+ *
+ * @param profileHandle the profile handle
+ */
+ ICC_ProfileGray(long profileHandle) {
+ super(profileHandle);
+ }
+
+ /**
+ * Gets the TRC as an array of shorts.
+ *
+ * @return a short array of the TRC.
+ */
+ public short[] getTRC() {
+ return super.getTRC(icSigGrayTRCTag);
+ }
+
+ @Override
+ public float[] getMediaWhitePoint() {
+ return super.getMediaWhitePoint();
+ }
+
+ /**
+ * Gets a gamma value representing the tone reproduction curve (TRC).
+ *
+ * @return the gamma value representing the tone reproduction curve (TRC).
+ */
+ public float getGamma() {
+ return super.getGamma(icSigGrayTRCTag);
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileRGB.java b/awt/java/awt/color/ICC_ProfileRGB.java
new file mode 100644
index 0000000..beb1a0c
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileRGB.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ICC_ProfileRGB class represents profiles with RGB color space type and
+ * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag,
+ * greenTRCTag, blueTRCTag, and mediaWhitePointTag tags.
+ */
+public class ICC_ProfileRGB extends ICC_Profile {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8505067385152579334L;
+
+ /**
+ * Instantiates a new iC c_ profile rgb.
+ *
+ * @param profileHandle the profile handle
+ */
+ ICC_ProfileRGB(long profileHandle) {
+ super(profileHandle);
+ }
+
+ /** The Constant REDCOMPONENT indicates the red component. */
+ public static final int REDCOMPONENT = 0;
+
+ /** The Constant GREENCOMPONENT indicates the green component. */
+ public static final int GREENCOMPONENT = 1;
+
+ /** The Constant BLUECOMPONENT indicates the blue component. */
+ public static final int BLUECOMPONENT = 2;
+
+ // awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT.
+ /** The Constant UNKNOWN_COMPONENT_MSG. */
+ private static final String UNKNOWN_COMPONENT_MSG = Messages
+ .getString("awt.15E"); //$NON-NLS-1$
+
+ @Override
+ public short[] getTRC(int component) {
+ switch (component) {
+ case REDCOMPONENT:
+ return super.getTRC(icSigRedTRCTag);
+ case GREENCOMPONENT:
+ return super.getTRC(icSigGreenTRCTag);
+ case BLUECOMPONENT:
+ return super.getTRC(icSigBlueTRCTag);
+ default:
+ }
+
+ throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG);
+ }
+
+ @Override
+ public float getGamma(int component) {
+ switch (component) {
+ case REDCOMPONENT:
+ return super.getGamma(icSigRedTRCTag);
+ case GREENCOMPONENT:
+ return super.getGamma(icSigGreenTRCTag);
+ case BLUECOMPONENT:
+ return super.getGamma(icSigBlueTRCTag);
+ default:
+ }
+
+ throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG);
+ }
+
+ /**
+ * Gets a float matrix which contains the X, Y, and Z components of
+ * the profile's redColorantTag, greenColorantTag, and blueColorantTag.
+ *
+ * @return a float matrix which contains the X, Y, and Z components of
+ * the profile's redColorantTag, greenColorantTag, and blueColorantTag.
+ */
+ public float[][] getMatrix() {
+ float [][] m = new float[3][3]; // The matrix
+
+ float[] redXYZ = getXYZValue(icSigRedColorantTag);
+ float[] greenXYZ = getXYZValue(icSigGreenColorantTag);
+ float[] blueXYZ = getXYZValue(icSigBlueColorantTag);
+
+ m[0][0] = redXYZ[0];
+ m[1][0] = redXYZ[1];
+ m[2][0] = redXYZ[2];
+
+ m[0][1] = greenXYZ[0];
+ m[1][1] = greenXYZ[1];
+ m[2][1] = greenXYZ[2];
+
+ m[0][2] = blueXYZ[0];
+ m[1][2] = blueXYZ[1];
+ m[2][2] = blueXYZ[2];
+
+ return m;
+ }
+
+ @Override
+ public float[] getMediaWhitePoint() {
+ return super.getMediaWhitePoint();
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileStub.java b/awt/java/awt/color/ICC_ProfileStub.java
new file mode 100644
index 0000000..bc04c8a
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileStub.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.color;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+final class ICC_ProfileStub extends ICC_Profile {
+ private static final long serialVersionUID = 501389760875253507L;
+
+ transient int colorspace;
+
+ public ICC_ProfileStub(int csSpecifier) {
+ switch (csSpecifier) {
+ case ColorSpace.CS_sRGB:
+ case ColorSpace.CS_CIEXYZ:
+ case ColorSpace.CS_LINEAR_RGB:
+ case ColorSpace.CS_PYCC:
+ case ColorSpace.CS_GRAY:
+ break;
+ default:
+ // awt.15D=Invalid colorspace
+ throw new IllegalArgumentException(Messages.getString("awt.15D")); //$NON-NLS-1$
+ }
+ colorspace = csSpecifier;
+ }
+
+ @Override
+ public void write(String fileName) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ /**
+ * Serializable implementation
+ *
+ * @throws ObjectStreamException
+ */
+ private Object writeReplace() throws ObjectStreamException {
+ return loadProfile();
+ }
+
+ @Override
+ public void write(OutputStream s) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setData(int tagSignature, byte[] tagData) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public byte[] getData(int tagSignature) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public byte[] getData() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ protected void finalize() {
+ }
+
+ @Override
+ public int getProfileClass() {
+ return CLASS_COLORSPACECONVERSION;
+ }
+
+ @Override
+ public int getPCSType() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getNumComponents() {
+ switch (colorspace) {
+ case ColorSpace.CS_sRGB:
+ case ColorSpace.CS_CIEXYZ:
+ case ColorSpace.CS_LINEAR_RGB:
+ case ColorSpace.CS_PYCC:
+ return 3;
+ case ColorSpace.CS_GRAY:
+ return 1;
+ default:
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public int getMinorVersion() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getMajorVersion() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getColorSpaceType() {
+ switch (colorspace) {
+ case ColorSpace.CS_sRGB:
+ case ColorSpace.CS_LINEAR_RGB:
+ return ColorSpace.TYPE_RGB;
+ case ColorSpace.CS_CIEXYZ:
+ return ColorSpace.TYPE_XYZ;
+ case ColorSpace.CS_PYCC:
+ return ColorSpace.TYPE_3CLR;
+ case ColorSpace.CS_GRAY:
+ return ColorSpace.TYPE_GRAY;
+ default:
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+ }
+
+ public static ICC_Profile getInstance(String fileName) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public static ICC_Profile getInstance(InputStream s) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public static ICC_Profile getInstance(byte[] data) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public static ICC_Profile getInstance(int cspace) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public ICC_Profile loadProfile() {
+ switch (colorspace) {
+ case ColorSpace.CS_sRGB:
+ return ICC_Profile.getInstance(ColorSpace.CS_sRGB);
+ case ColorSpace.CS_GRAY:
+ return ICC_Profile.getInstance(ColorSpace.CS_GRAY);
+ case ColorSpace.CS_CIEXYZ:
+ return ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
+ case ColorSpace.CS_LINEAR_RGB:
+ return ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB);
+ case ColorSpace.CS_PYCC:
+ return ICC_Profile.getInstance(ColorSpace.CS_PYCC);
+ default:
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+ }
+} \ No newline at end of file
diff --git a/awt/java/awt/color/ProfileDataException.java b/awt/java/awt/color/ProfileDataException.java
new file mode 100644
index 0000000..ca169fe
--- /dev/null
+++ b/awt/java/awt/color/ProfileDataException.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The ProfileDataException class represents an error which occurs
+ * while accessing or processing an ICC_Profile object.
+ */
+public class ProfileDataException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 7286140888240322498L;
+
+ /**
+ * Instantiates a new profile data exception with detailed message.
+ *
+ * @param s the detailed message.
+ */
+ public ProfileDataException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/event/AWTEventListener.java b/awt/java/awt/event/AWTEventListener.java
new file mode 100644
index 0000000..f621c9b
--- /dev/null
+++ b/awt/java/awt/event/AWTEventListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.util.EventListener;
+
+public interface AWTEventListener extends EventListener {
+
+ public void eventDispatched(AWTEvent event);
+
+}
diff --git a/awt/java/awt/event/AWTEventListenerProxy.java b/awt/java/awt/event/AWTEventListenerProxy.java
new file mode 100644
index 0000000..5ee5e59
--- /dev/null
+++ b/awt/java/awt/event/AWTEventListenerProxy.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+import java.util.EventListenerProxy;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class AWTEventListenerProxy extends EventListenerProxy implements AWTEventListener {
+
+ private AWTEventListener listener;
+ private long eventMask;
+
+ public AWTEventListenerProxy(long eventMask, AWTEventListener listener) {
+ super(listener);
+
+ // awt.193=Listener can't be zero
+ assert listener != null : Messages.getString("awt.193"); //$NON-NLS-1$
+
+ this.listener = listener;
+ this.eventMask = eventMask;
+ }
+
+ public void eventDispatched(AWTEvent evt) {
+ listener.eventDispatched(evt);
+ }
+
+ public long getEventMask() {
+ return eventMask;
+ }
+
+}
diff --git a/awt/java/awt/event/ActionEvent.java b/awt/java/awt/event/ActionEvent.java
new file mode 100644
index 0000000..c32fc4b
--- /dev/null
+++ b/awt/java/awt/event/ActionEvent.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+public class ActionEvent extends AWTEvent {
+
+ private static final long serialVersionUID = -7671078796273832149L;
+
+ public static final int SHIFT_MASK = 1;
+
+ public static final int CTRL_MASK = 2;
+
+ public static final int META_MASK = 4;
+
+ public static final int ALT_MASK = 8;
+
+ public static final int ACTION_FIRST = 1001;
+
+ public static final int ACTION_LAST = 1001;
+
+ public static final int ACTION_PERFORMED = 1001;
+
+ private long when;
+ private int modifiers;
+ private String command;
+
+ public ActionEvent(Object source, int id, String command) {
+ this(source, id, command, 0);
+ }
+
+ public ActionEvent(Object source, int id, String command, int modifiers) {
+ this(source, id, command, 0l, modifiers);
+ }
+
+ public ActionEvent(Object source, int id, String command, long when, int modifiers) {
+ super(source, id);
+
+ this.command = command;
+ this.when = when;
+ this.modifiers = modifiers;
+ }
+
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ public String getActionCommand() {
+ return command;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * ActionEvent e = new ActionEvent(new Component(){},
+ * ActionEvent.ACTION_PERFORMED, "Command",
+ * ActionEvent.SHIFT_MASK|ActionEvent.CTRL_MASK|
+ * ActionEvent.META_MASK|ActionEvent.ALT_MASK);
+ * System.out.println(e);
+ */
+
+ String idString = (id == ACTION_PERFORMED) ?
+ "ACTION_PERFORMED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$
+ String modifiersString = ""; //$NON-NLS-1$
+
+ if ((modifiers & SHIFT_MASK) > 0) {
+ modifiersString += "Shift"; //$NON-NLS-1$
+ }
+ if ((modifiers & CTRL_MASK) > 0) {
+ modifiersString += modifiersString.length() == 0 ? "Ctrl" : "+Ctrl"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiers & META_MASK) > 0) {
+ modifiersString += modifiersString.length() == 0 ? "Meta" : "+Meta"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiers & ALT_MASK) > 0) {
+ modifiersString += modifiersString.length() == 0 ? "Alt" : "+Alt"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return (idString + ",cmd=" + command + ",when=" + when + //$NON-NLS-1$ //$NON-NLS-2$
+ ",modifiers=" + modifiersString); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/ActionListener.java b/awt/java/awt/event/ActionListener.java
new file mode 100644
index 0000000..473d2b6
--- /dev/null
+++ b/awt/java/awt/event/ActionListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ActionListener extends EventListener {
+
+ public void actionPerformed(ActionEvent e);
+
+}
diff --git a/awt/java/awt/event/AdjustmentEvent.java b/awt/java/awt/event/AdjustmentEvent.java
new file mode 100644
index 0000000..a2b11a8
--- /dev/null
+++ b/awt/java/awt/event/AdjustmentEvent.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Adjustable;
+
+public class AdjustmentEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 5700290645205279921L;
+
+ public static final int ADJUSTMENT_FIRST = 601;
+
+ public static final int ADJUSTMENT_LAST = 601;
+
+ public static final int ADJUSTMENT_VALUE_CHANGED = 601;
+
+ public static final int UNIT_INCREMENT = 1;
+
+ public static final int UNIT_DECREMENT = 2;
+
+ public static final int BLOCK_DECREMENT = 3;
+
+ public static final int BLOCK_INCREMENT = 4;
+
+ public static final int TRACK = 5;
+
+ private int type;
+ private int value;
+ private boolean isAdjusting;
+
+ public AdjustmentEvent(Adjustable source, int id, int type, int value) {
+ this(source, id, type, value, false);
+ }
+
+ public AdjustmentEvent(Adjustable source, int id, int type, int value,
+ boolean isAdjusting) {
+ super(source, id);
+ this.type = type;
+ this.value = value;
+ this.isAdjusting = isAdjusting;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public int getAdjustmentType() {
+ return type;
+ }
+
+ public boolean getValueIsAdjusting() {
+ return isAdjusting;
+ }
+
+ public Adjustable getAdjustable() {
+ return (Adjustable) source;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * AdjustmentEvent e = new AdjustmentEvent(new Scrollbar(),
+ * AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
+ * AdjustmentEvent.UNIT_INCREMENT, 1);
+ * System.out.println(e);
+ */
+
+ String idString = (id == ADJUSTMENT_VALUE_CHANGED ?
+ "ADJUSTMENT_VALUE_CHANGED" : "unknown type"); //$NON-NLS-1$ //$NON-NLS-2$
+ String adjType = null;
+
+ switch (type) {
+ case UNIT_INCREMENT:
+ adjType = "UNIT_INCREMENT"; //$NON-NLS-1$
+ break;
+ case UNIT_DECREMENT:
+ adjType = "UNIT_DECREMENT"; //$NON-NLS-1$
+ break;
+ case BLOCK_INCREMENT:
+ adjType = "BLOCK_INCREMENT"; //$NON-NLS-1$
+ break;
+ case BLOCK_DECREMENT:
+ adjType = "BLOCK_DECREMENT"; //$NON-NLS-1$
+ break;
+ case TRACK:
+ adjType = "TRACK"; //$NON-NLS-1$
+ break;
+ default:
+ adjType = "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString + ",adjType=" + adjType + ",value=" + value + //$NON-NLS-1$ //$NON-NLS-2$
+ ",isAdjusting=" + isAdjusting); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/AdjustmentListener.java b/awt/java/awt/event/AdjustmentListener.java
new file mode 100644
index 0000000..ef7c378
--- /dev/null
+++ b/awt/java/awt/event/AdjustmentListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface AdjustmentListener extends EventListener {
+
+ public void adjustmentValueChanged(AdjustmentEvent e);
+
+}
diff --git a/awt/java/awt/event/ComponentAdapter.java b/awt/java/awt/event/ComponentAdapter.java
new file mode 100644
index 0000000..4f0bd90
--- /dev/null
+++ b/awt/java/awt/event/ComponentAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class ComponentAdapter implements ComponentListener {
+
+ public ComponentAdapter() {
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ }
+
+ public void componentResized(ComponentEvent e) {
+ }
+
+ public void componentShown(ComponentEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/ComponentEvent.java b/awt/java/awt/event/ComponentEvent.java
new file mode 100644
index 0000000..d0bca54
--- /dev/null
+++ b/awt/java/awt/event/ComponentEvent.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+
+public class ComponentEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 8101406823902992965L;
+
+ public static final int COMPONENT_FIRST = 100;
+
+ public static final int COMPONENT_LAST = 103;
+
+ public static final int COMPONENT_MOVED = 100;
+
+ public static final int COMPONENT_RESIZED = 101;
+
+ public static final int COMPONENT_SHOWN = 102;
+
+ public static final int COMPONENT_HIDDEN = 103;
+
+ public ComponentEvent(Component source, int id) {
+ super(source, id);
+ }
+
+ public Component getComponent() {
+ return (Component) source;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * ComponentEvent e = new ComponentEvent(new Button("Button"),
+ * ComponentEvent.COMPONENT_SHOWN);
+ * System.out.println(e);
+ */
+
+ String idString = null;
+ Component c = getComponent();
+
+ switch (id) {
+ case COMPONENT_MOVED:
+ idString = "COMPONENT_MOVED"; //$NON-NLS-1$
+ break;
+ case COMPONENT_RESIZED:
+ idString = "COMPONENT_RESIZED"; //$NON-NLS-1$
+ break;
+ case COMPONENT_SHOWN:
+ return "COMPONENT_SHOWN"; //$NON-NLS-1$
+ case COMPONENT_HIDDEN:
+ return "COMPONENT_HIDDEN"; //$NON-NLS-1$
+ default:
+ return "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString + " (" + c.getX() + "," + c.getY() + //$NON-NLS-1$ //$NON-NLS-2$
+ " " + c.getWidth()+ "x" + c.getHeight() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+}
diff --git a/awt/java/awt/event/ComponentListener.java b/awt/java/awt/event/ComponentListener.java
new file mode 100644
index 0000000..147e9e0
--- /dev/null
+++ b/awt/java/awt/event/ComponentListener.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ComponentListener extends EventListener {
+
+ public void componentHidden(ComponentEvent e);
+
+ public void componentMoved(ComponentEvent e);
+
+ public void componentResized(ComponentEvent e);
+
+ public void componentShown(ComponentEvent e);
+
+}
diff --git a/awt/java/awt/event/ContainerAdapter.java b/awt/java/awt/event/ContainerAdapter.java
new file mode 100644
index 0000000..12dc3de
--- /dev/null
+++ b/awt/java/awt/event/ContainerAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class ContainerAdapter implements ContainerListener {
+
+ public ContainerAdapter() {
+ }
+
+ public void componentAdded(ContainerEvent e) {
+ }
+
+ public void componentRemoved(ContainerEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/ContainerEvent.java b/awt/java/awt/event/ContainerEvent.java
new file mode 100644
index 0000000..1a1055c
--- /dev/null
+++ b/awt/java/awt/event/ContainerEvent.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+//???AWT: import java.awt.Container;
+
+public class ContainerEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = -4114942250539772041L;
+
+ public static final int CONTAINER_FIRST = 300;
+
+ public static final int CONTAINER_LAST = 301;
+
+ public static final int COMPONENT_ADDED = 300;
+
+ public static final int COMPONENT_REMOVED = 301;
+
+ private Component child;
+
+ public ContainerEvent(Component src, int id, Component child) {
+ super(src, id);
+ this.child = child;
+ }
+
+ public Component getChild() {
+ return child;
+ }
+
+ //???AWT
+ /*
+ public Container getContainer() {
+ return (Container) source;
+ }
+ */
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * ContainerEvent e = new ContainerEvent(new Panel(),
+ * ContainerEvent.COMPONENT_ADDED,
+ * new Button("Button"));
+ * System.out.println(e);
+ */
+
+ String idString = null;
+
+ switch (id) {
+ case COMPONENT_ADDED:
+ idString = "COMPONENT_ADDED"; //$NON-NLS-1$
+ break;
+ case COMPONENT_REMOVED:
+ idString = "COMPONENT_REMOVED"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString + ",child=" + child.getName()); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/ContainerListener.java b/awt/java/awt/event/ContainerListener.java
new file mode 100644
index 0000000..bf47664
--- /dev/null
+++ b/awt/java/awt/event/ContainerListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ContainerListener extends EventListener {
+
+ public void componentAdded(ContainerEvent e);
+
+ public void componentRemoved(ContainerEvent e);
+
+}
diff --git a/awt/java/awt/event/FocusAdapter.java b/awt/java/awt/event/FocusAdapter.java
new file mode 100644
index 0000000..3489e11
--- /dev/null
+++ b/awt/java/awt/event/FocusAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class FocusAdapter implements FocusListener {
+
+ public FocusAdapter() {
+ }
+
+ public void focusGained(FocusEvent e) {
+ }
+
+ public void focusLost(FocusEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/FocusEvent.java b/awt/java/awt/event/FocusEvent.java
new file mode 100644
index 0000000..1db5263
--- /dev/null
+++ b/awt/java/awt/event/FocusEvent.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+public class FocusEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = 523753786457416396L;
+
+ public static final int FOCUS_FIRST = 1004;
+
+ public static final int FOCUS_LAST = 1005;
+
+ public static final int FOCUS_GAINED = 1004;
+
+ public static final int FOCUS_LOST = 1005;
+
+ private boolean temporary;
+ private Component opposite;
+
+ public FocusEvent(Component source, int id) {
+ this(source, id, false);
+ }
+
+ public FocusEvent(Component source, int id, boolean temporary) {
+ this(source, id, temporary, null);
+ }
+
+ public FocusEvent(Component source, int id, boolean temporary, Component opposite) {
+ super(source, id);
+ this.temporary = temporary;
+ this.opposite = opposite;
+ }
+
+ public Component getOppositeComponent() {
+ return opposite;
+ }
+
+ public boolean isTemporary() {
+ return temporary;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * FocusEvent e = new FocusEvent(new Button("Button0"),
+ * FocusEvent.FOCUS_GAINED, false, new Button("Button1"));
+ * System.out.println(e);
+ */
+
+ String idString = null;
+
+ switch (id) {
+ case FOCUS_GAINED:
+ idString = "FOCUS_GAINED"; //$NON-NLS-1$
+ break;
+ case FOCUS_LOST:
+ idString = "FOCUS_LOST"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString +
+ (temporary ? ",temporary" : ",permanent") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",opposite=" + opposite); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/FocusListener.java b/awt/java/awt/event/FocusListener.java
new file mode 100644
index 0000000..ee98d90
--- /dev/null
+++ b/awt/java/awt/event/FocusListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface FocusListener extends EventListener {
+
+ public void focusGained(FocusEvent e);
+
+ public void focusLost(FocusEvent e);
+
+}
diff --git a/awt/java/awt/event/HierarchyBoundsAdapter.java b/awt/java/awt/event/HierarchyBoundsAdapter.java
new file mode 100644
index 0000000..24e3d9d
--- /dev/null
+++ b/awt/java/awt/event/HierarchyBoundsAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener {
+
+ public HierarchyBoundsAdapter() {
+ }
+
+ public void ancestorMoved(HierarchyEvent e) {
+ }
+
+ public void ancestorResized(HierarchyEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/HierarchyBoundsListener.java b/awt/java/awt/event/HierarchyBoundsListener.java
new file mode 100644
index 0000000..4288f52
--- /dev/null
+++ b/awt/java/awt/event/HierarchyBoundsListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface HierarchyBoundsListener extends EventListener {
+
+ public void ancestorMoved(HierarchyEvent e);
+
+ public void ancestorResized(HierarchyEvent e);
+
+}
diff --git a/awt/java/awt/event/HierarchyEvent.java b/awt/java/awt/event/HierarchyEvent.java
new file mode 100644
index 0000000..1881667
--- /dev/null
+++ b/awt/java/awt/event/HierarchyEvent.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+//???AWT: import java.awt.Container;
+
+public class HierarchyEvent extends AWTEvent {
+
+ private static final long serialVersionUID = -5337576970038043990L;
+
+ public static final int HIERARCHY_FIRST = 1400;
+
+ public static final int HIERARCHY_CHANGED = 1400;
+
+ public static final int ANCESTOR_MOVED = 1401;
+
+ public static final int ANCESTOR_RESIZED = 1402;
+
+ public static final int HIERARCHY_LAST = 1402;
+
+ public static final int PARENT_CHANGED = 1;
+
+ public static final int DISPLAYABILITY_CHANGED = 2;
+
+ public static final int SHOWING_CHANGED = 4;
+
+ //???AWT: private Container changedParent;
+ private Component changed;
+ private long changeFlag;
+
+ //???AWT
+ /*
+ public HierarchyEvent(Component source, int id, Component changed,
+ Container changedParent) {
+ this(source, id, changed, changedParent, 0l);
+ }
+ */
+
+ //???AWT
+ /*
+ public HierarchyEvent(Component source, int id, Component changed,
+ Container changedParent, long changeFlags) {
+ super(source, id);
+
+ this.changed = changed;
+ this.changedParent = changedParent;
+ this.changeFlag = changeFlags;
+ }
+ */
+ //???AWT: Fake constructor, should be as above.
+ public HierarchyEvent(Component source, int id, Component changed,
+ Object changedParent, long changeFlags) {
+ super(source, id);
+
+// this.changed = changed;
+// this.changedParent = changedParent;
+// this.changeFlag = changeFlags;
+ }
+
+ public Component getComponent() {
+ return (Component) source;
+ }
+
+ public long getChangeFlags() {
+ return changeFlag;
+ }
+
+ public Component getChanged() {
+ return changed;
+ }
+
+ //???AWT
+ /*
+ public Container getChangedParent() {
+ return changedParent;
+
+ }
+ */
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * HierarchyEvent e = new HierarchyEvent(new Button("Button"),
+ * HierarchyEvent.HIERARCHY_CHANGED,
+ * new Panel(), new Container());
+ * System.out.println(e);
+ */
+ String paramString = null;
+
+ switch (id) {
+ case HIERARCHY_CHANGED:
+ paramString = "HIERARCHY_CHANGED"; //$NON-NLS-1$
+ break;
+ case ANCESTOR_MOVED:
+ paramString = "ANCESTOR_MOVED"; //$NON-NLS-1$
+ break;
+ case ANCESTOR_RESIZED:
+ paramString = "ANCESTOR_RESIZED"; //$NON-NLS-1$
+ break;
+ default:
+ paramString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString += " ("; //$NON-NLS-1$
+
+ if (id == HIERARCHY_CHANGED) {
+ if ((changeFlag & PARENT_CHANGED) > 0) {
+ paramString += "PARENT_CHANGED,"; //$NON-NLS-1$
+ }
+ if ((changeFlag & DISPLAYABILITY_CHANGED) > 0) {
+ paramString += "DISPLAYABILITY_CHANGED,"; //$NON-NLS-1$
+ }
+ if ((changeFlag & SHOWING_CHANGED) > 0) {
+ paramString += "SHOWING_CHANGED,"; //$NON-NLS-1$
+ }
+ }
+
+ //???AWT
+ /*
+ return paramString + "changed=" + changed + //$NON-NLS-1$
+ ",changedParent=" + changedParent + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ */
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/HierarchyListener.java b/awt/java/awt/event/HierarchyListener.java
new file mode 100644
index 0000000..e01ba11
--- /dev/null
+++ b/awt/java/awt/event/HierarchyListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface HierarchyListener extends EventListener {
+
+ public void hierarchyChanged(HierarchyEvent e);
+
+}
diff --git a/awt/java/awt/event/InputEvent.java b/awt/java/awt/event/InputEvent.java
new file mode 100644
index 0000000..c98382d
--- /dev/null
+++ b/awt/java/awt/event/InputEvent.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+public abstract class InputEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = -2482525981698309786L;
+
+ public static final int SHIFT_MASK = 1;
+
+ public static final int CTRL_MASK = 2;
+
+ public static final int META_MASK = 4;
+
+ public static final int ALT_MASK = 8;
+
+ public static final int ALT_GRAPH_MASK = 32;
+
+ public static final int BUTTON1_MASK = 16;
+
+ public static final int BUTTON2_MASK = 8;
+
+ public static final int BUTTON3_MASK = 4;
+
+ public static final int SHIFT_DOWN_MASK = 64;
+
+ public static final int CTRL_DOWN_MASK = 128;
+
+ public static final int META_DOWN_MASK = 256;
+
+ public static final int ALT_DOWN_MASK = 512;
+
+ public static final int BUTTON1_DOWN_MASK = 1024;
+
+ public static final int BUTTON2_DOWN_MASK = 2048;
+
+ public static final int BUTTON3_DOWN_MASK = 4096;
+
+ public static final int ALT_GRAPH_DOWN_MASK = 8192;
+
+ private static final int DOWN_MASKS = SHIFT_DOWN_MASK | CTRL_DOWN_MASK |
+ META_DOWN_MASK | ALT_DOWN_MASK | BUTTON1_DOWN_MASK |
+ BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK | ALT_GRAPH_DOWN_MASK;
+
+ private long when;
+ private int modifiersEx;
+
+ public static String getModifiersExText(int modifiers/*Ex*/) {
+ return MouseEvent.addMouseModifiersExText(
+ KeyEvent.getKeyModifiersExText(modifiers), modifiers);
+ }
+
+ static int extractExFlags(int modifiers) {
+ int exFlags = modifiers & DOWN_MASKS;
+
+ if ((modifiers & SHIFT_MASK) != 0) {
+ exFlags |= SHIFT_DOWN_MASK;
+ }
+ if ((modifiers & CTRL_MASK) != 0) {
+ exFlags |= CTRL_DOWN_MASK;
+ }
+ if ((modifiers & META_MASK) != 0) {
+ exFlags |= META_DOWN_MASK;
+ }
+ if ((modifiers & ALT_MASK) != 0) {
+ exFlags |= ALT_DOWN_MASK;
+ }
+ if ((modifiers & ALT_GRAPH_MASK) != 0) {
+ exFlags |= ALT_GRAPH_DOWN_MASK;
+ }
+ if ((modifiers & BUTTON1_MASK) != 0) {
+ exFlags |= BUTTON1_DOWN_MASK;
+ }
+ if ((modifiers & BUTTON2_MASK) != 0) {
+ exFlags |= BUTTON2_DOWN_MASK;
+ }
+ if ((modifiers & BUTTON3_MASK) != 0) {
+ exFlags |= BUTTON3_DOWN_MASK;
+ }
+
+ return exFlags;
+ }
+
+ InputEvent(Component source, int id, long when, int modifiers) {
+ super(source, id);
+
+ this.when = when;
+ modifiersEx = extractExFlags(modifiers);
+ }
+
+ public int getModifiers() {
+ int modifiers = 0;
+
+ if ((modifiersEx & SHIFT_DOWN_MASK) != 0) {
+ modifiers |= SHIFT_MASK;
+ }
+ if ((modifiersEx & CTRL_DOWN_MASK) != 0) {
+ modifiers |= CTRL_MASK;
+ }
+ if ((modifiersEx & META_DOWN_MASK) != 0) {
+ modifiers |= META_MASK;
+ }
+ if ((modifiersEx & ALT_DOWN_MASK) != 0) {
+ modifiers |= ALT_MASK;
+ }
+ if ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0) {
+ modifiers |= ALT_GRAPH_MASK;
+ }
+ if ((modifiersEx & BUTTON1_DOWN_MASK) != 0) {
+ modifiers |= BUTTON1_MASK;
+ }
+ if ((modifiersEx & BUTTON2_DOWN_MASK) != 0) {
+ modifiers |= BUTTON2_MASK;
+ }
+ if ((modifiersEx & BUTTON3_DOWN_MASK) != 0) {
+ modifiers |= BUTTON3_MASK;
+ }
+
+ return modifiers;
+ }
+
+ public int getModifiersEx() {
+ return modifiersEx;
+ }
+
+ void setModifiers(int modifiers) {
+ modifiersEx = extractExFlags(modifiers);
+ }
+
+ public boolean isAltDown() {
+ return ((modifiersEx & ALT_DOWN_MASK) != 0);
+ }
+
+ public boolean isAltGraphDown() {
+ return ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0);
+ }
+
+ public boolean isControlDown() {
+ return ((modifiersEx & CTRL_DOWN_MASK) != 0);
+ }
+
+ public boolean isMetaDown() {
+ return ((modifiersEx & META_DOWN_MASK) != 0);
+ }
+
+ public boolean isShiftDown() {
+ return ((modifiersEx & SHIFT_DOWN_MASK) != 0);
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public void consume() {
+ super.consume();
+ }
+
+ @Override
+ public boolean isConsumed() {
+ return super.isConsumed();
+ }
+
+}
diff --git a/awt/java/awt/event/InputMethodEvent.java b/awt/java/awt/event/InputMethodEvent.java
new file mode 100644
index 0000000..a5cac4e
--- /dev/null
+++ b/awt/java/awt/event/InputMethodEvent.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.font.TextHitInfo;
+import java.text.AttributedCharacterIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class InputMethodEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 4727190874778922661L;
+
+ public static final int INPUT_METHOD_FIRST = 1100;
+
+ public static final int INPUT_METHOD_TEXT_CHANGED = 1100;
+
+ public static final int CARET_POSITION_CHANGED = 1101;
+
+ public static final int INPUT_METHOD_LAST = 1101;
+
+ private AttributedCharacterIterator text;
+ private TextHitInfo visiblePosition;
+ private TextHitInfo caret;
+ private int committedCharacterCount;
+ private long when;
+
+ public InputMethodEvent(Component src, int id,
+ TextHitInfo caret,
+ TextHitInfo visiblePos) {
+ this(src, id, null, 0, caret, visiblePos);
+ }
+
+ public InputMethodEvent(Component src, int id,
+ AttributedCharacterIterator text,
+ int commitedCharCount,
+ TextHitInfo caret,
+ TextHitInfo visiblePos) {
+ this(src, id, 0l, text, commitedCharCount, caret, visiblePos);
+ }
+
+ public InputMethodEvent(Component src, int id, long when,
+ AttributedCharacterIterator text,
+ int committedCharacterCount,
+ TextHitInfo caret,
+ TextHitInfo visiblePos) {
+ super(src, id);
+
+ if ((id < INPUT_METHOD_FIRST) || (id > INPUT_METHOD_LAST)) {
+ // awt.18E=Wrong event id
+ throw new IllegalArgumentException(Messages.getString("awt.18E")); //$NON-NLS-1$
+ }
+ if ((id == CARET_POSITION_CHANGED) && (text != null)) {
+ // awt.18F=Text must be null for CARET_POSITION_CHANGED
+ throw new IllegalArgumentException(Messages.getString("awt.18F")); //$NON-NLS-1$
+ }
+ if ((text != null) &&
+ ((committedCharacterCount < 0) ||
+ (committedCharacterCount >
+ (text.getEndIndex() - text.getBeginIndex())))) {
+ // awt.190=Wrong committedCharacterCount
+ throw new IllegalArgumentException(Messages.getString("awt.190")); //$NON-NLS-1$
+ }
+
+ this.when = when;
+ this.text = text;
+ this.caret = caret;
+ this.visiblePosition = visiblePos;
+ this.committedCharacterCount = committedCharacterCount;
+ }
+
+ public TextHitInfo getCaret() {
+ return caret;
+ }
+
+ public int getCommittedCharacterCount() {
+ return committedCharacterCount;
+ }
+
+ public AttributedCharacterIterator getText() {
+ return text;
+ }
+
+ public TextHitInfo getVisiblePosition() {
+ return visiblePosition;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public void consume() {
+ super.consume();
+ }
+
+ @Override
+ public boolean isConsumed() {
+ return super.isConsumed();
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * InputMethodEvent e = new InputMethodEvent(new Component(){},
+ * InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
+ * TextHitInfo.leading(1), TextHitInfo.trailing(2));
+ * System.out.println(e);
+ */
+ String typeString = null;
+
+ switch (id) {
+ case INPUT_METHOD_TEXT_CHANGED:
+ typeString = "INPUT_METHOD_TEXT_CHANGED"; //$NON-NLS-1$
+ break;
+ case CARET_POSITION_CHANGED:
+ typeString = "CARET_POSITION_CHANGED"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return typeString + ",text=" + text + //$NON-NLS-1$
+ ",commitedCharCount=" + committedCharacterCount + //$NON-NLS-1$
+ ",caret=" + caret + ",visiblePosition=" + visiblePosition; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
diff --git a/awt/java/awt/event/InputMethodListener.java b/awt/java/awt/event/InputMethodListener.java
new file mode 100644
index 0000000..0ab6918
--- /dev/null
+++ b/awt/java/awt/event/InputMethodListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface InputMethodListener extends EventListener {
+
+ public void caretPositionChanged(InputMethodEvent e);
+
+ public void inputMethodTextChanged(InputMethodEvent e);
+
+}
diff --git a/awt/java/awt/event/InvocationEvent.java b/awt/java/awt/event/InvocationEvent.java
new file mode 100644
index 0000000..59346ed4
--- /dev/null
+++ b/awt/java/awt/event/InvocationEvent.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.ActiveEvent;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class InvocationEvent extends AWTEvent implements ActiveEvent {
+
+ private static final long serialVersionUID = 436056344909459450L;
+
+ public static final int INVOCATION_FIRST = 1200;
+
+ public static final int INVOCATION_DEFAULT = 1200;
+
+ public static final int INVOCATION_LAST = 1200;
+
+ protected Runnable runnable;
+
+ protected Object notifier;
+
+ protected boolean catchExceptions;
+
+ private long when;
+ private Throwable throwable;
+
+ public InvocationEvent(Object source, Runnable runnable) {
+ this(source, runnable, null, false);
+ }
+
+ public InvocationEvent(Object source, Runnable runnable,
+ Object notifier, boolean catchExceptions) {
+ this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions);
+ }
+
+ protected InvocationEvent(Object source, int id, Runnable runnable,
+ Object notifier, boolean catchExceptions)
+ {
+ super(source, id);
+
+ // awt.18C=Cannot invoke null runnable
+ assert runnable != null : Messages.getString("awt.18C"); //$NON-NLS-1$
+
+ if (source == null) {
+ // awt.18D=Source is null
+ throw new IllegalArgumentException(Messages.getString("awt.18D")); //$NON-NLS-1$
+ }
+ this.runnable = runnable;
+ this.notifier = notifier;
+ this.catchExceptions = catchExceptions;
+
+ throwable = null;
+ when = System.currentTimeMillis();
+ }
+
+ public void dispatch() {
+ if (!catchExceptions) {
+ runAndNotify();
+ } else {
+ try {
+ runAndNotify();
+ } catch (Throwable t) {
+ throwable = t;
+ }
+ }
+ }
+
+ private void runAndNotify() {
+ if (notifier != null) {
+ synchronized(notifier) {
+ try {
+ runnable.run();
+ } finally {
+ notifier.notifyAll();
+ }
+ }
+ } else {
+ runnable.run();
+ }
+ }
+
+ public Exception getException() {
+ return (throwable != null && throwable instanceof Exception) ?
+ (Exception)throwable : null;
+ }
+
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * InvocationEvent e = new InvocationEvent(new Component(){},
+ * new Runnable() { public void run(){} });
+ * System.out.println(e);
+ */
+
+ return ((id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",runnable=" + runnable + //$NON-NLS-1$
+ ",notifier=" + notifier + //$NON-NLS-1$
+ ",catchExceptions=" + catchExceptions + //$NON-NLS-1$
+ ",when=" + when); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/ItemEvent.java b/awt/java/awt/event/ItemEvent.java
new file mode 100644
index 0000000..842da14
--- /dev/null
+++ b/awt/java/awt/event/ItemEvent.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.ItemSelectable;
+
+public class ItemEvent extends AWTEvent {
+
+ private static final long serialVersionUID = -608708132447206933L;
+
+ public static final int ITEM_FIRST = 701;
+
+ public static final int ITEM_LAST = 701;
+
+ public static final int ITEM_STATE_CHANGED = 701;
+
+ public static final int SELECTED = 1;
+
+ public static final int DESELECTED = 2;
+
+ private Object item;
+ private int stateChange;
+
+ public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) {
+ super(source, id);
+
+ this.item = item;
+ this.stateChange = stateChange;
+ }
+
+ public Object getItem() {
+ return item;
+ }
+
+ public int getStateChange() {
+ return stateChange;
+ }
+
+ public ItemSelectable getItemSelectable() {
+ return (ItemSelectable) source;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * Checkbox c = new Checkbox("Checkbox", true);
+ * ItemEvent e = new ItemEvent(c, ItemEvent.ITEM_STATE_CHANGED,
+ * c, ItemEvent.SELECTED);
+ * System.out.println(e);
+ */
+
+ String stateString = null;
+
+ switch (stateChange) {
+ case SELECTED:
+ stateString = "SELECTED"; //$NON-NLS-1$
+ break;
+ case DESELECTED:
+ stateString = "DESELECTED"; //$NON-NLS-1$
+ break;
+ default:
+ stateString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return ((id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",item=" + item + ",stateChange=" + stateString); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
diff --git a/awt/java/awt/event/ItemListener.java b/awt/java/awt/event/ItemListener.java
new file mode 100644
index 0000000..33633be
--- /dev/null
+++ b/awt/java/awt/event/ItemListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ItemListener extends EventListener {
+
+ public void itemStateChanged(ItemEvent e);
+
+}
diff --git a/awt/java/awt/event/KeyAdapter.java b/awt/java/awt/event/KeyAdapter.java
new file mode 100644
index 0000000..423b5c9
--- /dev/null
+++ b/awt/java/awt/event/KeyAdapter.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class KeyAdapter implements KeyListener {
+
+ public KeyAdapter() {
+ }
+
+ public void keyPressed(KeyEvent e) {
+ }
+
+ public void keyReleased(KeyEvent e) {
+ }
+
+ public void keyTyped(KeyEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/KeyEvent.java b/awt/java/awt/event/KeyEvent.java
new file mode 100644
index 0000000..056c64c
--- /dev/null
+++ b/awt/java/awt/event/KeyEvent.java
@@ -0,0 +1,681 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class KeyEvent extends InputEvent {
+
+ private static final long serialVersionUID = -2352130953028126954L;
+
+ public static final int KEY_FIRST = 400;
+
+ public static final int KEY_LAST = 402;
+
+ public static final int KEY_TYPED = 400;
+
+ public static final int KEY_PRESSED = 401;
+
+ public static final int KEY_RELEASED = 402;
+
+ public static final int VK_ENTER = 10;
+
+ public static final int VK_BACK_SPACE = 8;
+
+ public static final int VK_TAB = 9;
+
+ public static final int VK_CANCEL = 3;
+
+ public static final int VK_CLEAR = 12;
+
+ public static final int VK_SHIFT = 16;
+
+ public static final int VK_CONTROL = 17;
+
+ public static final int VK_ALT = 18;
+
+ public static final int VK_PAUSE = 19;
+
+ public static final int VK_CAPS_LOCK = 20;
+
+ public static final int VK_ESCAPE = 27;
+
+ public static final int VK_SPACE = 32;
+
+ public static final int VK_PAGE_UP = 33;
+
+ public static final int VK_PAGE_DOWN = 34;
+
+ public static final int VK_END = 35;
+
+ public static final int VK_HOME = 36;
+
+ public static final int VK_LEFT = 37;
+
+ public static final int VK_UP = 38;
+
+ public static final int VK_RIGHT = 39;
+
+ public static final int VK_DOWN = 40;
+
+ public static final int VK_COMMA = 44;
+
+ public static final int VK_MINUS = 45;
+
+ public static final int VK_PERIOD = 46;
+
+ public static final int VK_SLASH = 47;
+
+ public static final int VK_0 = 48;
+
+ public static final int VK_1 = 49;
+
+ public static final int VK_2 = 50;
+
+ public static final int VK_3 = 51;
+
+ public static final int VK_4 = 52;
+
+ public static final int VK_5 = 53;
+
+ public static final int VK_6 = 54;
+
+ public static final int VK_7 = 55;
+
+ public static final int VK_8 = 56;
+
+ public static final int VK_9 = 57;
+
+ public static final int VK_SEMICOLON = 59;
+
+ public static final int VK_EQUALS = 61;
+
+ public static final int VK_A = 65;
+
+ public static final int VK_B = 66;
+
+ public static final int VK_C = 67;
+
+ public static final int VK_D = 68;
+
+ public static final int VK_E = 69;
+
+ public static final int VK_F = 70;
+
+ public static final int VK_G = 71;
+
+ public static final int VK_H = 72;
+
+ public static final int VK_I = 73;
+
+ public static final int VK_J = 74;
+
+ public static final int VK_K = 75;
+
+ public static final int VK_L = 76;
+
+ public static final int VK_M = 77;
+
+ public static final int VK_N = 78;
+
+ public static final int VK_O = 79;
+
+ public static final int VK_P = 80;
+
+ public static final int VK_Q = 81;
+
+ public static final int VK_R = 82;
+
+ public static final int VK_S = 83;
+
+ public static final int VK_T = 84;
+
+ public static final int VK_U = 85;
+
+ public static final int VK_V = 86;
+
+ public static final int VK_W = 87;
+
+ public static final int VK_X = 88;
+
+ public static final int VK_Y = 89;
+
+ public static final int VK_Z = 90;
+
+ public static final int VK_OPEN_BRACKET = 91;
+
+ public static final int VK_BACK_SLASH = 92;
+
+ public static final int VK_CLOSE_BRACKET = 93;
+
+ public static final int VK_NUMPAD0 = 96;
+
+ public static final int VK_NUMPAD1 = 97;
+
+ public static final int VK_NUMPAD2 = 98;
+
+ public static final int VK_NUMPAD3 = 99;
+
+ public static final int VK_NUMPAD4 = 100;
+
+ public static final int VK_NUMPAD5 = 101;
+
+ public static final int VK_NUMPAD6 = 102;
+
+ public static final int VK_NUMPAD7 = 103;
+
+ public static final int VK_NUMPAD8 = 104;
+
+ public static final int VK_NUMPAD9 = 105;
+
+ public static final int VK_MULTIPLY = 106;
+
+ public static final int VK_ADD = 107;
+
+ public static final int VK_SEPARATER = 108;
+
+ public static final int VK_SEPARATOR = 108;
+
+ public static final int VK_SUBTRACT = 109;
+
+ public static final int VK_DECIMAL = 110;
+
+ public static final int VK_DIVIDE = 111;
+
+ public static final int VK_DELETE = 127;
+
+ public static final int VK_NUM_LOCK = 144;
+
+ public static final int VK_SCROLL_LOCK = 145;
+
+ public static final int VK_F1 = 112;
+
+ public static final int VK_F2 = 113;
+
+ public static final int VK_F3 = 114;
+
+ public static final int VK_F4 = 115;
+
+ public static final int VK_F5 = 116;
+
+ public static final int VK_F6 = 117;
+
+ public static final int VK_F7 = 118;
+
+ public static final int VK_F8 = 119;
+
+ public static final int VK_F9 = 120;
+
+ public static final int VK_F10 = 121;
+
+ public static final int VK_F11 = 122;
+
+ public static final int VK_F12 = 123;
+
+ public static final int VK_F13 = 61440;
+
+ public static final int VK_F14 = 61441;
+
+ public static final int VK_F15 = 61442;
+
+ public static final int VK_F16 = 61443;
+
+ public static final int VK_F17 = 61444;
+
+ public static final int VK_F18 = 61445;
+
+ public static final int VK_F19 = 61446;
+
+ public static final int VK_F20 = 61447;
+
+ public static final int VK_F21 = 61448;
+
+ public static final int VK_F22 = 61449;
+
+ public static final int VK_F23 = 61450;
+
+ public static final int VK_F24 = 61451;
+
+ public static final int VK_PRINTSCREEN = 154;
+
+ public static final int VK_INSERT = 155;
+
+ public static final int VK_HELP = 156;
+
+ public static final int VK_META = 157;
+
+ public static final int VK_BACK_QUOTE = 192;
+
+ public static final int VK_QUOTE = 222;
+
+ public static final int VK_KP_UP = 224;
+
+ public static final int VK_KP_DOWN = 225;
+
+ public static final int VK_KP_LEFT = 226;
+
+ public static final int VK_KP_RIGHT = 227;
+
+ public static final int VK_DEAD_GRAVE = 128;
+
+ public static final int VK_DEAD_ACUTE = 129;
+
+ public static final int VK_DEAD_CIRCUMFLEX = 130;
+
+ public static final int VK_DEAD_TILDE = 131;
+
+ public static final int VK_DEAD_MACRON = 132;
+
+ public static final int VK_DEAD_BREVE = 133;
+
+ public static final int VK_DEAD_ABOVEDOT = 134;
+
+ public static final int VK_DEAD_DIAERESIS = 135;
+
+ public static final int VK_DEAD_ABOVERING = 136;
+
+ public static final int VK_DEAD_DOUBLEACUTE = 137;
+
+ public static final int VK_DEAD_CARON = 138;
+
+ public static final int VK_DEAD_CEDILLA = 139;
+
+ public static final int VK_DEAD_OGONEK = 140;
+
+ public static final int VK_DEAD_IOTA = 141;
+
+ public static final int VK_DEAD_VOICED_SOUND = 142;
+
+ public static final int VK_DEAD_SEMIVOICED_SOUND = 143;
+
+ public static final int VK_AMPERSAND = 150;
+
+ public static final int VK_ASTERISK = 151;
+
+ public static final int VK_QUOTEDBL = 152;
+
+ public static final int VK_LESS = 153;
+
+ public static final int VK_GREATER = 160;
+
+ public static final int VK_BRACELEFT = 161;
+
+ public static final int VK_BRACERIGHT = 162;
+
+ public static final int VK_AT = 512;
+
+ public static final int VK_COLON = 513;
+
+ public static final int VK_CIRCUMFLEX = 514;
+
+ public static final int VK_DOLLAR = 515;
+
+ public static final int VK_EURO_SIGN = 516;
+
+ public static final int VK_EXCLAMATION_MARK = 517;
+
+ public static final int VK_INVERTED_EXCLAMATION_MARK = 518;
+
+ public static final int VK_LEFT_PARENTHESIS = 519;
+
+ public static final int VK_NUMBER_SIGN = 520;
+
+ public static final int VK_PLUS = 521;
+
+ public static final int VK_RIGHT_PARENTHESIS = 522;
+
+ public static final int VK_UNDERSCORE = 523;
+
+ public static final int VK_FINAL = 24;
+
+ public static final int VK_WINDOWS = 524;
+
+ public static final int VK_CONTEXT_MENU = 525;
+
+ public static final int VK_CONVERT = 28;
+
+ public static final int VK_NONCONVERT = 29;
+
+ public static final int VK_ACCEPT = 30;
+
+ public static final int VK_MODECHANGE = 31;
+
+ public static final int VK_KANA = 21;
+
+ public static final int VK_KANJI = 25;
+
+ public static final int VK_ALPHANUMERIC = 240;
+
+ public static final int VK_KATAKANA = 241;
+
+ public static final int VK_HIRAGANA = 242;
+
+ public static final int VK_FULL_WIDTH = 243;
+
+ public static final int VK_HALF_WIDTH = 244;
+
+ public static final int VK_ROMAN_CHARACTERS = 245;
+
+ public static final int VK_ALL_CANDIDATES = 256;
+
+ public static final int VK_PREVIOUS_CANDIDATE = 257;
+
+ public static final int VK_CODE_INPUT = 258;
+
+ public static final int VK_JAPANESE_KATAKANA = 259;
+
+ public static final int VK_JAPANESE_HIRAGANA = 260;
+
+ public static final int VK_JAPANESE_ROMAN = 261;
+
+ public static final int VK_KANA_LOCK = 262;
+
+ public static final int VK_INPUT_METHOD_ON_OFF = 263;
+
+ public static final int VK_CUT = 65489;
+
+ public static final int VK_COPY = 65485;
+
+ public static final int VK_PASTE = 65487;
+
+ public static final int VK_UNDO = 65483;
+
+ public static final int VK_AGAIN = 65481;
+
+ public static final int VK_FIND = 65488;
+
+ public static final int VK_PROPS = 65482;
+
+ public static final int VK_STOP = 65480;
+
+ public static final int VK_COMPOSE = 65312;
+
+ public static final int VK_ALT_GRAPH = 65406;
+
+ public static final int VK_BEGIN = 65368;
+
+ public static final int VK_UNDEFINED = 0;
+
+ public static final char CHAR_UNDEFINED = (char)(-1);
+
+ public static final int KEY_LOCATION_UNKNOWN = 0;
+
+ public static final int KEY_LOCATION_STANDARD = 1;
+
+ public static final int KEY_LOCATION_LEFT = 2;
+
+ public static final int KEY_LOCATION_RIGHT = 3;
+
+ public static final int KEY_LOCATION_NUMPAD = 4;
+
+ private int keyCode;
+ private char keyChar;
+ private int keyLocation;
+
+ public static String getKeyModifiersText(int modifiers) {
+ return getKeyModifiersExText(extractExFlags(modifiers));
+ }
+
+ static String getKeyModifiersExText(int modifiersEx) {
+ String text = ""; //$NON-NLS-1$
+
+ if ((modifiersEx & InputEvent.META_DOWN_MASK) != 0) {
+ text += Toolkit.getProperty("AWT.meta", "Meta"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.CTRL_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.control", "Ctrl"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.ALT_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.alt", "Alt"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.shift", "Shift"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.altGraph", "Alt Graph"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return text;
+ }
+
+ public static String getKeyText(int keyCode) {
+ String[] rawName = getPublicStaticFinalIntFieldName(keyCode); //$NON-NLS-1$
+
+ if ((rawName == null) || (rawName.length == 0)) {
+ return ("Unknown keyCode: " + (keyCode >= 0 ? "0x" : "-0x") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ Integer.toHexString(Math.abs(keyCode)));
+ }
+
+ String propertyName = getPropertyName(rawName);
+ String defaultName = getDefaultName(rawName);
+
+ return Toolkit.getProperty(propertyName, defaultName);
+ }
+
+ private static String getDefaultName(String[] rawName) {
+ String name = ""; //$NON-NLS-1$
+
+ for (int i = 0; true; i++) {
+ String part = rawName[i];
+
+ name += new String(new char[] {part.charAt(0)}).toUpperCase() +
+ part.substring(1).toLowerCase();
+
+ if (i == (rawName.length - 1)) {
+ break;
+ }
+ name += " "; //$NON-NLS-1$
+ }
+
+ return name;
+ }
+
+ private static String getPropertyName(String[] rawName) {
+ String name = rawName[0].toLowerCase();
+
+ for (int i = 1; i < rawName.length; i++) {
+ String part = rawName[i];
+
+ name += new String(new char[] {part.charAt(0)}).toUpperCase() +
+ part.substring(1).toLowerCase();
+ }
+
+ return ("AWT." + name); //$NON-NLS-1$
+ }
+
+ private static String[] getPublicStaticFinalIntFieldName(int value) {
+ Field[] allFields = KeyEvent.class.getDeclaredFields();
+
+ try {
+ for (Field field : allFields) {
+ Class<?> ssalc = field.getType();
+ int modifiers = field.getModifiers();
+
+ if (ssalc.isPrimitive() && ssalc.getName().equals("int") && //$NON-NLS-1$
+ Modifier.isFinal(modifiers) && Modifier.isPublic(modifiers) &&
+ Modifier.isStatic(modifiers))
+ {
+ if (field.getInt(null) == value){
+ final String name = field.getName();
+ final int prefixLength = name.indexOf("_") + 1;
+ return name.substring(prefixLength).split("_"); //$NON-NLS-1$
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return null;
+ }
+
+ @Deprecated
+ public KeyEvent(Component src, int id,
+ long when, int modifiers,
+ int keyCode) {
+ this(src, id, when, modifiers, keyCode,
+ (keyCode > (2 << 7) - 1) ? CHAR_UNDEFINED : (char) keyCode);
+ }
+
+ public KeyEvent(Component src, int id,
+ long when, int modifiers,
+ int keyCode, char keyChar) {
+ this(src, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN);
+ }
+
+ public KeyEvent(Component src, int id,
+ long when, int modifiers,
+ int keyCode, char keyChar,
+ int keyLocation) {
+ super(src, id, when, modifiers);
+
+ if (id == KEY_TYPED) {
+ if (keyCode != VK_UNDEFINED) {
+ // awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED
+ throw new IllegalArgumentException(Messages.getString("awt.191")); //$NON-NLS-1$
+ }
+ if (keyChar == CHAR_UNDEFINED) {
+ // awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED
+ throw new IllegalArgumentException(Messages.getString("awt.192")); //$NON-NLS-1$
+ }
+ }
+
+ if ((keyLocation < KEY_LOCATION_UNKNOWN)
+ || (keyLocation > KEY_LOCATION_NUMPAD)) {
+ // awt.297=Invalid keyLocation
+ throw new IllegalArgumentException(Messages.getString("awt.297")); //$NON-NLS-1$
+ }
+
+ this.keyChar = keyChar;
+ this.keyLocation = keyLocation;
+ this.keyCode = keyCode;
+ }
+
+ public int getKeyCode() {
+ return keyCode;
+ }
+
+ public void setKeyCode(int keyCode) {
+ this.keyCode = keyCode;
+ }
+
+ public char getKeyChar() {
+ return keyChar;
+ }
+
+ public void setKeyChar(char keyChar) {
+ this.keyChar = keyChar;
+ }
+
+ public int getKeyLocation() {
+ return keyLocation;
+ }
+
+ @Override
+ @Deprecated
+ public void setModifiers(int modifiers) {
+ super.setModifiers(modifiers);
+ }
+
+ public boolean isActionKey() {
+ return ((keyChar == CHAR_UNDEFINED) && (keyCode != VK_UNDEFINED) &&
+ !((keyCode == VK_ALT) || (keyCode == VK_ALT_GRAPH) ||
+ (keyCode == VK_CONTROL) || (keyCode == VK_META) || (keyCode == VK_SHIFT)));
+ }
+
+ @Override
+ public String paramString() {
+ /*
+ * The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * KeyEvent e = new KeyEvent(new Component() {},
+ * KeyEvent.KEY_PRESSED, 0,
+ * KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK,
+ * KeyEvent.VK_A, 'A', KeyEvent.KEY_LOCATION_STANDARD);
+ * System.out.println(e);
+ */
+
+ String idString = null;
+ String locString = null;
+ String paramString = null;
+ String keyCharString = (keyChar == '\n') ?
+ keyCharString = getKeyText(VK_ENTER) : "'" + keyChar + "'"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ switch (id) {
+ case KEY_PRESSED:
+ idString = "KEY_PRESSED"; //$NON-NLS-1$
+ break;
+ case KEY_RELEASED:
+ idString = "KEY_RELEASED"; //$NON-NLS-1$
+ break;
+ case KEY_TYPED:
+ idString = "KEY_TYPED"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ switch(keyLocation){
+ case KEY_LOCATION_STANDARD:
+ locString = "KEY_LOCATION_STANDARD"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_LEFT:
+ locString = "KEY_LOCATION_LEFT"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_RIGHT:
+ locString = "KEY_LOCATION_RIGHT"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_NUMPAD:
+ locString = "KEY_LOCATION_NUMPAD"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_UNKNOWN:
+ locString = "KEY_LOCATION_UNKNOWN"; //$NON-NLS-1$
+ break;
+ default:
+ locString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString = idString + ",keyCode=" + keyCode; //$NON-NLS-1$
+ if (isActionKey()) {
+ paramString += "," + getKeyText(keyCode); //$NON-NLS-1$
+ } else {
+ paramString += ",keyChar=" + keyCharString; //$NON-NLS-1$
+ }
+ if (getModifiersEx() > 0) {
+ paramString += ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$
+ ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$
+ }
+ paramString += ",keyLocation=" + locString; //$NON-NLS-1$
+
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/KeyListener.java b/awt/java/awt/event/KeyListener.java
new file mode 100644
index 0000000..f20fc90
--- /dev/null
+++ b/awt/java/awt/event/KeyListener.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface KeyListener extends EventListener {
+
+ public void keyPressed(KeyEvent e);
+
+ public void keyReleased(KeyEvent e);
+
+ public void keyTyped(KeyEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseAdapter.java b/awt/java/awt/event/MouseAdapter.java
new file mode 100644
index 0000000..4973956
--- /dev/null
+++ b/awt/java/awt/event/MouseAdapter.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class MouseAdapter implements MouseListener {
+
+ public MouseAdapter() {
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ public void mouseExited(MouseEvent e) {
+ }
+
+ public void mousePressed(MouseEvent e) {
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/MouseEvent.java b/awt/java/awt/event/MouseEvent.java
new file mode 100644
index 0000000..0b776f9
--- /dev/null
+++ b/awt/java/awt/event/MouseEvent.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.Toolkit;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class MouseEvent extends InputEvent {
+
+ private static final long serialVersionUID = -991214153494842848L;
+
+ public static final int MOUSE_FIRST = 500;
+
+ public static final int MOUSE_LAST = 507;
+
+ public static final int MOUSE_CLICKED = 500;
+
+ public static final int MOUSE_PRESSED = 501;
+
+ public static final int MOUSE_RELEASED = 502;
+
+ public static final int MOUSE_MOVED = 503;
+
+ public static final int MOUSE_ENTERED = 504;
+
+ public static final int MOUSE_EXITED = 505;
+
+ public static final int MOUSE_DRAGGED = 506;
+
+ public static final int MOUSE_WHEEL = 507;
+
+ public static final int NOBUTTON = 0;
+
+ public static final int BUTTON1 = 1;
+
+ public static final int BUTTON2 = 2;
+
+ public static final int BUTTON3 = 3;
+
+ private boolean popupTrigger;
+ private int clickCount;
+ private int button;
+ private int x;
+ private int y;
+
+ public static String getMouseModifiersText(int modifiers) {
+ final StringBuffer text = new StringBuffer();
+
+ if ((modifiers & META_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.meta", "Meta")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & SHIFT_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.shift", "Shift")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & CTRL_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.control", "Ctrl")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & ALT_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.alt", "Alt")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & ALT_GRAPH_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & BUTTON1_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.button1", "Button1")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & BUTTON2_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.button2", "Button2")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & BUTTON3_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.button3", "Button3")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ return text.length() == 0 ? text.toString() : text.substring(0, text
+ .length() - 1);
+ }
+
+ static String addMouseModifiersExText(String text, int modifiersEx) {
+ if ((modifiersEx & InputEvent.BUTTON1_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.button1", "Button1"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.BUTTON2_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.button2", "Button2"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.BUTTON3_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.button3", "Button3"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return text;
+ }
+
+ public MouseEvent(Component source, int id, long when,
+ int modifiers, int x, int y,
+ int clickCount, boolean popupTrigger) {
+ this(source, id, when, modifiers, x, y,
+ clickCount, popupTrigger, NOBUTTON);
+ }
+
+ public MouseEvent(Component source, int id, long when,
+ int modifiers, int x, int y,
+ int clickCount, boolean popupTrigger, int button) {
+ super(source, id, when, modifiers);
+
+ if ((button != NOBUTTON) && (button != BUTTON1) &&
+ (button != BUTTON2) && (button != BUTTON3)) {
+ // awt.18B=Invalid button value
+ throw new IllegalArgumentException(Messages.getString("awt.18B")); //$NON-NLS-1$
+ }
+
+ this.popupTrigger = popupTrigger;
+ this.clickCount = clickCount;
+ this.button = button;
+ this.x = x;
+ this.y = y;
+ }
+
+ public int getButton() {
+ return button;
+ }
+
+ public int getClickCount() {
+ return clickCount;
+ }
+
+ public Point getPoint() {
+ return new Point(x, y);
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public boolean isPopupTrigger() {
+ return popupTrigger;
+ }
+
+ public void translatePoint(int x, int y) {
+ this.x += x;
+ this.y += y;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * MouseEvent e = new MouseEvent(new Component(){},
+ * MouseEvent.MOUSE_PRESSED, 0,
+ * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK,
+ * 10, 20, 1, false, MouseEvent.BUTTON1);
+ * System.out.println(e);
+ */
+
+ String idString = null;
+ String paramString = null;
+
+ switch (id) {
+ case MOUSE_MOVED:
+ idString = "MOUSE_MOVED"; //$NON-NLS-1$
+ break;
+ case MOUSE_CLICKED:
+ idString = "MOUSE_CLICKED"; //$NON-NLS-1$
+ break;
+ case MOUSE_PRESSED:
+ idString = "MOUSE_PRESSED"; //$NON-NLS-1$
+ break;
+ case MOUSE_RELEASED:
+ idString = "MOUSE_RELEASED"; //$NON-NLS-1$
+ break;
+ case MOUSE_DRAGGED:
+ idString = "MOUSE_DRAGGED"; //$NON-NLS-1$
+ break;
+ case MOUSE_ENTERED:
+ idString = "MOUSE_ENTERED"; //$NON-NLS-1$
+ break;
+ case MOUSE_EXITED:
+ idString = "MOUSE_EXITED"; //$NON-NLS-1$
+ break;
+ case MOUSE_WHEEL:
+ idString = "MOUSE_WHEEL"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString = idString + ",(" + getX() + "," + getY() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ",button=" + button; //$NON-NLS-1$
+ if (getModifiersEx() > 0) {
+ paramString +=
+ ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$
+ ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$
+ }
+ paramString += ",clickCount=" + getClickCount(); //$NON-NLS-1$
+
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/MouseListener.java b/awt/java/awt/event/MouseListener.java
new file mode 100644
index 0000000..5d32b0f
--- /dev/null
+++ b/awt/java/awt/event/MouseListener.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface MouseListener extends EventListener {
+
+ public void mouseClicked(MouseEvent e);
+
+ public void mouseEntered(MouseEvent e);
+
+ public void mouseExited(MouseEvent e);
+
+ public void mousePressed(MouseEvent e);
+
+ public void mouseReleased(MouseEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseMotionAdapter.java b/awt/java/awt/event/MouseMotionAdapter.java
new file mode 100644
index 0000000..a4bebcc
--- /dev/null
+++ b/awt/java/awt/event/MouseMotionAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class MouseMotionAdapter implements MouseMotionListener {
+
+ public MouseMotionAdapter() {
+ }
+
+ public void mouseDragged(MouseEvent e) {
+ }
+
+ public void mouseMoved(MouseEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/MouseMotionListener.java b/awt/java/awt/event/MouseMotionListener.java
new file mode 100644
index 0000000..a5c11da
--- /dev/null
+++ b/awt/java/awt/event/MouseMotionListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface MouseMotionListener extends EventListener {
+
+ public void mouseDragged(MouseEvent e);
+
+ public void mouseMoved(MouseEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseWheelEvent.java b/awt/java/awt/event/MouseWheelEvent.java
new file mode 100644
index 0000000..d3ac9d8
--- /dev/null
+++ b/awt/java/awt/event/MouseWheelEvent.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+public class MouseWheelEvent extends MouseEvent {
+
+ private static final long serialVersionUID = -9187413581993563929L;
+
+ public static final int WHEEL_UNIT_SCROLL = 0;
+
+ public static final int WHEEL_BLOCK_SCROLL = 1;
+
+ private int wheelRotation;
+ private int scrollAmount;
+ private int scrollType;
+
+ public MouseWheelEvent(Component source, int id, long when, int modifiers,
+ int x, int y, int clickCount, boolean popupTrigger, int scrollType,
+ int scrollAmount, int wheelRotation) {
+ super(source, id, when, modifiers, x, y, clickCount, popupTrigger);
+
+ this.scrollType = scrollType;
+ this.scrollAmount = scrollAmount;
+ this.wheelRotation = wheelRotation;
+ }
+
+ public int getScrollAmount() {
+ return scrollAmount;
+ }
+
+ public int getScrollType() {
+ return scrollType;
+ }
+
+ public int getWheelRotation() {
+ return wheelRotation;
+ }
+
+ public int getUnitsToScroll() {
+ return (scrollAmount * wheelRotation);
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * MouseWheelEvent e = new MouseWheelEvent(new Component(){},
+ * MouseWheelEvent.MOUSE_WHEEL, 0,
+ * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK,
+ * 10, 20, 1, false, MouseWheelEvent.WHEEL_UNIT_SCROLL,
+ * 1, 3);
+ * System.out.println(e);
+ */
+
+ String paramString = super.paramString();
+ String typeString = null;
+
+ switch (scrollType) {
+ case WHEEL_UNIT_SCROLL:
+ typeString = "WHEEL_UNIT_SCROLL"; //$NON-NLS-1$
+ break;
+ case WHEEL_BLOCK_SCROLL:
+ typeString = "WHEEL_BLOCK_SCROLL"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString += ",scrollType=" + typeString + //$NON-NLS-1$
+ ",scrollAmount=" + scrollAmount + //$NON-NLS-1$
+ ",wheelRotation=" + wheelRotation; //$NON-NLS-1$
+
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/MouseWheelListener.java b/awt/java/awt/event/MouseWheelListener.java
new file mode 100644
index 0000000..8ca1c8b
--- /dev/null
+++ b/awt/java/awt/event/MouseWheelListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface MouseWheelListener extends EventListener {
+
+ public void mouseWheelMoved(MouseWheelEvent e);
+
+}
diff --git a/awt/java/awt/event/PaintEvent.java b/awt/java/awt/event/PaintEvent.java
new file mode 100644
index 0000000..d0573e1
--- /dev/null
+++ b/awt/java/awt/event/PaintEvent.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Rectangle;
+
+public class PaintEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = 1267492026433337593L;
+
+ public static final int PAINT_FIRST = 800;
+
+ public static final int PAINT_LAST = 801;
+
+ public static final int PAINT = 800;
+
+ public static final int UPDATE = 801;
+
+ private Rectangle updateRect;
+
+ public PaintEvent(Component source, int id, Rectangle updateRect) {
+ super(source, id);
+
+ this.updateRect = updateRect;
+ }
+
+ public Rectangle getUpdateRect() {
+ return updateRect;
+ }
+
+ public void setUpdateRect(Rectangle updateRect) {
+ this.updateRect = updateRect;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * PaintEvent e = new PaintEvent(new Component(){},
+ * PaintEvent.PAINT, new Rectangle(0, 0, 10, 20));
+ * System.out.println(e);
+ */
+
+ String typeString = null;
+
+ switch (id) {
+ case PAINT:
+ typeString = "PAINT"; //$NON-NLS-1$
+ break;
+ case UPDATE:
+ typeString = "UPDATE"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return typeString + ",updateRect=" + updateRect; //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/TextEvent.java b/awt/java/awt/event/TextEvent.java
new file mode 100644
index 0000000..e2bfd96
--- /dev/null
+++ b/awt/java/awt/event/TextEvent.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+public class TextEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 6269902291250941179L;
+
+ public static final int TEXT_FIRST = 900;
+
+ public static final int TEXT_LAST = 900;
+
+ public static final int TEXT_VALUE_CHANGED = 900;
+
+ public TextEvent(Object src, int id) {
+ super(src, id);
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * TextEvent e = new TextEvent(new Component(){},
+ * TextEvent.TEXT_VALUE_CHANGED);
+ * System.out.println(e);
+ */
+
+ return (id == TEXT_VALUE_CHANGED) ?
+ "TEXT_VALUE_CHANGED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
diff --git a/awt/java/awt/event/TextListener.java b/awt/java/awt/event/TextListener.java
new file mode 100644
index 0000000..6c5a671
--- /dev/null
+++ b/awt/java/awt/event/TextListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface TextListener extends EventListener {
+
+ public void textValueChanged(TextEvent e);
+
+}
+
diff --git a/awt/java/awt/event/WindowAdapter.java b/awt/java/awt/event/WindowAdapter.java
new file mode 100644
index 0000000..9d4b377
--- /dev/null
+++ b/awt/java/awt/event/WindowAdapter.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener {
+
+ public WindowAdapter() {
+ }
+
+ public void windowActivated(WindowEvent e) {
+ }
+
+ public void windowClosed(WindowEvent e) {
+ }
+
+ public void windowClosing(WindowEvent e) {
+ }
+
+ public void windowDeactivated(WindowEvent e) {
+ }
+
+ public void windowDeiconified(WindowEvent e) {
+ }
+
+ public void windowGainedFocus(WindowEvent e) {
+ }
+
+ public void windowIconified(WindowEvent e) {
+ }
+
+ public void windowLostFocus(WindowEvent e) {
+ }
+
+ public void windowOpened(WindowEvent e) {
+ }
+
+ public void windowStateChanged(WindowEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/WindowEvent.java b/awt/java/awt/event/WindowEvent.java
new file mode 100644
index 0000000..65a30e4
--- /dev/null
+++ b/awt/java/awt/event/WindowEvent.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+
+//???AWT
+//import java.awt.Window;
+//import java.awt.Frame;
+
+public class WindowEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = -1567959133147912127L;
+
+ public static final int WINDOW_FIRST = 200;
+
+ public static final int WINDOW_OPENED = 200;
+
+ public static final int WINDOW_CLOSING = 201;
+
+ public static final int WINDOW_CLOSED = 202;
+
+ public static final int WINDOW_ICONIFIED = 203;
+
+ public static final int WINDOW_DEICONIFIED = 204;
+
+ public static final int WINDOW_ACTIVATED = 205;
+
+ public static final int WINDOW_DEACTIVATED = 206;
+
+ public static final int WINDOW_GAINED_FOCUS = 207;
+
+ public static final int WINDOW_LOST_FOCUS = 208;
+
+ public static final int WINDOW_STATE_CHANGED = 209;
+
+ public static final int WINDOW_LAST = 209;
+
+ //???AWT: private Window oppositeWindow;
+ private int oldState;
+ private int newState;
+
+ //???AWT
+ /*
+ public WindowEvent(Window source, int id) {
+ this(source, id, null);
+ }
+
+ public WindowEvent(Window source, int id, Window opposite) {
+ this(source, id, opposite, Frame.NORMAL, Frame.NORMAL);
+ }
+
+ public WindowEvent(Window source, int id, int oldState, int newState) {
+ this(source, id, null, oldState, newState);
+ }
+
+ public WindowEvent(Window source, int id, Window opposite,
+ int oldState, int newState) {
+ super(source, id);
+
+ oppositeWindow = opposite;
+ this.oldState = oldState;
+ this.newState = newState;
+ }
+ */
+ //???AWT: Fake constructor
+ public WindowEvent() {
+ super(null, 0);
+ }
+
+ public int getNewState() {
+ return newState;
+ }
+
+ public int getOldState() {
+ return oldState;
+ }
+
+ //???AWT
+ /*
+ public Window getOppositeWindow() {
+ return oppositeWindow;
+ }
+
+ public Window getWindow() {
+ return (Window) source;
+ }
+ */
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * WindowEvent e = new WindowEvent(new Frame(),
+ * WindowEvent.WINDOW_OPENED);
+ * System.out.println(e);
+ */
+
+ String typeString = null;
+
+ switch (id) {
+ case WINDOW_OPENED:
+ typeString = "WINDOW_OPENED"; //$NON-NLS-1$
+ break;
+ case WINDOW_CLOSING:
+ typeString = "WINDOW_CLOSING"; //$NON-NLS-1$
+ break;
+ case WINDOW_CLOSED:
+ typeString = "WINDOW_CLOSED"; //$NON-NLS-1$
+ break;
+ case WINDOW_ICONIFIED:
+ typeString = "WINDOW_ICONIFIED"; //$NON-NLS-1$
+ break;
+ case WINDOW_DEICONIFIED:
+ typeString = "WINDOW_DEICONIFIED"; //$NON-NLS-1$
+ break;
+ case WINDOW_ACTIVATED:
+ typeString = "WINDOW_ACTIVATED"; //$NON-NLS-1$
+ break;
+ case WINDOW_DEACTIVATED:
+ typeString = "WINDOW_DEACTIVATED"; //$NON-NLS-1$
+ break;
+ case WINDOW_GAINED_FOCUS:
+ typeString = "WINDOW_GAINED_FOCUS"; //$NON-NLS-1$
+ break;
+ case WINDOW_LOST_FOCUS:
+ typeString = "WINDOW_LOST_FOCUS"; //$NON-NLS-1$
+ break;
+ case WINDOW_STATE_CHANGED:
+ typeString = "WINDOW_STATE_CHANGED"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ //???AWT
+ /*
+ return typeString + ",opposite=" + oppositeWindow + //$NON-NLS-1$
+ ",oldState=" + oldState + ",newState=" + newState; //$NON-NLS-1$ //$NON-NLS-2$
+ */
+ return typeString;
+ }
+
+}
diff --git a/awt/java/awt/event/WindowFocusListener.java b/awt/java/awt/event/WindowFocusListener.java
new file mode 100644
index 0000000..e0200f2
--- /dev/null
+++ b/awt/java/awt/event/WindowFocusListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface WindowFocusListener extends EventListener {
+
+ public void windowGainedFocus(WindowEvent e);
+
+ public void windowLostFocus(WindowEvent e);
+
+}
diff --git a/awt/java/awt/event/WindowListener.java b/awt/java/awt/event/WindowListener.java
new file mode 100644
index 0000000..20a2b08
--- /dev/null
+++ b/awt/java/awt/event/WindowListener.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface WindowListener extends EventListener {
+
+ public void windowActivated(WindowEvent e);
+
+ public void windowClosed(WindowEvent e);
+
+ public void windowClosing(WindowEvent e);
+
+ public void windowDeactivated(WindowEvent e);
+
+ public void windowDeiconified(WindowEvent e);
+
+ public void windowIconified(WindowEvent e);
+
+ public void windowOpened(WindowEvent e);
+
+}
diff --git a/awt/java/awt/event/WindowStateListener.java b/awt/java/awt/event/WindowStateListener.java
new file mode 100644
index 0000000..12dbc20
--- /dev/null
+++ b/awt/java/awt/event/WindowStateListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface WindowStateListener extends EventListener {
+
+ public void windowStateChanged(WindowEvent e);
+
+}
+
diff --git a/awt/java/awt/font/FontRenderContext.java b/awt/java/awt/font/FontRenderContext.java
new file mode 100644
index 0000000..766300d
--- /dev/null
+++ b/awt/java/awt/font/FontRenderContext.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * The FontRenderContext class contains the information
+ * about text measurement. Anti-aliasing and fractional-metrics
+ * modes are defined by an application and affect the size of
+ * a character.
+ */
+public class FontRenderContext {
+
+ // Affine transform of this mode
+ /** The transform. */
+ private AffineTransform transform;
+
+ // Is the anti-aliased mode used
+ /** The anti aliased. */
+ private boolean fAntiAliased;
+
+ // Is the fractional metrics used
+ /** The fractional metrics. */
+ private boolean fFractionalMetrics;
+
+
+ /**
+ * Instantiates a new FontRenderContext object with the specified
+ * AffineTransform, anti-aliasing and fractional metrics flags.
+ *
+ * @param trans the AffineTransform.
+ * @param antiAliased the anti-aliasing flag.
+ * @param usesFractionalMetrics the fractional metrics flag.
+ */
+ public FontRenderContext(AffineTransform trans, boolean antiAliased,
+ boolean usesFractionalMetrics) {
+ if (trans != null){
+ transform = new AffineTransform(trans);
+ }
+ fAntiAliased = antiAliased;
+ fFractionalMetrics = usesFractionalMetrics;
+ }
+
+ /**
+ * Instantiates a new FontRenderContext object.
+ */
+ protected FontRenderContext() {
+ }
+
+ /**
+ * Compares the specified Object with current FontRenderContext object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is equal to current
+ * FontRenderContext object.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null) {
+ try {
+ return equals((FontRenderContext) obj);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * Gets the transform which is used for scaling typographical points
+ * to pixels in this FontRenderContext.
+ *
+ * @return the AffineTransform which is used for scaling typographical
+ * points to pixels in this FontRenderContext.
+ */
+ public AffineTransform getTransform() {
+ if (transform != null){
+ return new AffineTransform(transform);
+ }
+ return new AffineTransform();
+ }
+
+ /**
+ * Compares the specified FontRenderContext object with current
+ * FontRenderContext.
+ *
+ * @param frc the FontRenderContext object to be compared.
+ *
+ * @return true, if the specified FontRenderContext object is
+ * equal to current FontRenderContext.
+ */
+ public boolean equals(FontRenderContext frc) {
+ if (this == frc){
+ return true;
+ }
+
+ if (frc == null){
+ return false;
+ }
+
+ if (!frc.getTransform().equals(this.getTransform()) &&
+ !frc.isAntiAliased() == this.fAntiAliased &&
+ !frc.usesFractionalMetrics() == this.fFractionalMetrics){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the text fractional metrics are used in
+ * this FontRenderContext.
+ *
+ * @return true, if the text fractional metrics are used in
+ * this FontRenderContext, false otherwise.
+ */
+ public boolean usesFractionalMetrics() {
+ return this.fFractionalMetrics;
+ }
+
+ /**
+ * Returns true if anti-aliasing is used in this FontRenderContext.
+ *
+ * @return true, if is anti-aliasing is used in this FontRenderContext,
+ * false otherwise.
+ */
+ public boolean isAntiAliased() {
+ return this.fAntiAliased;
+ }
+
+ /**
+ * Returns hash code of the FontRenderContext object.
+ *
+ * @return the hash code of the FontRenderContext object.
+ */
+ @Override
+ public int hashCode() {
+ return this.getTransform().hashCode() ^
+ new Boolean(this.fFractionalMetrics).hashCode() ^
+ new Boolean(this.fAntiAliased).hashCode();
+ }
+
+}
+
diff --git a/awt/java/awt/font/GlyphJustificationInfo.java b/awt/java/awt/font/GlyphJustificationInfo.java
new file mode 100644
index 0000000..4c3e02e
--- /dev/null
+++ b/awt/java/awt/font/GlyphJustificationInfo.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GlyphJustificationInfo class provides information about
+ * the glyph's justification properties. There are four justification
+ * properties: weight, priority, absorb, and limit.
+ * <p>
+ * There are two sets of metrics: growing and shrinking.
+ * Growing metrics are used when the glyphs are to be spread apart
+ * to fit a larger width. Shrinking metrics are used when the glyphs
+ * are to be moved together to fit a smaller width.
+ */
+public final class GlyphJustificationInfo {
+
+ /**
+ * The Constant PRIORITY_KASHIDA indicates the highest
+ * justification priority.
+ */
+ public static final int PRIORITY_KASHIDA = 0;
+
+ /**
+ * The Constant PRIORITY_WHITESPACE indicates the second highest
+ * justification priority.
+ */
+ public static final int PRIORITY_WHITESPACE = 1;
+
+ /**
+ * The Constant PRIORITY_INTERCHAR indicates the second lowest
+ * justification priority.
+ */
+ public static final int PRIORITY_INTERCHAR = 2;
+
+ /**
+ * The Constant PRIORITY_NONE indicates the lowest justification
+ * priority.
+ */
+ public static final int PRIORITY_NONE = 3;
+
+ /**
+ * The grow absorb flag indicates if this glyph absorbs all extra
+ * space at this and lower priority levels when it grows.
+ */
+ public final boolean growAbsorb;
+
+ /**
+ * The grow left limit value represents the maximum value by which
+ * the left side of this glyph grows.
+ */
+ public final float growLeftLimit;
+
+ /**
+ * The grow right limit value repesents the maximum value by which
+ * the right side of this glyph grows.
+ */
+ public final float growRightLimit;
+
+ /**
+ * The grow priority value represents the priority level of this
+ * glyph as it is growing.
+ */
+ public final int growPriority;
+
+ /**
+ * The shrink absorb fleg indicates this glyph absorbs all remaining
+ * shrinkage at this and lower priority levels as it shrinks.
+ */
+ public final boolean shrinkAbsorb;
+
+ /**
+ * The shrink left limit value represents the maximum value by which
+ * the left side of this glyph shrinks.
+ */
+ public final float shrinkLeftLimit;
+
+ /**
+ * The shrink right limit value represents the maximum value by which
+ * the right side of this glyph shrinks.
+ */
+ public final float shrinkRightLimit;
+
+ /**
+ * The shrink priority represents the glyth's priority level
+ * as it is shrinking.
+ */
+ public final int shrinkPriority;
+
+ /**
+ * The weight of the glyph.
+ */
+ public final float weight;
+
+ /**
+ * Instantiates a new GlyphJustificationInfo object which contains
+ * glyph's justification properties.
+ *
+ * @param weight the weight of glyph.
+ * @param growAbsorb indicates if this glyph contais all space
+ * at this priority and lower priority levels when it grows.
+ * @param growPriority indicates the priority level of this glyph
+ * when it grows.
+ * @param growLeftLimit indicates the maximum value of which the
+ * left side of this glyph can grow.
+ * @param growRightLimit the maximum value of which the right side of
+ * this glyph can grow.
+ * @param shrinkAbsorb indicates if this glyph contains all remaining
+ * shrinkage at this and lower priority levels when it shrinks.
+ * @param shrinkPriority indicates the glyph's priority level when
+ * it shrinks.
+ * @param shrinkLeftLimit indicates the maximum value of which
+ * the left side of this glyph can shrink.
+ * @param shrinkRightLimit indicates the maximum amount by which
+ * the right side of this glyph can shrink.
+ */
+ public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority,
+ float growLeftLimit, float growRightLimit, boolean shrinkAbsorb,
+ int shrinkPriority, float shrinkLeftLimit, float shrinkRightLimit) {
+
+ if (weight < 0) {
+ // awt.19C=weight must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.19C")); //$NON-NLS-1$
+ }
+ this.weight = weight;
+
+ if (growLeftLimit < 0) {
+ // awt.19D=growLeftLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.19D")); //$NON-NLS-1$
+ }
+ this.growLeftLimit = growLeftLimit;
+
+ if (growRightLimit < 0) {
+ // awt.19E=growRightLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.19E")); //$NON-NLS-1$
+ }
+ this.growRightLimit = growRightLimit;
+
+ if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) {
+ // awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+ throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$
+ }
+ this.shrinkPriority = shrinkPriority;
+
+ if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) {
+ // awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+ throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$
+ }
+ this.growPriority = growPriority;
+
+ if (shrinkLeftLimit < 0) {
+ // awt.201=shrinkLeftLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.201")); //$NON-NLS-1$
+ }
+ this.shrinkLeftLimit = shrinkLeftLimit;
+
+ if (shrinkRightLimit < 0) {
+ // awt.202=shrinkRightLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.202")); //$NON-NLS-1$
+ }
+ this.shrinkRightLimit = shrinkRightLimit;
+
+ this.shrinkAbsorb = shrinkAbsorb;
+ this.growAbsorb = growAbsorb;
+ }
+}
diff --git a/awt/java/awt/font/GlyphMetrics.java b/awt/java/awt/font/GlyphMetrics.java
new file mode 100644
index 0000000..d96ef18
--- /dev/null
+++ b/awt/java/awt/font/GlyphMetrics.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The GlyphMetrics class provides information about the size and shape
+ * of a single glyph.
+ * Each glyph has information to specify whether its baseline is horizontal
+ * or vertical as well as information on how it interacts with
+ * other characters in a text, given as one of the
+ * following types: STANDARD, LIGATURE, COMBINING, or COMPONENT.
+ */
+public final class GlyphMetrics {
+
+ // advance width of the glyph character cell
+ /** The advance x. */
+ private float advanceX;
+
+ // advance height of the glyph character cell
+ /** The advance y. */
+ private float advanceY;
+
+ // flag if the glyph horizontal
+ /** The horizontal. */
+ private boolean horizontal;
+
+ // glyph type code
+ /** The glyph type. */
+ private byte glyphType;
+
+ // bounding box for outline of the glyph
+ /** The bounds. */
+ private Rectangle2D.Float bounds;
+
+ /**
+ * The Constant STANDARD indicates a glyph that represents a single
+ * character.
+ */
+ public static final byte STANDARD = 0;
+
+ /**
+ * The Constant LIGATURE indicates a glyph that represents multiple
+ * characters as a ligature.
+ */
+ public static final byte LIGATURE = 1;
+
+ /**
+ * The Constant COMBINING indicates a glyph which has no caret position
+ * between glyphs (for example umlaut).
+ */
+ public static final byte COMBINING = 2;
+
+ /**
+ * The Constant COMPONENT indicates a glyph with no corresponding character
+ * in the backing store.
+ */
+ public static final byte COMPONENT = 3;
+
+ /**
+ * The Constant WHITESPACE indicates a glyph without visual
+ * representation.
+ */
+ public static final byte WHITESPACE = 4;
+
+ /**
+ * Instantiates a new GlyphMetrics object with the specified parameters.
+ *
+ * @param horizontal specifies if metrics are for a horizontal baseline
+ * (true value), or a vertical baseline (false value).
+ * @param advanceX the X component of the glyph's advance.
+ * @param advanceY the Y component of the glyph's advance.
+ * @param bounds the glyph's bounds.
+ * @param glyphType the glyph's type.
+ */
+ public GlyphMetrics(boolean horizontal, float advanceX, float advanceY,
+ Rectangle2D bounds, byte glyphType) {
+ this.horizontal = horizontal;
+ this.advanceX = advanceX;
+ this.advanceY = advanceY;
+
+ this.bounds = new Rectangle2D.Float();
+ this.bounds.setRect(bounds);
+
+ this.glyphType = glyphType;
+ }
+
+ /**
+ * Instantiates a new horizontal GlyphMetrics with the specified parameters.
+ *
+ * @param advanceX the X component of the glyph's advance.
+ * @param bounds the glyph's bounds.
+ * @param glyphType the glyph's type.
+ */
+ public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) {
+ this.advanceX = advanceX;
+ this.advanceY = 0;
+
+ this.horizontal = true;
+
+ this.bounds = new Rectangle2D.Float();
+ this.bounds.setRect(bounds);
+
+ this.glyphType = glyphType;
+ }
+
+ /**
+ * Gets the glyph's bounds.
+ *
+ * @return glyph's bounds.
+ */
+ public Rectangle2D getBounds2D() {
+ return (Rectangle2D.Float) this.bounds.clone();
+ }
+
+ /**
+ * Checks if this glyph is whitespace or not.
+ *
+ * @return true, if this glyph is whitespace, false otherwise.
+ */
+ public boolean isWhitespace() {
+ return ((this.glyphType & 4) == WHITESPACE);
+ }
+
+ /**
+ * Checks if this glyph is standard or not.
+ *
+ * @return true, if this glyph is standard, false otherwise.
+ */
+ public boolean isStandard() {
+ return ((this.glyphType & 3) == STANDARD);
+ }
+
+ /**
+ * Checks if this glyph is ligature or not.
+ *
+ * @return true, if this glyph is ligature, false otherwise.
+ */
+ public boolean isLigature() {
+ return ((this.glyphType & 3) == LIGATURE);
+ }
+
+ /**
+ * Checks if this glyph is component or not.
+ *
+ * @return true, if this glyph is component, false otherwise.
+ */
+ public boolean isComponent() {
+ return ((this.glyphType & 3) == COMPONENT);
+ }
+
+ /**
+ * Checks if this glyph is combining or not.
+ *
+ * @return true, if this glyph is combining, false otherwise.
+ */
+ public boolean isCombining() {
+ return ((this.glyphType & 3) == COMBINING);
+ }
+
+ /**
+ * Gets the glyph's type.
+ *
+ * @return the glyph's type.
+ */
+ public int getType() {
+ return this.glyphType;
+ }
+
+ /**
+ * Gets the distance from the right (for horizontal) or
+ * bottom (for vertical) of the glyph bounds to the advance.
+ *
+ * @return the distance from the right (for horizontal) or
+ * bottom (for vertical) of the glyph bounds to the advance.
+ */
+ public float getRSB() {
+ if (this.horizontal) {
+ return this.advanceX - this.bounds.x - (float)this.bounds.getWidth();
+ }
+ return this.advanceY - this.bounds.y - (float)this.bounds.getHeight();
+ }
+
+ /**
+ * Gets the distance from 0, 0 to the left (for horizontal)
+ * or top (for vertical) of the glyph bounds.
+ *
+ * @return the distance from 0, 0 to the left (for horizontal)
+ * or top (for vertical) of the glyph bounds.
+ */
+ public float getLSB() {
+ if (this.horizontal) {
+ return this.bounds.x;
+ }
+ return this.bounds.y;
+ }
+
+ /**
+ * Gets the Y component of the glyph's advance.
+ *
+ * @return the Y component of the glyph's advance.
+ */
+ public float getAdvanceY() {
+ return this.advanceY;
+ }
+
+ /**
+ * Gets the X component of the glyph's advance.
+ *
+ * @return the X component of the glyph's advance.
+ */
+ public float getAdvanceX() {
+ return this.advanceX;
+ }
+
+ /**
+ * Gets the glyph's advance along the baseline.
+ *
+ * @return the glyph's advance.
+ */
+ public float getAdvance() {
+ if (this.horizontal) {
+ return this.advanceX;
+ }
+ return this.advanceY;
+ }
+
+}
+
diff --git a/awt/java/awt/font/GlyphVector.java b/awt/java/awt/font/GlyphVector.java
new file mode 100644
index 0000000..b3c9406
--- /dev/null
+++ b/awt/java/awt/font/GlyphVector.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The GlyphVector class contains a collection of glyphs with geometric
+ * information and each glyph's location. Each GlyphVector can be associated
+ * with only one Font. GlyphVector contains the following properties for
+ * each glyph:
+ * <ul>
+ * <li>the glyph position;</li>
+ * <li>the transform of the glyph;</li>
+ * <li>the metrics of the glyph in the context of the GlyphVector.</li>
+ * </ul>
+ */
+public abstract class GlyphVector implements Cloneable {
+
+ /**
+ * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector
+ * has per-glyph transforms.
+ */
+ public static final int FLAG_HAS_TRANSFORMS = 1;
+
+ /**
+ * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that
+ * the GlyphVector has per-glyph position adjustments.
+ */
+ public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2;
+
+ /**
+ * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a
+ * right to left run direction.
+ */
+ public static final int FLAG_RUN_RTL = 4;
+
+ /**
+ * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector
+ * has a complex glyph to char mapping.
+ */
+ public static final int FLAG_COMPLEX_GLYPHS = 8;
+
+ /**
+ * The Constant FLAG_MASK indicates a mask for supported flags
+ * from getLayoutFlags.
+ */
+ public static final int FLAG_MASK = 15; // (|) mask of other flags
+
+ /**
+ * Instantiates a new GlyphVector.
+ */
+ public GlyphVector() {
+ }
+
+ /**
+ * Gets the pixel bounds of the GlyphVector when rendered
+ * at the specified location with the specified FontRenderContext.
+ *
+ * @param frc the FontRenderContext.
+ * @param x the X coordinate of the GlyphVector's location.
+ * @param y the Y coordinate of the GlyphVector's location.
+ *
+ * @return the pixel bounds
+ */
+ public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {
+ // default implementation - integer Rectangle, that encloses visual
+ // bounds rectangle
+ Rectangle2D visualRect = getVisualBounds();
+
+ int minX = (int)Math.floor(visualRect.getMinX() + x);
+ int minY = (int)Math.floor(visualRect.getMinY() + y);
+ int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX;
+ int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY;
+
+ return new Rectangle(minX, minY, width, height);
+ }
+
+ /**
+ * Gets the pixel bounds of the glyph with the specified index in
+ * this GlyphVector which is rendered with the specified
+ * FontRenderContext at the specified location.
+ *
+ * @param index the glyph index in this GlyphVector.
+ * @param frc the FontRenderContext.
+ * @param x the X coordinate of the GlyphVector's location.
+ * @param y the Y coordinate of the GlyphVector's location.
+ *
+ * @return a Rectangle bounds.
+ */
+ public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc,
+ float x, float y) {
+ Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D();
+
+ int minX = (int)Math.floor(visualRect.getMinX() + x);
+ int minY = (int)Math.floor(visualRect.getMinY() + y);
+ int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX;
+ int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY;
+
+ return new Rectangle(minX, minY, width, height);
+ }
+
+ /**
+ * Gets the visual bounds of the GlyphVector.
+ *
+ * @return the visual bounds of the GlyphVector.
+ */
+ public abstract Rectangle2D getVisualBounds();
+
+ /**
+ * Gets the logical bounds of the GlyphVector.
+ *
+ * @return the logical bounds of the GlyphVector.
+ */
+ public abstract Rectangle2D getLogicalBounds();
+
+ /**
+ * Sets the position of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ * @param newPos the new position of the glyph at the specified glyphIndex.
+ */
+ public abstract void setGlyphPosition(int glyphIndex, Point2D newPos);
+
+ /**
+ * Gets the position of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ *
+ * @return the position of the specified glyph in this GlyphVector.
+ */
+ public abstract Point2D getGlyphPosition(int glyphIndex);
+
+ /**
+ * Sets the affine transform to a glyph with the specified index
+ * in this GlyphVector.
+ *
+ * @param glyphIndex the glyth index in this GlyphVector.
+ * @param trans the AffineTransform to be assigned to the
+ * specified glyph.
+ */
+ public abstract void setGlyphTransform(int glyphIndex,
+ AffineTransform trans);
+
+ /**
+ * Gets the transform of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ *
+ * @return the new transform of the glyph.
+ */
+ public abstract AffineTransform getGlyphTransform(int glyphIndex);
+
+ /**
+ * Compares this GlyphVector with the specified GlyphVector objects.
+ *
+ * @param glyphVector the GlyphVector object to be compared.
+ *
+ * @return true, if this GlyphVector is equal to the specified GlyphVector
+ * object, false otherwise.
+ */
+ public abstract boolean equals(GlyphVector glyphVector);
+
+ /**
+ * Gets the metrics of the glyph with the specified index
+ * in this GlyphVector.
+ *
+ * @param glyphIndex index in this GlyphVector.
+ *
+ * @return the metrics of the glyph with the specified index
+ * in this GlyphVector.
+ */
+ public abstract GlyphMetrics getGlyphMetrics(int glyphIndex);
+
+ /**
+ * Gets the justification information of the glyph
+ * whose index is specified.
+ *
+ * @param glyphIndex the glyph index.
+ *
+ * @return the GlyphJustificationInfo for the specified glyph.
+ */
+ public abstract GlyphJustificationInfo getGlyphJustificationInfo(
+ int glyphIndex);
+
+ /**
+ * Gets the FontRenderContext of this GlyphVector.
+ *
+ * @return the FontRenderContext of this GlyphVector.
+ */
+ public abstract FontRenderContext getFontRenderContext();
+
+ /**
+ * Gets a Shape object which defines the visual representation
+ * of the specified glyph in this GlyphVector, translated a
+ * distance of x in the X direction and y in the Y direction.
+ *
+ * @param glyphIndex the glyth index in this GlyphVector.
+ * @param x the distance in the X direction to translate the
+ * shape object before returning it.
+ * @param y the distance in the Y direction to translate the
+ * shape object before returning it.
+ *
+ * @return a Shape object which represents the visual representation
+ * of the specified glyph in this GlyphVector - glyph outline.
+ */
+ public Shape getGlyphOutline(int glyphIndex, float x, float y) {
+ Shape initialShape = getGlyphOutline(glyphIndex);
+ AffineTransform trans = AffineTransform.getTranslateInstance(x, y);
+ return trans.createTransformedShape(initialShape);
+ }
+
+ /**
+ * Gets the visual bounds of the specified glyph in the GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ *
+ * @return the glyph visual bounds of the glyph with the specified
+ * index in the GlyphVector.
+ */
+ public abstract Shape getGlyphVisualBounds(int glyphIndex);
+
+ /**
+ * Gets a Shape object which defines the visual representation
+ * of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyth index in this GlyphVector.
+ *
+ * @return a Shape object which represents the visual representation
+ * of the specified glyph in this GlyphVector - glyph outline.
+ */
+ public abstract Shape getGlyphOutline(int glyphIndex);
+
+ /**
+ * Gets the logical bounds of the specified glyph in
+ * the GlyphVector.
+ *
+ * @param glyphIndex the index in this GlyphVector of the glyph from which
+ * to retrieve its logical bounds
+ *
+ * @return the logical bounds of the specified glyph in
+ * the GlyphVector.
+ */
+ public abstract Shape getGlyphLogicalBounds(int glyphIndex);
+
+ /**
+ * Gets the visual representation of this GlyphVector rendered in
+ * x, y location as a Shape object.
+ *
+ * @param x the x coordinate of the GlyphVector.
+ * @param y the y coordinate of the GlyphVector.
+ *
+ * @return the visual representation of this GlyphVector as a Shape object.
+ */
+ public abstract Shape getOutline(float x, float y);
+
+ /**
+ * Gets the visual representation of this GlyphVector as a Shape object.
+ *
+ * @return the visual representation of this GlyphVector as a Shape object.
+ */
+ public abstract Shape getOutline();
+
+ /**
+ * Gets the font of this GlyphVector.
+ *
+ * @return the font of this GlyphVector.
+ */
+ public abstract Font getFont();
+
+ /**
+ * Gets an array of the glyph codes of the specified glyphs.
+ *
+ * @param beginGlyphIndex the index into this GlyphVector at which
+ * to start retrieving glyph codes.
+ * @param numEntries the number of glyph codes.
+ * @param codeReturn the array into which the resulting
+ * glyphcodes will be written.
+ *
+ * @return the array of the glyph codes.
+ */
+ public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn);
+
+ /**
+ * Gets an array of the character indices of
+ * the specified glyphs.
+ *
+ * @param beginGlyphIndex the index of the first glyph to return information for.
+ * @param numEntries the number of glyph indices to return.
+ * @param codeReturn the array into which the resulting character
+ * indices will be written.
+ *
+ * @return an array of character indices for the specifies glyphs.
+ */
+ public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+
+ for (int i = 0; i < numEntries; i++){
+ codeReturn[i] = getGlyphCharIndex(i+beginGlyphIndex);
+ }
+ return codeReturn;
+ }
+
+ /**
+ * Gets an array of the positions of the specified glyphs in
+ * this GlyphVector.
+ *
+ * @param beginGlyphIndex the index of the first glyph to return information for.
+ * @param numEntries the number of glyphs to return information for.
+ * @param positionReturn the array where the result will be stored.
+ *
+ * @return an array of glyph positions.
+ */
+ public abstract float[] getGlyphPositions(int beginGlyphIndex,
+ int numEntries, float[] positionReturn);
+
+ /**
+ * Gets the glyph code of the specified glyph.
+ *
+ * @param glyphIndex the index in this GlyphVector which corresponds
+ * to the glyph from which to retrieve the glyphcode.
+ *
+ * @return the glyphcode of the specified glyph.
+ */
+ public abstract int getGlyphCode(int glyphIndex);
+
+ /**
+ * Gets the first logical character's index of the specified glyph.
+ *
+ * @param glyphIndex the glyph index.
+ *
+ * @return the the first logical character's index.
+ */
+ public int getGlyphCharIndex(int glyphIndex){
+ // default implemetation one-to-one
+ return glyphIndex;
+ }
+
+ /**
+ * Sets default layout to this GlyphVector.
+ */
+ public abstract void performDefaultLayout();
+
+ /**
+ * Gets the number of glyphs in the GlyphVector.
+ *
+ * @return the number of glyphs in the GlyphVector.
+ */
+ public abstract int getNumGlyphs();
+
+ /**
+ * Gets flags which describe the global state of the GlyphVector.
+ * The default implementation returns 0.
+ *
+ * @return the layout flags
+ */
+ public int getLayoutFlags(){
+ // default implementation - returned value is 0
+ return 0;
+ }
+
+}
+
diff --git a/awt/java/awt/font/GraphicAttribute.java b/awt/java/awt/font/GraphicAttribute.java
new file mode 100644
index 0000000..2f41951
--- /dev/null
+++ b/awt/java/awt/font/GraphicAttribute.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicAttribute abstract class provides an opportunity to
+ * insert graphical elements in printed text.
+ */
+public abstract class GraphicAttribute {
+
+ /**
+ * The Constant TOP_ALIGNMENT indicates using the top line to
+ * calculate placement of graphics.
+ */
+ public static final int TOP_ALIGNMENT = -1;
+
+ /**
+ * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to
+ * calculate placement of graphics.
+ */
+ public static final int BOTTOM_ALIGNMENT = -2;
+
+ /**
+ * The Constant ROMAN_BASELINE indicates the placement of the roman
+ * baseline with respect to the graphics origin.
+ */
+ public static final int ROMAN_BASELINE = 0;
+
+ /**
+ * The Constant CENTER_BASELINE indicates the placement of the center
+ * baseline with respect to the graphics origin.
+ */
+ public static final int CENTER_BASELINE = 1;
+
+ /**
+ * The Constant HANGING_BASELINE indicates the placement of the hanging
+ * baseline with respect to the graphics origin.
+ */
+ public static final int HANGING_BASELINE = 2;
+
+ // the alignment of this GraphicAttribute
+ /** The alignment. */
+ private int alignment;
+
+ /**
+ * Instantiates a new graphic attribute with the specified alignment.
+ *
+ * @param align the specified alignment.
+ */
+ protected GraphicAttribute(int align) {
+ if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) {
+ // awt.198=Illegal alignment argument
+ throw new IllegalArgumentException(Messages.getString("awt.198")); //$NON-NLS-1$
+ }
+ this.alignment = align;
+ }
+
+ /**
+ * Draws the GraphicAttribute at the specified location.
+ *
+ * @param graphics the Graphics.
+ * @param x the X coordinate of GraphicAttribute location.
+ * @param y the Y coordinate of GraphicAttribute location.
+ */
+ public abstract void draw(Graphics2D graphics, float x, float y);
+
+ /**
+ * Gets the GraphicAttribute's advance. It's the distance from the point
+ * at which the graphic is rendered and the point where the next character
+ * or graphic is rendered.
+ *
+ * @return the GraphicAttribute's advance.
+ */
+ public abstract float getAdvance();
+
+ /**
+ * Gets the alignment of this GraphicAttribute.
+ *
+ * @return the alignment of this GraphicAttribute.
+ */
+ public final int getAlignment() {
+ return this.alignment;
+ }
+
+ /**
+ * Gets the ascent of this GraphicAttribute.
+ *
+ * @return the ascent of this GraphicAttribute.
+ */
+ public abstract float getAscent();
+
+ /**
+ * Gets the bounds of this GraphicAttribute.
+ *
+ * @return the bounds of this GraphicAttribute.
+ */
+ public Rectangle2D getBounds() {
+ float ascent = getAscent();
+ float advance = getAdvance();
+ float descent = getDescent();
+
+ // Default implementation - see API documentation.
+ return new Rectangle2D.Float(0, -ascent, advance, ascent + descent);
+ }
+
+ /**
+ * Gets the descent of this GraphicAttribute.
+ *
+ * @return the descent of this GraphicAttribute.
+ */
+ public abstract float getDescent();
+
+ /**
+ * Gets the GlyphJustificationInfo of this GraphicAttribute.
+ *
+ * @return the GlyphJustificationInfo of this GraphicAttribute.
+ */
+ public GlyphJustificationInfo getJustificationInfo() {
+
+ /* Default implementation.
+ * Since documentation doesn't describe default values,
+ * they were calculated based on 1.5 release
+ * behavior and can be obtained using next test sample:
+ *
+ * // Create GraphicAttribute class implementation
+ * public class MyGraphicAttribute extends GraphicAttribute {
+ * protected MyGraphicAttribute(int align) {
+ * super(align);
+ * }
+ *
+ * public float getDescent() {
+ * return 0;
+ * }
+ *
+ * public float getAdvance() {
+ * return 1;
+ * }
+ *
+ * public void draw(Graphics2D g2, float x, float y) {
+ * }
+ *
+ * public float getAscent() {
+ * return 0;
+ * }
+ * }
+ *
+ * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0);
+ * // print justification parameters
+ * System.out.println(myGA.getJustificationInfo().growAbsorb);
+ * System.out.println(myGA.getJustificationInfo().shrinkAbsorb);
+ * System.out.println(myGA.getJustificationInfo().growLeftLimit);
+ * System.out.println(myGA.getJustificationInfo().growPriority);
+ * System.out.println(myGA.getJustificationInfo().growRightLimit);
+ * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit);
+ * System.out.println(myGA.getJustificationInfo().shrinkPriority);
+ * System.out.println(myGA.getJustificationInfo().shrinkRightLimit);
+ * System.out.println(myGA.getJustificationInfo().weight);
+ */
+ float advance = getAdvance();
+ return new GlyphJustificationInfo(
+ advance,
+ false,
+ GlyphJustificationInfo.PRIORITY_INTERCHAR,
+ advance / 3,
+ advance / 3,
+ false,
+ GlyphJustificationInfo.PRIORITY_WHITESPACE,
+ 0,
+ 0);
+ }
+
+}
+
diff --git a/awt/java/awt/font/ImageGraphicAttribute.java b/awt/java/awt/font/ImageGraphicAttribute.java
new file mode 100644
index 0000000..41f90b8
--- /dev/null
+++ b/awt/java/awt/font/ImageGraphicAttribute.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The ImageGraphicAttribute class provides an opportunity to insert
+ * images to a text.
+ */
+public final class ImageGraphicAttribute extends GraphicAttribute {
+
+ // Image object rendered by this ImageGraphicAttribute
+ /** The image. */
+ private Image fImage;
+
+ // X coordinate of the origin point
+ /** The origin x. */
+ private float fOriginX;
+
+ // Y coordinate of the origin point
+ /** The origin y. */
+ private float fOriginY;
+
+ // the width of the image object
+ /** The img width. */
+ private float fImgWidth;
+
+ // the height of the image object
+ /** The img height. */
+ private float fImgHeight;
+
+ /**
+ * Instantiates a new ImageGraphicAttribute with the specified image,
+ * alignment and origins.
+ *
+ * @param image the Image to be rendered by ImageGraphicAttribute.
+ * @param alignment the alignment of the ImageGraphicAttribute.
+ * @param originX the origin X coordinate in the image of
+ * ImageGraphicAttribute.
+ * @param originY the origin Y coordinate in the image of
+ * ImageGraphicAttribute.
+ */
+ public ImageGraphicAttribute(Image image, int alignment, float originX,
+ float originY) {
+ super(alignment);
+
+ this.fImage = image;
+ this.fOriginX = originX;
+ this.fOriginY = originY;
+
+ this.fImgWidth = fImage.getWidth(null);
+ this.fImgHeight = fImage.getHeight(null);
+
+ }
+
+ /**
+ * Instantiates a new ImageGraphicAttribute with the specified image and
+ * alignment.
+ *
+ * @param image the Image to be rendered by ImageGraphicAttribute.
+ * @param alignment the alignment of the ImageGraphicAttribute.
+ */
+ public ImageGraphicAttribute(Image image, int alignment) {
+ this(image, alignment, 0, 0);
+ }
+
+ /**
+ * Returns a hash code of this ImageGraphicAttribute object.
+ *
+ * @return the hash code of this ImageGraphicAttribute object.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+
+ hash.append(fImage.hashCode());
+ hash.append(getAlignment());
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares the specified ImageGraphicAttribute object with this
+ * ImageGraphicAttribute object.
+ *
+ * @param iga the ImageGraphicAttribute object to be compared.
+ *
+ * @return true, if the specified ImageGraphicAttribute object is equal to
+ * this ImageGraphicAttribute object, false otherwise.
+ */
+ public boolean equals(ImageGraphicAttribute iga) {
+ if (iga == null) {
+ return false;
+ }
+
+ if (iga == this) {
+ return true;
+ }
+
+ return (fOriginX == iga.fOriginX &&
+ fOriginY == iga.fOriginY &&
+ getAlignment() == iga.getAlignment() &&
+ fImage.equals(iga.fImage));
+ }
+
+ /**
+ * Compares the specified Object with this ImageGraphicAttribute object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is equal to this
+ * ImageGraphicAttribute object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ return equals((ImageGraphicAttribute) obj);
+ }
+ catch(ClassCastException e) {
+ return false;
+ }
+
+ }
+
+ @Override
+ public void draw(Graphics2D g2, float x, float y) {
+ g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null);
+ }
+
+ /**
+ * @see java.awt.font.GraphicAttribute#getAdvance()
+ */
+ @Override
+ public float getAdvance() {
+ return Math.max(0, fImgWidth - fOriginX);
+ }
+
+ @Override
+ public float getAscent() {
+ return Math.max(0, fOriginY);
+ }
+
+ @Override
+ public Rectangle2D getBounds() {
+ return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight);
+ }
+
+ /**
+ * @see java.awt.font.GraphicAttribute#getDescent()
+ */
+ @Override
+ public float getDescent() {
+ return Math.max(0, fImgHeight - fOriginY);
+ }
+
+}
+
diff --git a/awt/java/awt/font/LineBreakMeasurer.java b/awt/java/awt/font/LineBreakMeasurer.java
new file mode 100644
index 0000000..efce615
--- /dev/null
+++ b/awt/java/awt/font/LineBreakMeasurer.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.text.AttributedCharacterIterator;
+//???AWT: import java.text.BreakIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The class LineBreakMeasurer provides methods to measure the graphical
+ * representation of a text in order to determine where to add line
+ * breaks so the resulting line of text fits its wrapping width.
+ * The wrapping width defines the visual width of the paragraph.
+ */
+public final class LineBreakMeasurer {
+
+ /** The tm. */
+ private TextMeasurer tm = null;
+ //???AWT private BreakIterator bi = null;
+ /** The position. */
+ private int position = 0;
+
+ /** The maxpos. */
+ int maxpos = 0;
+
+ /**
+ * Instantiates a new LineBreakMeasurer object for the specified text.
+ *
+ * @param text the AttributedCharacterIterator object which contains
+ * text with at least one character.
+ * @param frc the FontRenderContext represented information
+ * about graphic device.
+ */
+ public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
+ //???AWT: this(text, BreakIterator.getLineInstance(), frc);
+ }
+
+ /* ???AWT
+ public LineBreakMeasurer(
+ AttributedCharacterIterator text,
+ BreakIterator bi,
+ FontRenderContext frc
+ ) {
+ tm = new TextMeasurer(text, frc);
+ this.bi = bi;
+ this.bi.setText(text);
+ position = text.getBeginIndex();
+ maxpos = tm.aci.getEndIndex();
+ }
+ */
+
+ /**
+ * Deletes a character from the specified position of the text,
+ * updates this LineBreakMeasurer object.
+ *
+ * @param newText the new text.
+ * @param pos the posion of the character which is deleted.
+ */
+ public void deleteChar(AttributedCharacterIterator newText, int pos) {
+ tm.deleteChar(newText, pos);
+ //???AWT: bi.setText(newText);
+
+ position = newText.getBeginIndex();
+
+ maxpos--;
+ }
+
+ /**
+ * Gets current position of this LineBreakMeasurer.
+ *
+ * @return current position of this LineBreakMeasurer
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Insertes a character at the specified position in the text,
+ * updates this LineBreakMeasurer object.
+ *
+ * @param newText the new text.
+ * @param pos the posion of the character which is inserted.
+ */
+ public void insertChar(AttributedCharacterIterator newText, int pos) {
+ tm.insertChar(newText, pos);
+// ???AWT: bi.setText(newText);
+
+ position = newText.getBeginIndex();
+
+ maxpos++;
+ }
+
+ /**
+ * Returns the next line of text, updates current position in this
+ * LineBreakMeasurer.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ * @param offsetLimit the limit point withing the text indicating
+ * that no further text should be included on the line; the paragraph break.
+ * @param requireNextWord if true, null is returned (the entire word at the current
+ * position does not fit within the wrapping width);
+ * if false, a valid layout is returned that includes at least the
+ * character at the current position.
+ *
+ * @return the next TextLayout which begins at the current position and
+ * represents the next line of text with width wrappingWidth, null is
+ * returned if the entire word at the current position does not fit within
+ * the wrapping width.
+ */
+ public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) {
+ if (position == maxpos) {
+ return null;
+ }
+
+ int nextPosition = nextOffset(wrappingWidth, offsetLimit, requireNextWord);
+
+ if (nextPosition == position) {
+ return null;
+ }
+ TextLayout layout = tm.getLayout(position, nextPosition);
+ position = nextPosition;
+ return layout;
+ }
+
+ /**
+ * Returns the next line of text.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ *
+ * @return the next line of text.
+ */
+ public TextLayout nextLayout(float wrappingWidth) {
+ return nextLayout(wrappingWidth, maxpos, false);
+ }
+
+ /**
+ * Returns the end position of the next line of text.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ *
+ * @return the end position of the next line of text.
+ */
+ public int nextOffset(float wrappingWidth) {
+ return nextOffset(wrappingWidth, maxpos, false);
+ }
+
+ /**
+ * Returns the end position of the next line of text.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ * @param offsetLimit the limit point withing the text indicating
+ * that no further text should be included on the line; the paragraph break.
+ * @param requireNextWord if true, the current position is returned
+ * if the entire next word does not fit within wrappingWidth;
+ * if false, the offset returned is at least one greater than the current
+ * position.
+ *
+ * @return the end position of the next line of text.
+ *
+ * @throws IllegalArgumentException if the offsetLimit is less than
+ * the current position.
+ */
+ public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) {
+ if (offsetLimit <= position) {
+ // awt.203=Offset limit should be greater than current position.
+ throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$
+ }
+
+ if (position == maxpos) {
+ return position;
+ }
+
+ int breakPos = tm.getLineBreakIndex(position, wrappingWidth);
+ int correctedPos = breakPos;
+
+ // This check is required because bi.preceding(maxpos) throws an exception
+ /* ???AWT
+ if (breakPos == maxpos) {
+ correctedPos = maxpos;
+ } else if (Character.isWhitespace(bi.getText().setIndex(breakPos))) {
+ correctedPos = bi.following(breakPos);
+ } else {
+ correctedPos = bi.preceding(breakPos);
+ }
+ */
+
+ if (position >= correctedPos) {
+ if (requireNextWord) {
+ correctedPos = position;
+ } else {
+ correctedPos = Math.max(position+1, breakPos);
+ }
+ }
+
+ return Math.min(correctedPos, offsetLimit);
+ }
+
+ /**
+ * Sets the new position of this LineBreakMeasurer.
+ *
+ * @param pos the new position of this LineBreakMeasurer.
+ */
+ public void setPosition(int pos) {
+ if (tm.aci.getBeginIndex() > pos || maxpos < pos) {
+ // awt.33=index is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.33")); //$NON-NLS-1$
+ }
+ position = pos;
+ }
+}
+
diff --git a/awt/java/awt/font/LineMetrics.java b/awt/java/awt/font/LineMetrics.java
new file mode 100644
index 0000000..2857187
--- /dev/null
+++ b/awt/java/awt/font/LineMetrics.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+/**
+ * The LineMetrics class provides information such as concerning how the text
+ * is positioned with respect to the base line, such as ascent, descent,
+ * and leading.
+ *
+ */
+public abstract class LineMetrics {
+
+ /**
+ * Gets the baseline offsets of the text according to the
+ * the baseline of this text.
+ *
+ * @return the baseline offsets of the text according to the
+ * the baseline of this text.
+ */
+ public abstract float[] getBaselineOffsets();
+
+ /**
+ * Gets the number of characters of the text.
+ *
+ * @return the number of characters of the text.
+ */
+ public abstract int getNumChars();
+
+ /**
+ * Gets the baseline index, returns one of the following
+ * index: ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE.
+ *
+ * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE
+ * or HANGING_BASELINE.
+ */
+ public abstract int getBaselineIndex();
+
+ /**
+ * Gets the thickness of the underline.
+ *
+ * @return the thickness of the underline.
+ */
+ public abstract float getUnderlineThickness();
+
+ /**
+ * Gets the offset of the underline.
+ *
+ * @return the offset of the underline.
+ */
+ public abstract float getUnderlineOffset();
+
+ /**
+ * Gets the thickness of strike through line.
+ *
+ * @return the thickness of strike through line.
+ */
+ public abstract float getStrikethroughThickness();
+
+ /**
+ * Gets the offset of the strike through line.
+ *
+ * @return the offset of the strike through line.
+ */
+ public abstract float getStrikethroughOffset();
+
+ /**
+ * Gets the leading of the text.
+ *
+ * @return the leading of the text.
+ */
+ public abstract float getLeading();
+
+ /**
+ * Gets the height of the text as a sum of the ascent, the descent
+ * and the leading.
+ *
+ * @return the height of the text as a sum of the ascent, the descent
+ * and the leading.
+ */
+ public abstract float getHeight();
+
+ /**
+ * Gets the descent of the text.
+ *
+ * @return the descent of the text.
+ */
+ public abstract float getDescent();
+
+ /**
+ * Gets the ascent of the text.
+ *
+ * @return the ascent of the text.
+ */
+ public abstract float getAscent();
+
+}
+
diff --git a/awt/java/awt/font/MultipleMaster.java b/awt/java/awt/font/MultipleMaster.java
new file mode 100644
index 0000000..773bfcf
--- /dev/null
+++ b/awt/java/awt/font/MultipleMaster.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Font;
+
+/**
+ * The MultipleMaster interface provides methods to manipulate MultipleMaster
+ * type fonts and retrieve graphical and design data from them.
+ */
+public interface MultipleMaster {
+
+ /**
+ * Derives a new multiple master font based on the specified
+ * parameters.
+ *
+ * @param glyphWidths float array which represents width of each glyph
+ * in font space.
+ * @param avgStemWidth the average stem width in font space.
+ * @param typicalCapHeight the typical upper case char height.
+ * @param typicalXHeight the typical lower case char height.
+ * @param italicAngle the slope angle for italics.
+ *
+ * @return a MultipleMaster font.
+ */
+ public Font deriveMMFont(float[] glyphWidths, float avgStemWidth,
+ float typicalCapHeight, float typicalXHeight, float italicAngle);
+
+ /**
+ * Derives a new multiple master font based on the design axis values
+ * contained in the specified array.
+ *
+ * @param axes an float array which contains axis values.
+ *
+ * @return a MultipleMaster font.
+ */
+ public Font deriveMMFont(float[] axes);
+
+ /**
+ * Gets default design values for the axes.
+ *
+ * @return the default design values for the axes.
+ */
+ public float[] getDesignAxisDefaults();
+
+ /**
+ * Gets the array of design axis names.
+ *
+ * @return the array of design axis names.
+ */
+ public String[] getDesignAxisNames();
+
+ /**
+ * Gets the array of design axis ranges.
+ *
+ * @return the array of design axis ranges.
+ */
+ public float[] getDesignAxisRanges();
+
+ /**
+ * Gets the number of multiple master design controls.
+ *
+ * @return the number of multiple master design controls.
+ */
+ public int getNumDesignAxes();
+
+}
+
diff --git a/awt/java/awt/font/OpenType.java b/awt/java/awt/font/OpenType.java
new file mode 100644
index 0000000..53cb6c0
--- /dev/null
+++ b/awt/java/awt/font/OpenType.java
@@ -0,0 +1,410 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+/**
+ * The OpenType interface provides constants and methods for getting
+ * instance data for fonts of type OpenType and TrueType. For more information,
+ * see the <a href="http://partners.adobe.com/public/developer/opentype/index_spec.html">OpenType specification</a>.
+ */
+public interface OpenType {
+
+ /**
+ * The Constant TAG_ACNT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_ACNT = 1633906292;
+
+ /**
+ * The Constant TAG_AVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_AVAR = 1635148146;
+
+ /**
+ * The Constant TAG_BASE indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BASE = 1111577413;
+
+ /**
+ * The Constant TAG_BDAT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BDAT = 1650745716;
+
+ /**
+ * The Constant TAG_BLOC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BLOC = 1651273571;
+
+ /**
+ * The Constant TAG_BSLN indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BSLN = 1651731566;
+
+ /**
+ * The Constant TAG_CFF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CFF = 1128678944;
+
+ /**
+ * The Constant TAG_CMAP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CMAP = 1668112752;
+
+ /**
+ * The Constant TAG_CVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CVAR = 1668702578;
+
+ /**
+ * The Constant TAG_CVT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CVT = 1668707360;
+
+ /**
+ * The Constant TAG_DSIG indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_DSIG = 1146308935;
+
+ /**
+ * The Constant TAG_EBDT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_EBDT = 1161970772;
+
+ /**
+ * The Constant TAG_EBLC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_EBLC = 1161972803;
+
+ /**
+ * The Constant TAG_EBSC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_EBSC = 1161974595;
+
+ /**
+ * The Constant TAG_FDSC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FDSC = 1717859171;
+
+ /**
+ * The Constant TAG_FEAT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FEAT = 1717920116;
+
+ /**
+ * The Constant TAG_FMTX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FMTX = 1718449272;
+
+ /**
+ * The Constant TAG_FPGM indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FPGM = 1718642541;
+
+ /**
+ * The Constant TAG_FVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FVAR = 1719034226;
+
+ /**
+ * The Constant TAG_GASP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GASP = 1734439792;
+
+ /**
+ * The Constant TAG_GDEF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GDEF = 1195656518;
+
+ /**
+ * The Constant TAG_GLYF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GLYF = 1735162214;
+
+ /**
+ * The Constant TAG_GPOS indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GPOS = 1196445523;
+
+ /**
+ * The Constant TAG_GSUB indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GSUB = 1196643650;
+
+ /**
+ * The Constant TAG_GVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GVAR = 1735811442;
+
+ /**
+ * The Constant TAG_HDMX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HDMX = 1751412088;
+
+ /**
+ * The Constant TAG_HEAD indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HEAD = 1751474532;
+
+ /**
+ * The Constant TAG_HHEA indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HHEA = 1751672161;
+
+ /**
+ * The Constant TAG_HMTX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HMTX = 1752003704;
+
+ /**
+ * The Constant TAG_JSTF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_JSTF = 1246975046;
+
+ /**
+ * The Constant TAG_JUST indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_JUST = 1786082164;
+
+ /**
+ * The Constant TAG_KERN indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_KERN = 1801810542;
+
+ /**
+ * The Constant TAG_LCAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_LCAR = 1818452338;
+
+ /**
+ * The Constant TAG_LOCA indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_LOCA = 1819239265;
+
+ /**
+ * The Constant TAG_LTSH indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_LTSH = 1280594760;
+
+ /**
+ * The Constant TAG_MAXP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MAXP = 1835104368;
+
+ /**
+ * The Constant TAG_MMFX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MMFX = 1296909912;
+
+ /**
+ * The Constant TAG_MMSD indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MMSD = 1296913220;
+
+ /**
+ * The Constant TAG_MORT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MORT = 1836020340;
+
+ /**
+ * The Constant TAG_NAME indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_NAME = 1851878757;
+
+ /**
+ * The Constant TAG_OPBD indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_OPBD = 1836020340;
+
+ /**
+ * The Constant TAG_OS2 indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_OS2 = 1330851634;
+
+ /**
+ * The Constant TAG_PCLT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_PCLT = 1346587732;
+
+ /**
+ * The Constant TAG_POST indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_POST = 1886352244;
+
+ /**
+ * The Constant TAG_PREP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_PREP = 1886545264;
+
+ /**
+ * The Constant TAG_PROP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_PROP = 1886547824;
+
+ /**
+ * The Constant TAG_TRAK indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_TRAK = 1953653099;
+
+ /**
+ * The Constant TAG_TYP1 indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_TYP1 = 1954115633;
+
+ /**
+ * The Constant TAG_VDMX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_VDMX = 1447316824;
+
+ /**
+ * The Constant TAG_VHEA indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_VHEA = 1986553185;
+
+ /**
+ * The Constant TAG_VMTX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_VMTX = 1986884728;
+
+ /**
+ * Returns the OpenType font version.
+ *
+ * @return the the OpenType font version.
+ */
+ public int getVersion();
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param sfntTag the sfnt tag.
+ *
+ * @return a byte array contains the font data corresponding
+ * to the specified tag.
+ */
+ public byte[] getFontTable(int sfntTag);
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param sfntTag the sfnt tag.
+ * @param offset the offset of the returned table.
+ * @param count the number of returned table.
+ *
+ * @return the table corresponding to sfntTag and containing
+ * the bytes starting at offset byte and including count bytes.
+ */
+ public byte[] getFontTable(int sfntTag, int offset, int count);
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param strSfntTag the str sfnt tag as a String.
+ *
+ * @return a byte array contains the font data corresponding
+ * to the specified tag.
+ */
+ public byte[] getFontTable(String strSfntTag);
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param strSfntTag the sfnt tag as a String.
+ * @param offset the offset of the returned table.
+ * @param count the number of returned table.
+ *
+ * @return the table corresponding to sfntTag and containing
+ * the bytes starting at offset byte and including count bytes.
+ */
+ public byte[] getFontTable(String strSfntTag, int offset, int count);
+
+ /**
+ * Gets the table size for a specified tag.
+ *
+ * @param strSfntTag the sfnt tag as a String.
+ *
+ * @return the table size for a specified tag.
+ */
+ public int getFontTableSize(String strSfntTag);
+
+ /**
+ * Gets the table size for a specified tag.
+ *
+ * @param sfntTag the sfnt tag.
+ *
+ * @return the table size for a specified tag.
+ */
+ public int getFontTableSize(int sfntTag);
+
+}
+
diff --git a/awt/java/awt/font/ShapeGraphicAttribute.java b/awt/java/awt/font/ShapeGraphicAttribute.java
new file mode 100644
index 0000000..45199fd
--- /dev/null
+++ b/awt/java/awt/font/ShapeGraphicAttribute.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The ShapeGraphicAttribute class provides an opportunity to insert
+ * shapes to a text.
+ */
+public final class ShapeGraphicAttribute extends GraphicAttribute {
+
+ // shape to render
+ /** The shape. */
+ private Shape fShape;
+
+ // flag, if the shape should be stroked (true) or filled (false)
+ /** The stroke. */
+ private boolean fStroke;
+
+ // bounds of the shape
+ /** The bounds. */
+ private Rectangle2D fBounds;
+
+ // X coordinate of the origin point
+ /** The origin x. */
+ private float fOriginX;
+
+ // Y coordinate of the origin point
+ /** The origin y. */
+ private float fOriginY;
+
+ // width of the shape
+ /** The shape width. */
+ private float fShapeWidth;
+
+ // height of the shape
+ /** The shape height. */
+ private float fShapeHeight;
+
+ /**
+ * The Constant STROKE indicates whether the Shape is stroked
+ * or not.
+ */
+ public static final boolean STROKE = true;
+
+ /**
+ * The Constant FILL indicates whether the Shape is filled
+ * or not. */
+ public static final boolean FILL = false;
+
+ /**
+ * Instantiates a new ShapeGraphicAttribute object for the specified
+ * Shape.
+ *
+ * @param shape the shape to be rendered by this
+ * ShapeGraphicAttribute.
+ * @param alignment the alignment of this ShapeGraphicAttribute.
+ * @param stroke true if the Shape is stroked,
+ * false if the Shape is filled.
+ */
+ public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) {
+ super(alignment);
+
+ this.fShape = shape;
+ this.fStroke = stroke;
+
+ this.fBounds = fShape.getBounds2D();
+
+ this.fOriginX = (float)fBounds.getMinX();
+ this.fOriginY = (float)fBounds.getMinY();
+
+ this.fShapeWidth = (float)fBounds.getWidth();
+ this.fShapeHeight = (float)fBounds.getHeight();
+ }
+
+ /**
+ * Returns a hash code of this ShapeGraphicAttribute object.
+ *
+ * @return a hash code of this ShapeGraphicAttribute object.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+
+ hash.append(fShape.hashCode());
+ hash.append(getAlignment());
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares this ShapeGraphicAttribute object to the specified
+ * ShapeGraphicAttribute object.
+ *
+ * @param sga the ShapeGraphicAttribute object to be compared.
+ *
+ * @return true, if this ShapeGraphicAttribute object is equal
+ * to the specified ShapeGraphicAttribute object, false otherwise.
+ */
+ public boolean equals(ShapeGraphicAttribute sga) {
+ if (sga == null) {
+ return false;
+ }
+
+ if (sga == this) {
+ return true;
+ }
+
+ return ( fStroke == sga.fStroke &&
+ getAlignment() == sga.getAlignment() &&
+ fShape.equals(sga.fShape));
+
+ }
+
+ /**
+ * Compares this ShapeGraphicAttribute object to the specified
+ * Object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if this ShapeGraphicAttribute object is equal
+ * to the specified Object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ return equals((ShapeGraphicAttribute) obj);
+ }
+ catch(ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void draw(Graphics2D g2, float x, float y) {
+ AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+ if (fStroke == STROKE){
+ Stroke oldStroke = g2.getStroke();
+ g2.setStroke(new BasicStroke());
+ g2.draw(at.createTransformedShape(fShape));
+ g2.setStroke(oldStroke);
+ } else {
+ g2.fill(at.createTransformedShape(fShape));
+ }
+
+ }
+
+ @Override
+ public float getAdvance() {
+ return Math.max(0, fShapeWidth + fOriginX);
+ }
+
+ @Override
+ public float getAscent() {
+ return Math.max(0, -fOriginY);
+ }
+
+ @Override
+ public Rectangle2D getBounds() {
+ return (Rectangle2D)fBounds.clone();
+ }
+
+ @Override
+ public float getDescent() {
+ return Math.max(0, fShapeHeight + fOriginY);
+ }
+
+}
+
diff --git a/awt/java/awt/font/TextHitInfo.java b/awt/java/awt/font/TextHitInfo.java
new file mode 100644
index 0000000..17bbf71
--- /dev/null
+++ b/awt/java/awt/font/TextHitInfo.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The TextHitInfo class provides information about a caret position
+ * in a text model for insertion or deletion of a character in a text.
+ * The TextHitInfo defines two biases of the character: leading or trailing.
+ * Leading position means the left edge of the specified character
+ * (TextHitInfo.leading(2) method for "text" returns the left side of "x").
+ * Trailing position means the right edge of the specified character
+ * (TextHitInfo.trailing(2) method for "text" returns the right side of "x").
+ */
+public final class TextHitInfo {
+
+ /** The char idx. */
+ private int charIdx; // Represents character index in the line
+
+ /** The is trailing. */
+ private boolean isTrailing;
+
+ /**
+ * Instantiates a new text hit info.
+ *
+ * @param idx the idx
+ * @param isTrailing the is trailing
+ */
+ private TextHitInfo(int idx, boolean isTrailing) {
+ charIdx = idx;
+ this.isTrailing = isTrailing;
+ }
+
+ /**
+ * To string.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return new String(
+ "TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$
+ (isTrailing?"Trailing":"Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ );
+ }
+
+ /**
+ * Compares this TextHitInfo object with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified object is a TextHitInfo object
+ * with the same data values as this TextHitInfo, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TextHitInfo) {
+ return equals((TextHitInfo) obj);
+ }
+ return false;
+ }
+
+ /**
+ * Compares this TextHitInfo object with the specified TextHitInfo
+ * object.
+ *
+ * @param thi the TextHitInfo object to be compared.
+ *
+ * @return true, if this TextHitInfo object has the same data values as the
+ * specified TextHitInfo object, false otherwise.
+ */
+ public boolean equals(TextHitInfo thi) {
+ return
+ thi != null &&
+ thi.charIdx == charIdx &&
+ thi.isTrailing == isTrailing;
+ }
+
+ /**
+ * Gets a TextHitInfo object with its character index
+ * at the specified offset from the character index of
+ * this TextHitInfo.
+ *
+ * @param offset the offset.
+ *
+ * @return the TextHitInfo.
+ */
+ public TextHitInfo getOffsetHit(int offset) {
+ return new TextHitInfo(charIdx + offset, isTrailing);
+ }
+
+ /**
+ * Gets a TextHitInfo associated with the other side of
+ * the insertion point.
+ *
+ * @return the other hit.
+ */
+ public TextHitInfo getOtherHit() {
+ return isTrailing ?
+ new TextHitInfo(charIdx+1, false) :
+ new TextHitInfo(charIdx-1, true);
+ }
+
+ /**
+ * Returns true if the leading edge of the character is hit,
+ * false if the trailing edge of the character is hit.
+ *
+ * @return true if the leading edge of the character is hit,
+ * false if the trailing edge of the character is hit.
+ */
+ public boolean isLeadingEdge() {
+ return !isTrailing;
+ }
+
+ /**
+ * Hash code.
+ *
+ * @return the int
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.combine(charIdx, isTrailing);
+ }
+
+ /**
+ * Gets the insertion index.
+ *
+ * @return the insertion index: character index if the leading edge
+ * is hit, or character index + 1 if the trailing edge is hit.
+ */
+ public int getInsertionIndex() {
+ return isTrailing ? charIdx+1 : charIdx;
+ }
+
+ /**
+ * Gets the index of the character hit.
+ *
+ * @return the character hit's index.
+ */
+ public int getCharIndex() {
+ return charIdx;
+ }
+
+ /**
+ * Returns a TextHitInfo associated with the trailing edge of
+ * the character at the specified char index.
+ *
+ * @param charIndex the char index.
+ *
+ * @return the TextHitInfo associated with the trailing edge of
+ * the character at the specified char index.
+ */
+ public static TextHitInfo trailing(int charIndex) {
+ return new TextHitInfo(charIndex, true);
+ }
+
+ /**
+ * Returns a TextHitInfo object associated with the leading edge
+ * of the character at the specified char index.
+ *
+ * @param charIndex the char index.
+ *
+ * @return the TextHitInfo object associated with the leading edge
+ * of the character at the specified char index.
+ */
+ public static TextHitInfo leading(int charIndex) {
+ return new TextHitInfo(charIndex, false);
+ }
+
+ /**
+ * Returns a (trailing) TextHitInfo object associated with the character
+ * before the specified offset.
+ *
+ * @param offset the offset.
+ *
+ * @return the TextHitInfo object associated with the character
+ * before the specified offset.
+ */
+ public static TextHitInfo beforeOffset(int offset) {
+ return new TextHitInfo(offset-1, true);
+ }
+
+ /**
+ * Returns a (leading) TextHitInfo object associated with the character
+ * after the specified offset.
+ *
+ * @param offset the offset.
+ *
+ * @return the TextHitInfo object associated with the character
+ * after the specified offset.
+ */
+ public static TextHitInfo afterOffset(int offset) {
+ return new TextHitInfo(offset, false);
+ }
+}
diff --git a/awt/java/awt/font/TextLayout.java b/awt/java/awt/font/TextLayout.java
new file mode 100644
index 0000000..e80afd0
--- /dev/null
+++ b/awt/java/awt/font/TextLayout.java
@@ -0,0 +1,916 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.font.BasicMetrics;
+import org.apache.harmony.awt.gl.font.CaretManager;
+import org.apache.harmony.awt.gl.font.TextMetricsCalculator;
+import org.apache.harmony.awt.gl.font.TextRunBreaker;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The TextLayout class defines the graphical representation of character data.
+ * This class provides method for obtaining information about cursor
+ * positioning and movement, split cursors for text with different directions,
+ * logical and visual highlighting, multiple baselines, hits, justification,
+ * ascent, descent, and advance, and rendering. A TextLayout object can be
+ * rendered using Graphics context.
+ */
+public final class TextLayout implements Cloneable {
+
+ /**
+ * The CaretPolicy class provides a policy for obtaining the
+ * caret location. The single getStrongCaret method specifies
+ * the policy.
+ */
+ public static class CaretPolicy {
+
+ /**
+ * Instantiates a new CaretPolicy.
+ */
+ public CaretPolicy() {
+ // Nothing to do
+ }
+
+ /**
+ * Returns whichever of the two specified TextHitInfo objects
+ * has the stronger caret (higher character level) in the
+ * specified TextLayout.
+ *
+ * @param hit1 the first TextHitInfo of the specified TextLayout.
+ * @param hit2 the second TextHitInfo of the specified TextLayout.
+ * @param layout the TextLayout.
+ *
+ * @return the TextHitInfo with the stronger caret.
+ */
+ public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) {
+ // Stronger hit is the one with greater level.
+ // If the level is same, leading edge is stronger.
+
+ int level1 = layout.getCharacterLevel(hit1.getCharIndex());
+ int level2 = layout.getCharacterLevel(hit2.getCharIndex());
+
+ if (level1 == level2) {
+ return (hit2.isLeadingEdge() && (!hit1.isLeadingEdge())) ? hit2 : hit1;
+ }
+ return level1 > level2 ? hit1 : hit2;
+ }
+
+ }
+
+ /**
+ * The Constant DEFAULT_CARET_POLICY indicates the default caret policy.
+ */
+ public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy();
+
+ /** The breaker. */
+ private TextRunBreaker breaker;
+
+ /** The metrics valid. */
+ private boolean metricsValid = false;
+
+ /** The tmc. */
+ private TextMetricsCalculator tmc;
+
+ /** The metrics. */
+ private BasicMetrics metrics;
+
+ /** The caret manager. */
+ private CaretManager caretManager;
+
+ /** The justification width. */
+ float justificationWidth = -1;
+
+ /**
+ * Instantiates a new TextLayout object from the specified string
+ * and Font.
+ *
+ * @param string the string to be displayed.
+ * @param font the font of the text.
+ * @param frc the FontRenderContext object for obtaining
+ * information about a graphics device.
+ */
+ public TextLayout(String string, Font font, FontRenderContext frc) {
+ if (string == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (font == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (string.length() == 0){
+ // awt.02='{0}' parameter has zero length
+ throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ AttributedString as = new AttributedString(string);
+ as.addAttribute(TextAttribute.FONT, font);
+ this.breaker = new TextRunBreaker(as.getIterator(), frc);
+ caretManager = new CaretManager(breaker);
+ }
+
+ /**
+ * Instantiates a new TextLayout from the specified text and
+ * a map of attributes.
+ *
+ * @param string the string to be displayed.
+ * @param attributes the attributes to be used for obtaining the text
+ * style.
+ * @param frc the FontRenderContext object for obtaining
+ * information about a graphics device.
+ */
+ public TextLayout(
+ String string,
+ Map<? extends java.text.AttributedCharacterIterator.Attribute, ?> attributes,
+ FontRenderContext frc ) {
+ if (string == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (attributes == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (string.length() == 0){
+ // awt.02='{0}' parameter has zero length
+ throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+
+ AttributedString as = new AttributedString(string);
+ as.addAttributes(attributes, 0, string.length());
+ this.breaker = new TextRunBreaker(as.getIterator(), frc);
+ caretManager = new CaretManager(breaker);
+ }
+
+ /**
+ * Instantiates a new TextLayout from the AttributedCharacterIterator.
+ *
+ * @param text the AttributedCharacterIterator.
+ * @param frc the FontRenderContext object for obtaining
+ * information about a graphics device.
+ */
+ public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
+ if (text == null){
+ // awt.03='{0}' iterator parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (text.getBeginIndex() == text.getEndIndex()){
+ // awt.04='{0}' iterator parameter has zero length
+ throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ this.breaker = new TextRunBreaker(text, frc);
+ caretManager = new CaretManager(breaker);
+ }
+
+ /**
+ * Instantiates a new text layout.
+ *
+ * @param breaker the breaker
+ */
+ TextLayout(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ caretManager = new CaretManager(this.breaker);
+ }
+
+ /**
+ * Returns a hash code of this TextLayout object.
+ *
+ * @return a hash code of this TextLayout object.
+ */
+ @Override
+ public int hashCode() {
+ return breaker.hashCode();
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return a copy of this object.
+ */
+ @Override
+ protected Object clone() {
+ TextLayout res = new TextLayout((TextRunBreaker) breaker.clone());
+
+ if (justificationWidth >= 0) {
+ res.handleJustify(justificationWidth);
+ }
+
+ return res;
+ }
+
+ /**
+ * Compares this TextLayout object to the specified TextLayout object.
+ *
+ * @param layout the TextLayout object to be compared.
+ *
+ * @return true, if this TextLayout object is equal to
+ * the specified TextLayout object, false otherwise.
+ */
+ public boolean equals(TextLayout layout) {
+ if (layout == null) {
+ return false;
+ }
+ return this.breaker.equals(layout.breaker);
+ }
+
+ /**
+ * Compares this TextLayout object to the specified Object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if this TextLayout object is equal to
+ * the specified Object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof TextLayout ? equals((TextLayout) obj) : false;
+ }
+
+ /**
+ * Gets the string representation for this TextLayout.
+ *
+ * @return the string representation for this TextLayout.
+ */
+ @Override
+ public String toString() { // what for?
+ return super.toString();
+ }
+
+ /**
+ * Draws this TextLayout at the specified location with the
+ * specified Graphics2D context.
+ *
+ * @param g2d the Graphics2D object which renders this TextLayout.
+ * @param x the X coordinate of the TextLayout origin.
+ * @param y the Y coordinate of the TextLayout origin.
+ */
+ public void draw(Graphics2D g2d, float x, float y) {
+ updateMetrics();
+ breaker.drawSegments(g2d, x ,y);
+ }
+
+ /**
+ * Update metrics.
+ */
+ private void updateMetrics() {
+ if (!metricsValid) {
+ breaker.createAllSegments();
+ tmc = new TextMetricsCalculator(breaker);
+ metrics = tmc.createMetrics();
+ metricsValid = true;
+ }
+ }
+
+ /**
+ * Gets the advance of this TextLayout object.
+ *
+ * @return the advance of this TextLayout object.
+ */
+ public float getAdvance() {
+ updateMetrics();
+ return metrics.getAdvance();
+ }
+
+ /**
+ * Gets the ascent of this TextLayout object.
+ *
+ * @return the ascent of this TextLayout object.
+ */
+ public float getAscent() {
+ updateMetrics();
+ return metrics.getAscent();
+ }
+
+ /**
+ * Gets the baseline of this TextLayout object.
+ *
+ * @return the baseline of this TextLayout object.
+ */
+ public byte getBaseline() {
+ updateMetrics();
+ return (byte) metrics.getBaseLineIndex();
+ }
+
+ /**
+ * Gets the float array of offsets for the baselines which
+ * are used in this TextLayout.
+ *
+ * @return the float array of offsets for the baselines which
+ * are used in this TextLayout.
+ */
+ public float[] getBaselineOffsets() {
+ updateMetrics();
+ return tmc.getBaselineOffsets();
+ }
+
+ /**
+ * Gets the black box bounds of the characters in the specified area.
+ * The black box bounds is an Shape which contains all
+ * bounding boxes of all the glyphs of the characters
+ * between firstEndpoint and secondEndpoint parameters values.
+ *
+ * @param firstEndpoint the first point of the area.
+ * @param secondEndpoint the second point of the area.
+ *
+ * @return the Shape which contains black box bounds.
+ */
+ public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) {
+ updateMetrics();
+ if (firstEndpoint < secondEndpoint) {
+ return breaker.getBlackBoxBounds(firstEndpoint, secondEndpoint);
+ }
+ return breaker.getBlackBoxBounds(secondEndpoint, firstEndpoint);
+ }
+
+ /**
+ * Gets the bounds of this TextLayout.
+ *
+ * @return the bounds of this TextLayout.
+ */
+ public Rectangle2D getBounds() {
+ updateMetrics();
+ return breaker.getVisualBounds();
+ }
+
+ /**
+ * Gets information about the caret of the specified TextHitInfo.
+ *
+ * @param hitInfo the TextHitInfo.
+ *
+ * @return the information about the caret of the specified TextHitInfo.
+ */
+ public float[] getCaretInfo(TextHitInfo hitInfo) {
+ updateMetrics();
+ return caretManager.getCaretInfo(hitInfo);
+ }
+
+ /**
+ * Gets information about the caret of the specified TextHitInfo
+ * of a character in this TextLayout.
+ *
+ * @param hitInfo the TextHitInfo of a character in this TextLayout.
+ * @param bounds the bounds to which the caret info is constructed.
+ *
+ * @return the caret of the specified TextHitInfo.
+ */
+ public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) {
+ updateMetrics();
+ return caretManager.getCaretInfo(hitInfo);
+ }
+
+ /**
+ * Gets a Shape which represents the caret of the specified TextHitInfo
+ * in the bounds of this TextLayout.
+ *
+ * @param hitInfo the TextHitInfo.
+ * @param bounds the bounds to which the caret info is constructed.
+ *
+ * @return the Shape which represents the caret.
+ */
+ public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) {
+ updateMetrics();
+ return caretManager.getCaretShape(hitInfo, this);
+ }
+
+ /**
+ * Gets a Shape which represents the caret of the specified TextHitInfo
+ * in the bounds of this TextLayout.
+ *
+ * @param hitInfo the TextHitInfo.
+ *
+ * @return the Shape which represents the caret.
+ */
+ public Shape getCaretShape(TextHitInfo hitInfo) {
+ updateMetrics();
+ return caretManager.getCaretShape(hitInfo, this);
+ }
+
+ /**
+ * Gets two Shapes for the strong and weak carets with
+ * default caret policy and null bounds: the first element
+ * is the strong caret, the second is the weak caret or null.
+ *
+ * @param offset an offset in the TextLayout.
+ *
+ * @return an array of two Shapes corresponded to the strong
+ * and weak carets.
+ */
+ public Shape[] getCaretShapes(int offset) {
+ return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets two Shapes for the strong and weak carets with
+ * the default caret policy: the first element is the strong
+ * caret, the second is the weak caret or null.
+ *
+ * @param offset an offset in the TextLayout.
+ * @param bounds the bounds to which to extend the carets.
+ *
+ * @return an array of two Shapes corresponded to the strong
+ * and weak carets.
+ */
+ public Shape[] getCaretShapes(int offset, Rectangle2D bounds) {
+ return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets two Shapes for the strong and weak carets: the first
+ * element is the strong caret, the second is the weak caret
+ * or null.
+ *
+ * @param offset an offset in the TextLayout.
+ * @param bounds the bounds to which to extend the carets.
+ * @param policy the specified CaretPolicy.
+ *
+ * @return an array of two Shapes corresponded to the strong
+ * and weak carets.
+ */
+ public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) {
+ if (offset < 0 || offset > breaker.getCharCount()) {
+ // awt.195=Offset is out of bounds
+ throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+ }
+
+ updateMetrics();
+ return caretManager.getCaretShapes(offset, bounds, policy, this);
+ }
+
+ /**
+ * Gets the number of characters in this TextLayout.
+ *
+ * @return the number of characters in this TextLayout.
+ */
+ public int getCharacterCount() {
+ return breaker.getCharCount();
+ }
+
+ /**
+ * Gets the level of the character with the specified index.
+ *
+ * @param index the specified index of the character.
+ *
+ * @return the level of the character.
+ */
+ public byte getCharacterLevel(int index) {
+ if (index == -1 || index == getCharacterCount()) {
+ return (byte) breaker.getBaseLevel();
+ }
+ return breaker.getLevel(index);
+ }
+
+ /**
+ * Gets the descent of this TextLayout.
+ *
+ * @return the descent of this TextLayout.
+ */
+ public float getDescent() {
+ updateMetrics();
+ return metrics.getDescent();
+ }
+
+ /**
+ * Gets the TextLayout wich is justified with the specified
+ * width related to this TextLayout.
+ *
+ * @param justificationWidth the width which is used
+ * for justification.
+ *
+ * @return a TextLayout justified to the specified width.
+ *
+ * @throws Error the error occures if this TextLayout has been
+ * already justified.
+ */
+ public TextLayout getJustifiedLayout(float justificationWidth) throws Error {
+ float justification = breaker.getJustification();
+
+ if (justification < 0) {
+ // awt.196=Justification impossible, layout already justified
+ throw new Error(Messages.getString("awt.196")); //$NON-NLS-1$
+ } else if (justification == 0) {
+ return this;
+ }
+
+ TextLayout justifiedLayout = new TextLayout((TextRunBreaker) breaker.clone());
+ justifiedLayout.handleJustify(justificationWidth);
+ return justifiedLayout;
+ }
+
+ /**
+ * Gets the leading of this TextLayout.
+ *
+ * @return the leading of this TextLayout.
+ */
+ public float getLeading() {
+ updateMetrics();
+ return metrics.getLeading();
+ }
+
+ /**
+ * Gets a Shape representing the logical selection betweeen
+ * the specified endpoints and extended to the natural
+ * bounds of this TextLayout.
+ *
+ * @param firstEndpoint the first selected endpoint within the area of characters
+ * @param secondEndpoint the second selected endpoint within the area of characters
+ *
+ * @return a Shape represented the logical selection betweeen
+ * the specified endpoints.
+ */
+ public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) {
+ updateMetrics();
+ return getLogicalHighlightShape(firstEndpoint, secondEndpoint, breaker.getLogicalBounds());
+ }
+
+ /**
+ * Gets a Shape representing the logical selection betweeen
+ * the specified endpoints and extended to the specified
+ * bounds of this TextLayout.
+ *
+ * @param firstEndpoint the first selected endpoint within the area of characters
+ * @param secondEndpoint the second selected endpoint within the area of characters
+ * @param bounds the specified bounds of this TextLayout.
+ *
+ * @return a Shape represented the logical selection betweeen
+ * the specified endpoints.
+ */
+ public Shape getLogicalHighlightShape(
+ int firstEndpoint,
+ int secondEndpoint,
+ Rectangle2D bounds
+ ) {
+ updateMetrics();
+
+ if (firstEndpoint > secondEndpoint) {
+ if (secondEndpoint < 0 || firstEndpoint > breaker.getCharCount()) {
+ // awt.197=Endpoints are out of range
+ throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$
+ }
+ return caretManager.getLogicalHighlightShape(
+ secondEndpoint,
+ firstEndpoint,
+ bounds,
+ this
+ );
+ }
+ if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) {
+ // awt.197=Endpoints are out of range
+ throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$
+ }
+ return caretManager.getLogicalHighlightShape(
+ firstEndpoint,
+ secondEndpoint,
+ bounds,
+ this
+ );
+ }
+
+ /**
+ * Gets the logical ranges of text which corresponds to a visual
+ * selection.
+ *
+ * @param hit1 the first endpoint of the visual range.
+ * @param hit2 the second endpoint of the visual range.
+ *
+ * @return the logical ranges of text which corresponds to a visual
+ * selection.
+ */
+ public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) {
+ return caretManager.getLogicalRangesForVisualSelection(hit1, hit2);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified offset.
+ *
+ * @param offset the offset in this TextLayout.
+ *
+ * @return the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified hit, or null
+ * if there is no hit.
+ */
+ public TextHitInfo getNextLeftHit(int offset) {
+ return getNextLeftHit(offset, DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified hit.
+ *
+ * @param hitInfo the initial hit.
+ *
+ * @return the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified hit, or null
+ * if there is no hit.
+ */
+ public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
+ breaker.createAllSegments();
+ return caretManager.getNextLeftHit(hitInfo);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified offset, given the
+ * specified caret policy.
+ *
+ * @param offset the offset in this TextLayout.
+ * @param policy the policy to be used for obtaining the strong caret.
+ *
+ * @return the TextHitInfo for the next caret to the left of the
+ * specified offset, or null if there is no hit.
+ */
+ public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) {
+ if (offset < 0 || offset > breaker.getCharCount()) {
+ // awt.195=Offset is out of bounds
+ throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+ }
+
+ TextHitInfo hit = TextHitInfo.afterOffset(offset);
+ TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this);
+ TextHitInfo nextLeftHit = getNextLeftHit(strongHit);
+
+ if (nextLeftHit != null) {
+ return policy.getStrongCaret(getVisualOtherHit(nextLeftHit), nextLeftHit, this);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified hit.
+ *
+ * @param hitInfo the initial hit.
+ *
+ * @return the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified hit, or null
+ * if there is no hit.
+ */
+ public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
+ breaker.createAllSegments();
+ return caretManager.getNextRightHit(hitInfo);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified offset.
+ *
+ * @param offset the offset in this TextLayout.
+ *
+ * @return the TextHitInfo for the next caret to the right of the
+ * specified offset, or null if there is no hit.
+ */
+ public TextHitInfo getNextRightHit(int offset) {
+ return getNextRightHit(offset, DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified offset, given the
+ * specified caret policy.
+ *
+ * @param offset the offset in this TextLayout.
+ * @param policy the policy to be used for obtaining the strong caret.
+ *
+ * @return the TextHitInfo for the next caret to the right of the
+ * specified offset, or null if there is no hit.
+ */
+ public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) {
+ if (offset < 0 || offset > breaker.getCharCount()) {
+ // awt.195=Offset is out of bounds
+ throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+ }
+
+ TextHitInfo hit = TextHitInfo.afterOffset(offset);
+ TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this);
+ TextHitInfo nextRightHit = getNextRightHit(strongHit);
+
+ if (nextRightHit != null) {
+ return policy.getStrongCaret(getVisualOtherHit(nextRightHit), nextRightHit, this);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the outline of this TextLayout as a Shape.
+ *
+ * @param xform the AffineTransform to be used to transform
+ * the outline before returning it, or null if no transformation
+ * is desired.
+ *
+ * @return the outline of this TextLayout as a Shape.
+ */
+ public Shape getOutline(AffineTransform xform) {
+ breaker.createAllSegments();
+
+ GeneralPath outline = breaker.getOutline();
+
+ if (outline != null && xform != null) {
+ outline.transform(xform);
+ }
+
+ return outline;
+ }
+
+ /**
+ * Gets the visible advance of this TextLayout which is defined as
+ * diffence between leading (advance) and trailing whitespace.
+ *
+ * @return the visible advance of this TextLayout.
+ */
+ public float getVisibleAdvance() {
+ updateMetrics();
+
+ // Trailing whitespace _SHOULD_ be reordered (Unicode spec) to
+ // base direction, so it is also trailing
+ // in logical representation. We use this fact.
+ int lastNonWhitespace = breaker.getLastNonWhitespace();
+
+ if (lastNonWhitespace < 0) {
+ return 0;
+ } else if (lastNonWhitespace == getCharacterCount()-1) {
+ return getAdvance();
+ } else if (justificationWidth >= 0) { // Layout is justified
+ return justificationWidth;
+ } else {
+ breaker.pushSegments(
+ breaker.getACI().getBeginIndex(),
+ lastNonWhitespace + breaker.getACI().getBeginIndex() + 1
+ );
+
+ breaker.createAllSegments();
+
+ float visAdvance = tmc.createMetrics().getAdvance();
+
+ breaker.popSegments();
+ return visAdvance;
+ }
+ }
+
+ /**
+ * Gets a Shape which corresponds to the highlighted (selected) area
+ * based on two hit locations within the text and extends to the bounds.
+ *
+ * @param hit1 the first text hit location.
+ * @param hit2 the second text hit location.
+ * @param bounds the rectangle that the highlighted area should be
+ * extended or restricted to.
+ *
+ * @return a Shape which corresponds to the highlighted (selected) area.
+ */
+ public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) {
+ return caretManager.getVisualHighlightShape(hit1, hit2, bounds, this);
+ }
+
+ /**
+ * Gets a Shape which corresponds to the highlighted (selected) area
+ * based on two hit locations within the text.
+ *
+ * @param hit1 the first text hit location.
+ * @param hit2 the second text hit location.
+ *
+ * @return a Shape which corresponds to the highlighted (selected) area.
+ */
+ public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) {
+ breaker.createAllSegments();
+ return caretManager.getVisualHighlightShape(hit1, hit2, breaker.getLogicalBounds(), this);
+ }
+
+ /**
+ * Gets the TextHitInfo for a hit on the opposite side of the
+ * specified hit's caret.
+ *
+ * @param hitInfo the specified TextHitInfo.
+ *
+ * @return the TextHitInfo for a hit on the opposite side of the
+ * specified hit's caret.
+ */
+ public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
+ return caretManager.getVisualOtherHit(hitInfo);
+ }
+
+ /**
+ * Justifies the text; this method should be overridden
+ * by subclasses.
+ *
+ * @param justificationWidth the width for justification.
+ */
+ protected void handleJustify(float justificationWidth) {
+ float justification = breaker.getJustification();
+
+ if (justification < 0) {
+ // awt.196=Justification impossible, layout already justified
+ throw new IllegalStateException(Messages.getString("awt.196")); //$NON-NLS-1$
+ } else if (justification == 0) {
+ return;
+ }
+
+ float gap = (justificationWidth - getVisibleAdvance()) * justification;
+ breaker.justify(gap);
+ this.justificationWidth = justificationWidth;
+
+ // Correct metrics
+ tmc = new TextMetricsCalculator(breaker);
+ tmc.correctAdvance(metrics);
+ }
+
+ /**
+ * Returns a TextHitInfo object that gives information on which
+ * division point (between two characters) is corresponds to a
+ * hit (such as a mouse click) at the specified coordinates.
+ *
+ * @param x the X coordinate in this TextLayout.
+ * @param y the Y coordinate in this TextLayout.
+ *
+ * TextHitInfo object cooresponding to the given coordinates
+ * within the text.
+ */
+ public TextHitInfo hitTestChar(float x, float y) {
+ return hitTestChar(x, y, getBounds());
+ }
+
+ /**
+ * Returns a TextHitInfo object that gives information on which
+ * division point (between two characters) is corresponds to a
+ * hit (such as a mouse click) at the specified coordinates within
+ * the specified text rectangle.
+ *
+ * @param x the X coordinate in this TextLayout.
+ * @param y the Y coordinate in this TextLayout.
+ * @param bounds the bounds of the text area.
+ *
+ * TextHitInfo object cooresponding to the given coordinates
+ * within the text.
+ */
+ public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) {
+ if (x > bounds.getMaxX()) {
+ return breaker.isLTR() ?
+ TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo.leading(0);
+ }
+
+ if (x < bounds.getMinX()) {
+ return breaker.isLTR() ?
+ TextHitInfo.leading(0) : TextHitInfo.trailing(breaker.getCharCount() - 1);
+ }
+
+ return breaker.hitTest(x, y);
+ }
+
+ /**
+ * Returns true if this TextLayout has a "left to right"
+ * direction.
+ *
+ * @return true if this TextLayout has a "left to right"
+ * direction, false if this TextLayout has a "right to left"
+ * direction.
+ */
+ public boolean isLeftToRight() {
+ return breaker.isLTR();
+ }
+
+ /**
+ * Returns true if this TextLayout is vertical, false otherwise.
+ *
+ * @return true if this TextLayout is vertical, false if horizontal.
+ */
+ public boolean isVertical() {
+ return false;
+ }
+}
+
diff --git a/awt/java/awt/font/TextMeasurer.java b/awt/java/awt/font/TextMeasurer.java
new file mode 100644
index 0000000..017f3d9
--- /dev/null
+++ b/awt/java/awt/font/TextMeasurer.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+
+import java.text.AttributedCharacterIterator;
+
+import org.apache.harmony.awt.gl.font.TextMetricsCalculator;
+import org.apache.harmony.awt.gl.font.TextRunBreaker;
+
+/**
+ * The TextMeasurer class provides utilities for line break operations.
+ */
+public final class TextMeasurer implements Cloneable {
+
+ /** The aci. */
+ AttributedCharacterIterator aci;
+
+ /** The frc. */
+ FontRenderContext frc;
+
+ /** The breaker. */
+ TextRunBreaker breaker = null;
+
+ /** The tmc. */
+ TextMetricsCalculator tmc = null;
+
+ /**
+ * Instantiates a new text measurer from the specified text.
+ *
+ * @param text the source text.
+ * @param frc the FontRenderContext.
+ */
+ public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
+ this.aci = text;
+ this.frc = frc;
+ breaker = new TextRunBreaker(aci, this.frc);
+ tmc = new TextMetricsCalculator(breaker);
+ }
+
+ /**
+ * Replaces the current text with the new text, inserting a break
+ * character at the specified insert position.
+ *
+ * @param newParagraph the new paragraph text.
+ * @param insertPos the position in the text where the character is inserted.
+ */
+ public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
+ AttributedCharacterIterator oldAci = aci;
+ aci = newParagraph;
+ if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) -
+ (aci.getEndIndex() - aci.getBeginIndex()) != -1) {
+ breaker = new TextRunBreaker(aci, this.frc);
+ tmc = new TextMetricsCalculator(breaker);
+ } else {
+ breaker.insertChar(newParagraph, insertPos);
+ }
+ }
+
+ /**
+ * Replaces the current text with the new text and deletes a
+ * character at the specified position.
+ *
+ * @param newParagraph the paragraph text after deletion.
+ * @param deletePos the position in the text where the character is removed.
+ */
+ public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
+ AttributedCharacterIterator oldAci = aci;
+ aci = newParagraph;
+ if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) -
+ (aci.getEndIndex() - aci.getBeginIndex()) != 1) {
+ breaker = new TextRunBreaker(aci, this.frc);
+ tmc = new TextMetricsCalculator(breaker);
+ } else {
+ breaker.deleteChar(newParagraph, deletePos);
+ }
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return a copy of this object.
+ */
+ @Override
+ protected Object clone() {
+ return new TextMeasurer((AttributedCharacterIterator) aci.clone(), frc);
+ }
+
+ /**
+ * Returns a TextLayout of the specified character range.
+ *
+ * @param start the index of the first character.
+ * @param limit the index after the last character.
+ *
+ * @return a TextLayout for the characters beginning at "start" up
+ * to "end".
+ */
+ public TextLayout getLayout(int start, int limit) {
+ breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex());
+
+ breaker.createAllSegments();
+ TextLayout layout = new TextLayout((TextRunBreaker) breaker.clone());
+
+ breaker.popSegments();
+ return layout;
+ }
+
+ /**
+ * Returns the graphical width of a line beginning at "start"
+ * parameter and including characters up to "end" parameter.
+ * "start" and "end" are absolute indices, not relative to the
+ * "start" of the paragraph.
+ *
+ * @param start the character index at which to start measuring.
+ * @param end the character index at which to stop measuring.
+ *
+ * @return the graphical width of a line beginning at "start"
+ * and including characters up to "end".
+ */
+ public float getAdvanceBetween(int start, int end) {
+ breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex());
+
+ breaker.createAllSegments();
+ float retval = tmc.createMetrics().getAdvance();
+
+ breaker.popSegments();
+ return retval;
+ }
+
+ /**
+ * Returns the index of the first character which is not fit on
+ * a line beginning at start and possible measuring up to maxAdvance
+ * in graphical width.
+ *
+ * @param start he character index at which to start measuring.
+ * @param maxAdvance the graphical width in which the line must fit.
+ *
+ * @return the index after the last character that is fit on a line
+ * beginning at start, which is not longer than maxAdvance in graphical
+ * width.
+ */
+ public int getLineBreakIndex(int start, float maxAdvance) {
+ breaker.createAllSegments();
+ return breaker.getLineBreakIndex(
+ start - aci.getBeginIndex(), maxAdvance) + aci.getBeginIndex();
+ }
+}
+
diff --git a/awt/java/awt/font/TransformAttribute.java b/awt/java/awt/font/TransformAttribute.java
new file mode 100644
index 0000000..7c9b0bd
--- /dev/null
+++ b/awt/java/awt/font/TransformAttribute.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+import java.io.Serializable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The TransformAttribute class is a wrapper for the AffineTransform class in
+ * order to use it as attribute.
+ */
+public final class TransformAttribute implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 3356247357827709530L;
+
+ // affine transform of this TransformAttribute instance
+ /** The transform. */
+ private AffineTransform fTransform;
+
+ /**
+ * Instantiates a new TransformAttribute from the specified
+ * AffineTransform.
+ *
+ * @param transform the AffineTransform to be wrapped.
+ */
+ public TransformAttribute(AffineTransform transform) {
+ if (transform == null) {
+ // awt.94=transform can not be null
+ throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+ }
+ if (!transform.isIdentity()){
+ this.fTransform = new AffineTransform(transform);
+ }
+ }
+
+ /**
+ * Gets the initial AffineTransform which is wrapped.
+ *
+ * @return the initial AffineTransform which is wrapped.
+ */
+ public AffineTransform getTransform() {
+ if (fTransform != null){
+ return new AffineTransform(fTransform);
+ }
+ return new AffineTransform();
+ }
+
+ /**
+ * Checks if this transform is an identity transform.
+ *
+ * @return true, if this transform is an identity transform,
+ * false otherwise.
+ */
+ public boolean isIdentity() {
+ return (fTransform == null);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/AffineTransform.java b/awt/java/awt/geom/AffineTransform.java
new file mode 100644
index 0000000..5fd3934
--- /dev/null
+++ b/awt/java/awt/geom/AffineTransform.java
@@ -0,0 +1,1158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Shape;
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class AffineTransform represents a linear transformation
+ * (rotation, scaling, or shear) followed by a translation that
+ * acts on a coordinate space. It preserves colinearity of points
+ * and ratios of distances between collinear points: so if A, B,
+ * and C are on a line, then after the space has been transformed
+ * via the affine transform, the images of the three points will
+ * still be on a line, and the ratio of the distance from A to B
+ * with the distance from B to C will be the same as the corresponding
+ * ratio in the image space.
+ */
+public class AffineTransform implements Cloneable, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 1330973210523860834L;
+
+ /** The Constant TYPE_IDENTITY. */
+ public static final int TYPE_IDENTITY = 0;
+
+ /** The Constant TYPE_TRANSLATION. */
+ public static final int TYPE_TRANSLATION = 1;
+
+ /** The Constant TYPE_UNIFORM_SCALE. */
+ public static final int TYPE_UNIFORM_SCALE = 2;
+
+ /** The Constant TYPE_GENERAL_SCALE. */
+ public static final int TYPE_GENERAL_SCALE = 4;
+
+ /** The Constant TYPE_QUADRANT_ROTATION. */
+ public static final int TYPE_QUADRANT_ROTATION = 8;
+
+ /** The Constant TYPE_GENERAL_ROTATION. */
+ public static final int TYPE_GENERAL_ROTATION = 16;
+
+ /** The Constant TYPE_GENERAL_TRANSFORM. */
+ public static final int TYPE_GENERAL_TRANSFORM = 32;
+
+ /** The Constant TYPE_FLIP. */
+ public static final int TYPE_FLIP = 64;
+
+ /** The Constant TYPE_MASK_SCALE. */
+ public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE;
+
+ /** The Constant TYPE_MASK_ROTATION. */
+ public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION;
+
+ /** The <code>TYPE_UNKNOWN</code> is an initial type value. */
+ static final int TYPE_UNKNOWN = -1;
+
+ /** The min value equivalent to zero. If absolute value less then ZERO it considered as zero. */
+ static final double ZERO = 1E-10;
+
+ /** The values of transformation matrix. */
+ double m00;
+
+ /** The m10. */
+ double m10;
+
+ /** The m01. */
+ double m01;
+
+ /** The m11. */
+ double m11;
+
+ /** The m02. */
+ double m02;
+
+ /** The m12. */
+ double m12;
+
+ /** The transformation <code>type</code>. */
+ transient int type;
+
+ /**
+ * Instantiates a new affine transform of type <code>TYPE_IDENTITY</code>
+ * (which leaves coordinates unchanged).
+ */
+ public AffineTransform() {
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0;
+ m10 = m01 = m02 = m12 = 0.0;
+ }
+
+ /**
+ * Instantiates a new affine transform that has the same data as
+ * the given AffineTransform.
+ *
+ * @param t the transform to copy.
+ */
+ public AffineTransform(AffineTransform t) {
+ this.type = t.type;
+ this.m00 = t.m00;
+ this.m10 = t.m10;
+ this.m01 = t.m01;
+ this.m11 = t.m11;
+ this.m02 = t.m02;
+ this.m12 = t.m12;
+ }
+
+ /**
+ * Instantiates a new affine transform by specifying the values of the 2x3
+ * transformation matrix as floats. The type is set to the default
+ * type: <code>TYPE_UNKNOWN</code>
+ *
+ * @param m00 the m00 entry in the transformation matrix.
+ * @param m10 the m10 entry in the transformation matrix.
+ * @param m01 the m01 entry in the transformation matrix.
+ * @param m11 the m11 entry in the transformation matrix.
+ * @param m02 the m02 entry in the transformation matrix.
+ * @param m12 the m12 entry in the transformation matrix.
+ */
+ public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ /**
+ * Instantiates a new affine transform by specifying the values of the 2x3
+ * transformation matrix as doubles. The type is set to the default
+ * type: <code>TYPE_UNKNOWN</code>
+ *
+ * @param m00 the m00 entry in the transformation matrix.
+ * @param m10 the m10 entry in the transformation matrix.
+ * @param m01 the m01 entry in the transformation matrix.
+ * @param m11 the m11 entry in the transformation matrix.
+ * @param m02 the m02 entry in the transformation matrix.
+ * @param m12 the m12 entry in the transformation matrix.
+ */
+ public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ /**
+ * Instantiates a new affine transform by reading the values of the
+ * transformation matrix from an array of floats. The mapping from the
+ * array to the matrix starts with <code>matrix[0]</code> giving the
+ * top-left entry of the matrix and
+ * proceeds with the usual left-to-right and top-down ordering.
+ * <p>
+ * If the array has only four entries, then the two entries of the
+ * last row of the transformation matrix default to zero.
+ *
+ * @param matrix the array of four or six floats giving the values
+ * of the matrix.
+ *
+ * @throws ArrayIndexOutOfBoundsException if the size of the array
+ * is 0, 1, 2, 3, or 5.
+ */
+ public AffineTransform(float[] matrix) {
+ this.type = TYPE_UNKNOWN;
+ m00 = matrix[0];
+ m10 = matrix[1];
+ m01 = matrix[2];
+ m11 = matrix[3];
+ if (matrix.length > 4) {
+ m02 = matrix[4];
+ m12 = matrix[5];
+ }
+ }
+
+ /**
+ * Instantiates a new affine transform by reading the values of the
+ * transformation matrix from an array of doubles. The mapping from the
+ * array to the matrix starts with <code>matrix[0]</code> giving the
+ * top-left entry of the matrix and
+ * proceeds with the usual left-to-right and top-down ordering.
+ * <p>
+ * If the array has only four entries, then the two entries of the
+ * last row of the transformation matrix default to zero.
+ *
+ * @param matrix the array of four or six doubles giving the values
+ * of the matrix.
+ *
+ * @throws ArrayIndexOutOfBoundsException if the size of the array
+ * is 0, 1, 2, 3, or 5.
+ */
+ public AffineTransform(double[] matrix) {
+ this.type = TYPE_UNKNOWN;
+ m00 = matrix[0];
+ m10 = matrix[1];
+ m01 = matrix[2];
+ m11 = matrix[3];
+ if (matrix.length > 4) {
+ m02 = matrix[4];
+ m12 = matrix[5];
+ }
+ }
+
+
+ /**
+ * Returns type of the affine transformation.
+ * <p>
+ * The type is computed as follows: Label the entries of the
+ * transformation matrix as three rows (m00, m01), (m10, m11), and
+ * (m02, m12). Then if the original basis vectors are (1, 0) and (0, 1),
+ * the new basis vectors after transformation are given by (m00, m01)
+ * and (m10, m11), and the translation vector is (m02, m12).
+ * <p>
+ * The types are classified as follows: <br/>
+ * TYPE_IDENTITY - no change<br/>
+ * TYPE_TRANSLATION - The translation vector isn't zero<br/>
+ * TYPE_UNIFORM_SCALE - The new basis vectors have equal length<br/>
+ * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length<br/>
+ * TYPE_FLIP - The new basis vector orientation differs from the original one<br/>
+ * TYPE_QUADRANT_ROTATION - The new basis is a rotation of the original by 90, 180, 270, or 360 degrees<br/>
+ * TYPE_GENERAL_ROTATION - The new basis is a rotation of the original by an arbitrary angle<br/>
+ * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.<br/>
+ * <p>
+ * Note that multiple types are possible, thus the types can be combined
+ * using bitwise combinations.
+ *
+ * @return the type of the Affine Transform.
+ */
+ public int getType() {
+ if (type != TYPE_UNKNOWN) {
+ return type;
+ }
+
+ int type = 0;
+
+ if (m00 * m01 + m10 * m11 != 0.0) {
+ type |= TYPE_GENERAL_TRANSFORM;
+ return type;
+ }
+
+ if (m02 != 0.0 || m12 != 0.0) {
+ type |= TYPE_TRANSLATION;
+ } else
+ if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) {
+ type = TYPE_IDENTITY;
+ return type;
+ }
+
+ if (m00 * m11 - m01 * m10 < 0.0) {
+ type |= TYPE_FLIP;
+ }
+
+ double dx = m00 * m00 + m10 * m10;
+ double dy = m01 * m01 + m11 * m11;
+ if (dx != dy) {
+ type |= TYPE_GENERAL_SCALE;
+ } else
+ if (dx != 1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+
+ if ((m00 == 0.0 && m11 == 0.0) ||
+ (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0)))
+ {
+ type |= TYPE_QUADRANT_ROTATION;
+ } else
+ if (m01 != 0.0 || m10 != 0.0) {
+ type |= TYPE_GENERAL_ROTATION;
+ }
+
+ return type;
+ }
+
+ /**
+ * Gets the scale x entry of the transformation matrix
+ * (the upper left matrix entry).
+ *
+ * @return the scale x value.
+ */
+ public double getScaleX() {
+ return m00;
+ }
+
+ /**
+ * Gets the scale y entry of the transformation matrix
+ * (the lower right entry of the linear transformation).
+ *
+ * @return the scale y value.
+ */
+ public double getScaleY() {
+ return m11;
+ }
+
+ /**
+ * Gets the shear x entry of the transformation matrix
+ * (the upper right entry of the linear transformation).
+ *
+ * @return the shear x value.
+ */
+ public double getShearX() {
+ return m01;
+ }
+
+ /**
+ * Gets the shear y entry of the transformation matrix
+ * (the lower left entry of the linear transformation).
+ *
+ * @return the shear y value.
+ */
+ public double getShearY() {
+ return m10;
+ }
+
+ /**
+ * Gets the x coordinate of the translation vector.
+ *
+ * @return the x coordinate of the translation vector.
+ */
+ public double getTranslateX() {
+ return m02;
+ }
+
+ /**
+ * Gets the y coordinate of the translation vector.
+ *
+ * @return the y coordinate of the translation vector.
+ */
+ public double getTranslateY() {
+ return m12;
+ }
+
+ /**
+ * Checks if the AffineTransformation is the identity.
+ *
+ * @return true, if the AffineTransformation is the identity.
+ */
+ public boolean isIdentity() {
+ return getType() == TYPE_IDENTITY;
+ }
+
+ /**
+ * Writes the values of the transformation matrix into the given
+ * array of doubles. If the array has length 4, only the linear
+ * transformation part will be written into it. If it has length
+ * greater than 4, the translation vector will be included as well.
+ *
+ * @param matrix the array to fill with the values of the matrix.
+ *
+ * @throws ArrayIndexOutOfBoundsException if the size of the array
+ * is 0, 1, 2, 3, or 5.
+ */
+ public void getMatrix(double[] matrix) {
+ matrix[0] = m00;
+ matrix[1] = m10;
+ matrix[2] = m01;
+ matrix[3] = m11;
+ if (matrix.length > 4) {
+ matrix[4] = m02;
+ matrix[5] = m12;
+ }
+ }
+
+ /**
+ * Gets the determinant of the linear transformation matrix.
+ *
+ * @return the determinant of the linear transformation matrix.
+ */
+ public double getDeterminant() {
+ return m00 * m11 - m01 * m10;
+ }
+
+ /**
+ * Sets the transform in terms of a list of double values.
+ *
+ * @param m00 the m00 coordinate of the transformation matrix.
+ * @param m10 the m10 coordinate of the transformation matrix.
+ * @param m01 the m01 coordinate of the transformation matrix.
+ * @param m11 the m11 coordinate of the transformation matrix.
+ * @param m02 the m02 coordinate of the transformation matrix.
+ * @param m12 the m12 coordinate of the transformation matrix.
+ */
+ public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ /**
+ * Sets the transform's data to match the data of the transform
+ * sent as a parameter.
+ *
+ * @param t the transform that gives the new values.
+ */
+ public void setTransform(AffineTransform t) {
+ type = t.type;
+ setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12);
+ }
+
+ /**
+ * Sets the transform to the identity transform.
+ */
+ public void setToIdentity() {
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0;
+ m10 = m01 = m02 = m12 = 0.0;
+ }
+
+ /**
+ * Sets the transformation to a translation alone.
+ * Sets the linear part of the transformation to identity
+ * and the translation vector to the values sent as parameters.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_TRANSLATION</code>.
+ *
+ * @param mx the distance to translate in the x direction.
+ * @param my the distance to translate in the y direction.
+ */
+ public void setToTranslation(double mx, double my) {
+ m00 = m11 = 1.0;
+ m01 = m10 = 0.0;
+ m02 = mx;
+ m12 = my;
+ if (mx == 0.0 && my == 0.0) {
+ type = TYPE_IDENTITY;
+ } else {
+ type = TYPE_TRANSLATION;
+ }
+ }
+
+ /**
+ * Sets the transformation to being a scale alone, eliminating
+ * rotation, shear, and translation elements.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param scx the scaling factor in the x direction.
+ * @param scy the scaling factor in the y direction.
+ */
+ public void setToScale(double scx, double scy) {
+ m00 = scx;
+ m11 = scy;
+ m10 = m01 = m02 = m12 = 0.0;
+ if (scx != 1.0 || scy != 1.0) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ /**
+ * Sets the transformation to being a shear alone, eliminating
+ * rotation, scaling, and translation elements.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param shx the shearing factor in the x direction.
+ * @param shy the shearing factor in the y direction.
+ */
+ public void setToShear(double shx, double shy) {
+ m00 = m11 = 1.0;
+ m02 = m12 = 0.0;
+ m01 = shx;
+ m10 = shy;
+ if (shx != 0.0 || shy != 0.0) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ /**
+ * Sets the transformation to being a rotation alone, eliminating
+ * shearing, scaling, and translation elements.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ */
+ public void setToRotation(double angle) {
+ double sin = Math.sin(angle);
+ double cos = Math.cos(angle);
+ if (Math.abs(cos) < ZERO) {
+ cos = 0.0;
+ sin = sin > 0.0 ? 1.0 : -1.0;
+ } else
+ if (Math.abs(sin) < ZERO) {
+ sin = 0.0;
+ cos = cos > 0.0 ? 1.0 : -1.0;
+ }
+ m00 = m11 = cos;
+ m01 = -sin;
+ m10 = sin;
+ m02 = m12 = 0.0;
+ type = TYPE_UNKNOWN;
+ }
+
+ /**
+ * Sets the transformation to being a rotation followed by a
+ * translation.
+ * Sets the type to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ * @param px the distance to translate in the x direction.
+ * @param py the distance to translate in the y direction.
+ */
+ public void setToRotation(double angle, double px, double py) {
+ setToRotation(angle);
+ m02 = px * (1.0 - m00) + py * m10;
+ m12 = py * (1.0 - m00) - px * m10;
+ type = TYPE_UNKNOWN;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a translation alone
+ * with the translation vector given by the values sent as parameters.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_TRANSLATION</code>.
+ *
+ * @param mx the distance to translate in the x direction.
+ * @param my the distance to translate in the y direction.
+
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getTranslateInstance(double mx, double my) {
+ AffineTransform t = new AffineTransform();
+ t.setToTranslation(mx, my);
+ return t;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a scale alone.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_UNKNOWN</code>.
+ *
+ * @param scx the scaling factor in the x direction.
+ * @param scY the scaling factor in the y direction.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getScaleInstance(double scx, double scY) {
+ AffineTransform t = new AffineTransform();
+ t.setToScale(scx, scY);
+ return t;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a shear alone.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_UNKNOWN</code>.
+ *
+ * @param shx the shearing factor in the x direction.
+ * @param shy the shearing factor in the y direction.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getShearInstance(double shx, double shy) {
+ AffineTransform m = new AffineTransform();
+ m.setToShear(shx, shy);
+ return m;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a rotation alone.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getRotateInstance(double angle) {
+ AffineTransform t = new AffineTransform();
+ t.setToRotation(angle);
+ return t;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a rotation followed by a
+ * translation.
+ * Sets the type to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ * @param x the distance to translate in the x direction.
+ * @param y the distance to translate in the y direction.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getRotateInstance(double angle, double x, double y) {
+ AffineTransform t = new AffineTransform();
+ t.setToRotation(angle, x, y);
+ return t;
+ }
+
+ /**
+ * Applies a translation to this AffineTransformation.
+ *
+ * @param mx the distance to translate in the x direction.
+ * @param my the distance to translate in the y direction.
+ */
+ public void translate(double mx, double my) {
+ concatenate(AffineTransform.getTranslateInstance(mx, my));
+ }
+
+ /**
+ * Applies a scaling transformation to this AffineTransformation.
+ *
+ * @param scx the scaling factor in the x direction.
+ * @param scy the scaling factor in the y direction.
+ */
+ public void scale(double scx, double scy) {
+ concatenate(AffineTransform.getScaleInstance(scx, scy));
+ }
+
+ /**
+ * Applies a shearing transformation to this AffineTransformation.
+ *
+ * @param shx the shearing factor in the x direction.
+ * @param shy the shearing factor in the y direction.
+ */
+ public void shear(double shx, double shy) {
+ concatenate(AffineTransform.getShearInstance(shx, shy));
+ }
+
+ /**
+ * Applies a rotation transformation to this AffineTransformation.
+ *
+ * @param angle the angle of rotation in radians.
+ */
+ public void rotate(double angle) {
+ concatenate(AffineTransform.getRotateInstance(angle));
+ }
+
+ /**
+ * Applies a rotation and translation transformation to this
+ * AffineTransformation.
+ *
+ * @param angle the angle of rotation in radians.
+ * @param px the distance to translate in the x direction.
+ * @param py the distance to translate in the y direction.
+ */
+ public void rotate(double angle, double px, double py) {
+ concatenate(AffineTransform.getRotateInstance(angle, px, py));
+ }
+
+ /**
+ * Multiplies the matrix representations of two AffineTransform objects.
+ *
+ * @param t1 - the AffineTransform object is a multiplicand
+ * @param t2 - the AffineTransform object is a multiplier
+ *
+ * @return an AffineTransform object that is the result of t1 multiplied by the matrix t2.
+ */
+ AffineTransform multiply(AffineTransform t1, AffineTransform t2) {
+ return new AffineTransform(
+ t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00
+ t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01
+ t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10
+ t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11
+ t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02
+ t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12
+ }
+
+ /**
+ * Applies the given AffineTransform to this AffineTransform
+ * via matrix multiplication.
+ *
+ * @param t the AffineTransform to apply to this AffineTransform.
+ */
+ public void concatenate(AffineTransform t) {
+ setTransform(multiply(t, this));
+ }
+
+ /**
+ * Changes the current AffineTransform the one obtained by
+ * taking the transform t and applying this AffineTransform to it.
+ *
+ * @param t the AffineTransform that this AffineTransform is multiplied by.
+ */
+ public void preConcatenate(AffineTransform t) {
+ setTransform(multiply(this, t));
+ }
+
+ /**
+ * Creates an AffineTransform that is the inverse of this transform.
+ *
+ * @return the affine transform that is the inverse of this AffineTransform.
+ *
+ * @throws NoninvertibleTransformException if this AffineTransform cannot be
+ * inverted (the determinant of the linear transformation part is zero).
+ */
+ public AffineTransform createInverse() throws NoninvertibleTransformException {
+ double det = getDeterminant();
+ if (Math.abs(det) < ZERO) {
+ // awt.204=Determinant is zero
+ throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+ }
+ return new AffineTransform(
+ m11 / det, // m00
+ -m10 / det, // m10
+ -m01 / det, // m01
+ m00 / det, // m11
+ (m01 * m12 - m11 * m02) / det, // m02
+ (m10 * m02 - m00 * m12) / det // m12
+ );
+ }
+
+ /**
+ * Apply the current AffineTransform to the point.
+ *
+ * @param src the original point.
+ * @param dst Point2D object to be filled with the destination
+ * coordinates (where the original point is sent by this AffineTransform). May be null.
+ *
+ * @return the point in the AffineTransform's image space where the
+ * original point is sent.
+ */
+ public Point2D transform(Point2D src, Point2D dst) {
+ if (dst == null) {
+ if (src instanceof Point2D.Double) {
+ dst = new Point2D.Double();
+ } else {
+ dst = new Point2D.Float();
+ }
+ }
+
+ double x = src.getX();
+ double y = src.getY();
+
+ dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ return dst;
+ }
+
+ /**
+ * Applies this AffineTransform to an array of points.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length > src.length</code> or
+ * <code>dstOff + length > dst.length</code>.
+ */
+ public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ Point2D srcPoint = src[srcOff++];
+ double x = srcPoint.getX();
+ double y = srcPoint.getY();
+ Point2D dstPoint = dst[dstOff];
+ if (dstPoint == null) {
+ if (srcPoint instanceof Point2D.Double) {
+ dstPoint = new Point2D.Double();
+ } else {
+ dstPoint = new Point2D.Float();
+ }
+ }
+ dstPoint.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ dst[dstOff++] = dstPoint;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
+ int step = 2;
+ if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+ srcOff = srcOff + length * 2 - 2;
+ dstOff = dstOff + length * 2 - 2;
+ step = -2;
+ }
+ while (--length >= 0) {
+ double x = src[srcOff + 0];
+ double y = src[srcOff + 1];
+ dst[dstOff + 0] = x * m00 + y * m01 + m02;
+ dst[dstOff + 1] = x * m10 + y * m11 + m12;
+ srcOff += step;
+ dstOff += step;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of float values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+ int step = 2;
+ if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+ srcOff = srcOff + length * 2 - 2;
+ dstOff = dstOff + length * 2 - 2;
+ step = -2;
+ }
+ while (--length >= 0) {
+ float x = src[srcOff + 0];
+ float y = src[srcOff + 1];
+ dst[dstOff + 0] = (float)(x * m00 + y * m01 + m02);
+ dst[dstOff + 1] = (float)(x * m10 + y * m11 + m12);
+ srcOff += step;
+ dstOff += step;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of float values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ * The destination coordinates are given as values of type <code>double</code>.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(float[] src, int srcOff, double[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ float x = src[srcOff++];
+ float y = src[srcOff++];
+ dst[dstOff++] = x * m00 + y * m01 + m02;
+ dst[dstOff++] = x * m10 + y * m11 + m12;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ * The destination coordinates are given as values of type <code>float</code>.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(double[] src, int srcOff, float[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ double x = src[srcOff++];
+ double y = src[srcOff++];
+ dst[dstOff++] = (float)(x * m00 + y * m01 + m02);
+ dst[dstOff++] = (float)(x * m10 + y * m11 + m12);
+ }
+ }
+
+ /**
+ * Transforms the point according to the linear transformation
+ * part of this AffineTransformation (without applying the translation).
+ *
+ * @param src the original point.
+ * @param dst the point object where the result of the delta transform
+ * is written.
+ *
+ * @return the result of applying the delta transform (linear part
+ * only) to the original point.
+ */
+ // TODO: is this right? if dst is null, we check what it's an
+ // instance of? Shouldn't it be src instanceof Point2D.Double?
+ public Point2D deltaTransform(Point2D src, Point2D dst) {
+ if (dst == null) {
+ if (dst instanceof Point2D.Double) {
+ dst = new Point2D.Double();
+ } else {
+ dst = new Point2D.Float();
+ }
+ }
+
+ double x = src.getX();
+ double y = src.getY();
+
+ dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
+ return dst;
+ }
+
+ /**
+ * Applies the linear transformation part of this AffineTransform
+ * (ignoring the translation part) to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the delta transformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ double x = src[srcOff++];
+ double y = src[srcOff++];
+ dst[dstOff++] = x * m00 + y * m01;
+ dst[dstOff++] = x * m10 + y * m11;
+ }
+ }
+
+ /**
+ * Transforms the point according to the inverse of this AffineTransformation.
+ *
+ * @param src the original point.
+ * @param dst the point object where the result of the inverse transform
+ * is written (may be null).
+ *
+ * @return the result of applying the inverse transform.
+ * Inverse transform.
+ *
+ * @throws NoninvertibleTransformException if this AffineTransform cannot be
+ * inverted (the determinant of the linear transformation part is zero).
+ */
+ public Point2D inverseTransform(Point2D src, Point2D dst) throws NoninvertibleTransformException {
+ double det = getDeterminant();
+ if (Math.abs(det) < ZERO) {
+ // awt.204=Determinant is zero
+ throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+ }
+
+ if (dst == null) {
+ if (src instanceof Point2D.Double) {
+ dst = new Point2D.Double();
+ } else {
+ dst = new Point2D.Float();
+ }
+ }
+
+ double x = src.getX() - m02;
+ double y = src.getY() - m12;
+
+ dst.setLocation((x * m11 - y * m01) / det, (y * m00 - x * m10) / det);
+ return dst;
+ }
+
+ /**
+ * Applies the inverse of this AffineTransform to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the inverse of the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ * @throws NoninvertibleTransformException if this AffineTransform cannot be
+ * inverted (the determinant of the linear transformation part is zero).
+ */
+ public void inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length)
+ throws NoninvertibleTransformException
+ {
+ double det = getDeterminant();
+ if (Math.abs(det) < ZERO) {
+ // awt.204=Determinant is zero
+ throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+ }
+
+ while (--length >= 0) {
+ double x = src[srcOff++] - m02;
+ double y = src[srcOff++] - m12;
+ dst[dstOff++] = (x * m11 - y * m01) / det;
+ dst[dstOff++] = (y * m00 - x * m10) / det;
+ }
+ }
+
+ /**
+ * Creates a new shape whose data is given by applying this
+ * AffineTransform to the specified shape.
+ *
+ * @param src the original shape whose data is to be transformed.
+ *
+ * @return the new shape found by applying this AffineTransform to
+ * the original shape.
+ */
+ public Shape createTransformedShape(Shape src) {
+ if (src == null) {
+ return null;
+ }
+ if (src instanceof GeneralPath) {
+ return ((GeneralPath)src).createTransformedShape(this);
+ }
+ PathIterator path = src.getPathIterator(this);
+ GeneralPath dst = new GeneralPath(path.getWindingRule());
+ dst.append(path, false);
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ return
+ getClass().getName() +
+ "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(m00);
+ hash.append(m01);
+ hash.append(m02);
+ hash.append(m10);
+ hash.append(m11);
+ hash.append(m12);
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AffineTransform) {
+ AffineTransform t = (AffineTransform)obj;
+ return
+ m00 == t.m00 && m01 == t.m01 &&
+ m02 == t.m02 && m10 == t.m10 &&
+ m11 == t.m11 && m12 == t.m12;
+ }
+ return false;
+ }
+
+
+ /**
+ * Writes the AffineTrassform object to the output steam.
+ *
+ * @param stream - the output stream
+ *
+ * @throws IOException - if there are I/O errors while writing to the output strem
+ */
+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ }
+
+
+ /**
+ * Read the AffineTransform object from the input stream.
+ *
+ * @param stream - the input steam
+ *
+ * @throws IOException - if there are I/O errors while reading from the input strem
+ * @throws ClassNotFoundException - if class could not be found
+ */
+ private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ type = TYPE_UNKNOWN;
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Arc2D.java b/awt/java/awt/geom/Arc2D.java
new file mode 100644
index 0000000..bc1e95c
--- /dev/null
+++ b/awt/java/awt/geom/Arc2D.java
@@ -0,0 +1,1028 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Arc2D represents a segment of a curve inscribed
+ * in a rectangle. The curve is defined by a start angle and an
+ * extent angle (the end angle minus the start angle) as
+ * a pie wedge whose point is in the center of the rectangle.
+ * The Arc2D as a shape may be either OPEN (including nothing
+ * but the curved arc segment itself), CHORD (the curved arc
+ * segment closed by a connecting segment from the end to the
+ * beginning of the arc, or PIE (the segments from the end
+ * of the arc to the center of the rectangle and from the
+ * center of the rectangle back to the arc's start point are
+ * included).
+ */
+public abstract class Arc2D extends RectangularShape {
+
+ /** The arc type OPEN indicates that the shape includes only the
+ * curved arc segment. */
+ public final static int OPEN = 0;
+
+ /** The arc type CHORD indicates that as a shape the connecting
+ * segment from the end point of the curved arc to the beginning
+ * point is included. */
+ public final static int CHORD = 1;
+
+ /** The arc type PIE indicates that as a shape the two segments
+ * from the arc's endpoint to the center of the rectangle and from
+ * the center of the rectangle to the arc's endpoint are included. */
+ public final static int PIE = 2;
+
+ /**
+ * The Class Float is a subclass of Arc2D in which all of the
+ * data values are given as floats.
+ * @see Arc2D.Double
+ */
+ public static class Float extends Arc2D {
+
+ /** The x coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public float x;
+
+ /** The y coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public float y;
+
+ /** The width of the rectangle that contains the arc. */
+ public float width;
+
+ /** The height of the rectangle that contains the arc. */
+ public float height;
+
+ /** The start angle of the arc in degrees. */
+ public float start;
+
+ /** The width angle of the arc in degrees. */
+ public float extent;
+
+ /**
+ * Instantiates a new Arc2D of type OPEN with float values.
+ */
+ public Float() {
+ super(OPEN);
+ }
+
+ /**
+ * Instantiates a new Arc2D of the specified type with float values.
+ *
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Float(int type) {
+ super(type);
+ }
+
+ /**
+ * Instantiates a Arc2D with the specified float-valued data.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param y the y coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param width the width of the rectangle that
+ * contains the arc.
+ * @param height the height of the rectangle that
+ * contains the arc.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Float(float x, float y, float width, float height, float start, float extent, int type) {
+ super(type);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.start = start;
+ this.extent = extent;
+ }
+
+ /**
+ * Instantiates a new Angle2D with the specified float-valued data
+ * and the bounding rectangle given by the parameter bounds.
+ *
+ * @param bounds the bounding rectangle of the Angle2D.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Float(Rectangle2D bounds, float start, float extent, int type) {
+ super(type);
+ this.x = (float)bounds.getX();
+ this.y = (float)bounds.getY();
+ this.width = (float)bounds.getWidth();
+ this.height = (float)bounds.getHeight();
+ this.start = start;
+ this.extent = extent;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getAngleStart() {
+ return start;
+ }
+
+ @Override
+ public double getAngleExtent() {
+ return extent;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0f || height <= 0.0f;
+ }
+
+ @Override
+ public void setArc(double x, double y, double width, double height,
+ double start, double extent, int type)
+ {
+ this.setArcType(type);
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ this.start = (float)start;
+ this.extent = (float)extent;
+ }
+
+ @Override
+ public void setAngleStart(double start) {
+ this.start = (float)start;
+ }
+
+ @Override
+ public void setAngleExtent(double extent) {
+ this.extent = (float)extent;
+ }
+
+ @Override
+ protected Rectangle2D makeBounds(double x, double y, double width, double height) {
+ return new Rectangle2D.Float((float)x, (float)y, (float)width, (float)height);
+ }
+
+ }
+
+ /**
+ * The Class Double is a subclass of Arc2D in which all of the
+ * data values are given as doubles.
+ * @see Arc2D.Float
+ */
+ public static class Double extends Arc2D {
+
+ /** The x coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public double x;
+
+ /** The y coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public double y;
+
+ /** The width of the rectangle that contains the arc. */
+ public double width;
+
+ /** The height of the rectangle that contains the arc. */
+ public double height;
+
+ /** The start angle of the arc in degrees. */
+ public double start;
+
+ /** The width angle of the arc in degrees. */
+ public double extent;
+
+ /**
+ * Instantiates a new Arc2D of type OPEN with double values.
+ */
+ public Double() {
+ super(OPEN);
+ }
+
+ /**
+ * Instantiates a new Arc2D of the specified type with double values.
+ *
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Double(int type) {
+ super(type);
+ }
+
+ /**
+ * Instantiates a Arc2D with the specified double-valued data.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param y the y coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param width the width of the rectangle that
+ * contains the arc.
+ * @param height the height of the rectangle that
+ * contains the arc.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Double(double x, double y, double width, double height,
+ double start, double extent, int type)
+ {
+ super(type);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.start = start;
+ this.extent = extent;
+ }
+
+ /**
+ * Instantiates a new Angle2D with the specified float-valued data
+ * and the bounding rectangle given by the parameter bounds.
+ *
+ * @param bounds the bounding rectangle of the Angle2D.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Double(Rectangle2D bounds, double start, double extent, int type) {
+ super(type);
+ this.x = bounds.getX();
+ this.y = bounds.getY();
+ this.width = bounds.getWidth();
+ this.height = bounds.getHeight();
+ this.start = start;
+ this.extent = extent;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getAngleStart() {
+ return start;
+ }
+
+ @Override
+ public double getAngleExtent() {
+ return extent;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setArc(double x, double y, double width, double height,
+ double start, double extent, int type)
+ {
+ this.setArcType(type);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.start = start;
+ this.extent = extent;
+ }
+
+ @Override
+ public void setAngleStart(double start) {
+ this.start = start;
+ }
+
+ @Override
+ public void setAngleExtent(double extent) {
+ this.extent = extent;
+ }
+
+ @Override
+ protected Rectangle2D makeBounds(double x, double y, double width, double height) {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+
+ }
+
+ /**
+ * The Class Iterator is the subclass of PathIterator that is used to
+ * traverse the boundary of a shape of type Arc2D.
+ */
+ class Iterator implements PathIterator {
+
+ /** The x coordinate of the center of the arc's bounding rectangle. */
+ double x;
+
+ /** The y coordinate of the center of the arc's bounding rectangle. */
+ double y;
+
+ /** Half of the width of the arc's bounding rectangle (the radius in the case of a circular arc). */
+ double width;
+
+ /** Half of the height of the arc's bounding rectangle (the radius in the case of a circular arc). */
+ double height;
+
+ /** The start angle of the arc in degrees. */
+ double angle;
+
+ /** The angle extent in degrees. */
+ double extent;
+
+ /** The closure type of the arc. */
+ int type;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segment index. */
+ int index;
+
+ /** The number of arc segments the source arc subdivided to be approximated by Bezier curves. Depends on extent value. */
+ int arcCount;
+
+ /** The number of line segments. Depends on closure type. */
+ int lineCount;
+
+ /** The step to calculate next arc subdivision point. */
+ double step;
+
+ /** The temporary value of cosinus of the current angle. */
+ double cos;
+
+ /** The temporary value of sinus of the current angle. */
+ double sin;
+
+ /** The coefficient to calculate control points of Bezier curves. */
+ double k;
+
+ /** The temporary value of x coordinate of the Bezier curve control vector. */
+ double kx;
+
+ /** The temporary value of y coordinate of the Bezier curve control vector. */
+ double ky;
+
+ /** The x coordinate of the first path point (MOVE_TO). */
+ double mx;
+
+ /** The y coordinate of the first path point (MOVE_TO). */
+ double my;
+
+ /**
+ * Constructs a new Arc2D.Iterator for given line and transformation
+ *
+ * @param a - the source Arc2D object
+ * @param t the AffineTransformation.
+ */
+ Iterator(Arc2D a, AffineTransform t) {
+ if (width < 0 || height < 0) {
+ arcCount = 0;
+ lineCount = 0;
+ index = 1;
+ return;
+ }
+
+ this.width = a.getWidth() / 2.0;
+ this.height = a.getHeight() / 2.0;
+ this.x = a.getX() + width;
+ this.y = a.getY() + height;
+ this.angle = -Math.toRadians(a.getAngleStart());
+ this.extent = -a.getAngleExtent();
+ this.type = a.getArcType();
+ this.t = t;
+
+ if (Math.abs(extent) >= 360.0) {
+ arcCount = 4;
+ k = 4.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+ step = Math.PI / 2.0;
+ if (extent < 0.0) {
+ step = -step;
+ k = -k;
+ }
+ } else {
+ arcCount = (int)Math.rint(Math.abs(extent) / 90.0);
+ step = Math.toRadians(extent / arcCount);
+ k = 4.0 / 3.0 * (1.0 - Math.cos(step / 2.0))
+ / Math.sin(step / 2.0);
+ }
+
+ lineCount = 0;
+ if (type == Arc2D.CHORD) {
+ lineCount++;
+ } else if (type == Arc2D.PIE) {
+ lineCount += 2;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > arcCount + lineCount;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[0] = mx = x + cos * width;
+ coords[1] = my = y + sin * height;
+ } else if (index <= arcCount) {
+ type = SEG_CUBICTO;
+ count = 3;
+ coords[0] = mx - kx;
+ coords[1] = my + ky;
+ angle += step;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[4] = mx = x + cos * width;
+ coords[5] = my = y + sin * height;
+ coords[2] = mx + kx;
+ coords[3] = my - ky;
+ } else if (index == arcCount + lineCount) {
+ type = SEG_CLOSE;
+ count = 0;
+ } else {
+ type = SEG_LINETO;
+ count = 1;
+ coords[0] = x;
+ coords[1] = y;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[0] = (float)(mx = x + cos * width);
+ coords[1] = (float)(my = y + sin * height);
+ } else if (index <= arcCount) {
+ type = SEG_CUBICTO;
+ count = 3;
+ coords[0] = (float)(mx - kx);
+ coords[1] = (float)(my + ky);
+ angle += step;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[4] = (float)(mx = x + cos * width);
+ coords[5] = (float)(my = y + sin * height);
+ coords[2] = (float)(mx + kx);
+ coords[3] = (float)(my - ky);
+ } else if (index == arcCount + lineCount) {
+ type = SEG_CLOSE;
+ count = 0;
+ } else {
+ type = SEG_LINETO;
+ count = 1;
+ coords[0] = (float)x;
+ coords[1] = (float)y;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /** The closure type of the arc. */
+ private int type;
+
+ /**
+ * Instantiates a new arc2D.
+ *
+ * @param type the closure type.
+ */
+ protected Arc2D(int type) {
+ setArcType(type);
+ }
+
+ /**
+ * Takes the double-valued data and creates the corresponding Rectangle2D
+ * object with values either of type float or of type double depending on
+ * whether this Arc2D instance is of type Float or Double.
+ *
+ * @param x the x coordinate of the upper left corner of the bounding rectangle.
+ * @param y the y coordinate of the upper left corner of the bounding rectangle.
+ * @param width the width of the bounding rectangle.
+ * @param height the height of the bounding rectangle.
+ *
+ * @return the corresponding Rectangle2D object.
+ */
+ protected abstract Rectangle2D makeBounds(double x, double y, double width, double height);
+
+ /**
+ * Gets the start angle.
+ *
+ * @return the start angle.
+ */
+ public abstract double getAngleStart();
+
+ /**
+ * Gets the width angle.
+ *
+ * @return the width angle.
+ */
+ public abstract double getAngleExtent();
+
+ /**
+ * Sets the start angle.
+ *
+ * @param start the new start angle.
+ */
+ public abstract void setAngleStart(double start);
+
+ /**
+ * Sets the width angle.
+ *
+ * @param extent the new width angle.
+ */
+ public abstract void setAngleExtent(double extent);
+
+ /**
+ * Sets the data values that define the arc.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param y the y coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param width the width of the rectangle that
+ * contains the arc.
+ * @param height the height of the rectangle that
+ * contains the arc.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public abstract void setArc(double x, double y, double width,
+ double height, double start, double extent, int type);
+
+ /**
+ * Gets the arc type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ *
+ * @return the arc type.
+ */
+ public int getArcType() {
+ return type;
+ }
+
+ /**
+ * Sets the arc type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ *
+ * @param type the new arc type.
+ */
+ public void setArcType(int type) {
+ if (type != OPEN && type != CHORD && type != PIE) {
+ // awt.205=Invalid type of Arc: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.205", type)); //$NON-NLS-1$
+ }
+ this.type = type;
+ }
+
+ /**
+ * Gets the start point of the arc as a Point2D.
+ *
+ * @return the start point of the curved arc segment.
+ */
+ public Point2D getStartPoint() {
+ double a = Math.toRadians(getAngleStart());
+ return new Point2D.Double(
+ getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0,
+ getY() + (1.0 - Math.sin(a)) * getHeight() / 2.0);
+ }
+
+ /**
+ * Gets the end point of the arc as a Point2D.
+ *
+ * @return the end point of the curved arc segment.
+ */
+ public Point2D getEndPoint() {
+ double a = Math.toRadians(getAngleStart() + getAngleExtent());
+ return new Point2D.Double(
+ getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0,
+ getY() + (1.0 - Math.sin(a)) * getHeight() / 2.0);
+ }
+
+ public Rectangle2D getBounds2D() {
+ if (isEmpty()) {
+ return makeBounds(getX(), getY(), getWidth(), getHeight());
+ }
+ double rx1 = getX();
+ double ry1 = getY();
+ double rx2 = rx1 + getWidth();
+ double ry2 = ry1 + getHeight();
+
+ Point2D p1 = getStartPoint();
+ Point2D p2 = getEndPoint();
+
+ double bx1 = containsAngle(180.0) ? rx1 : Math.min(p1.getX(), p2.getX());
+ double by1 = containsAngle(90.0) ? ry1 : Math.min(p1.getY(), p2.getY());
+ double bx2 = containsAngle(0.0) ? rx2 : Math.max(p1.getX(), p2.getX());
+ double by2 = containsAngle(270.0) ? ry2 : Math.max(p1.getY(), p2.getY());
+
+ if (type == PIE) {
+ double cx = getCenterX();
+ double cy = getCenterY();
+ bx1 = Math.min(bx1, cx);
+ by1 = Math.min(by1, cy);
+ bx2 = Math.max(bx2, cx);
+ by2 = Math.max(by2, cy);
+ }
+ return makeBounds(bx1, by1, bx2 - bx1, by2 - by1);
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ setArc(x, y, width, height, getAngleStart(), getAngleExtent(), type);
+ }
+
+ /**
+ * Sets the data that defines the arc.
+ *
+ * @param point the upper left corner of the bounding rectangle.
+ * @param size the size of the bounding rectangle.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the angle witdth of the arc in degrees.
+ * @param type the closure type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public void setArc(Point2D point, Dimension2D size, double start, double extent, int type) {
+ setArc(point.getX(), point.getY(), size.getWidth(), size.getHeight(), start, extent, type);
+ }
+
+ /**
+ * Sets the data that defines the arc.
+ *
+ * @param rect the arc's bounding rectangle.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the angle witdth of the arc in degrees.
+ * @param type the closure type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public void setArc(Rectangle2D rect, double start, double extent, int type) {
+ setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), start, extent, type);
+ }
+
+ /**
+ * Sets the data that defines the arc by copying it from another Arc2D.
+ *
+ * @param arc the arc whose data is copied into this arc.
+ */
+ public void setArc(Arc2D arc) {
+ setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc
+ .getAngleStart(), arc.getAngleExtent(), arc.getArcType());
+ }
+
+ /**
+ * Sets the data for a circular arc by giving its center and radius.
+ *
+ * @param x the x coordinate of the center of the circle.
+ * @param y the y coordinate of the center of the circle.
+ * @param radius the radius of the circle.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the angle witdth of the arc in degrees.
+ * @param type the closure type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public void setArcByCenter(double x, double y, double radius, double start, double extent, int type) {
+ setArc(x - radius, y - radius, radius * 2.0, radius * 2.0, start, extent, type);
+ }
+
+ /**
+ * Sets the arc data for a circular arc based on two tangent lines
+ * and the radius. The two tangent lines are the lines from p1
+ * to p2 and from p2 to p3, which determine a unique circle
+ * with the given radius. The start and end points of the arc
+ * are the points where the circle touches the two lines, and
+ * the arc itself is the shorter of the two circle segments
+ * determined by the two points (in other words, it is the
+ * piece of the circle that is closer to the lines' intersection
+ * point p2 and forms a concave shape with the segments from p1 to p2
+ * and from p2 to p3).
+ *
+ * @param p1 a point which determines one of the two tanget lines (with p2).
+ * @param p2 the point of intersection of the two tangent lines.
+ * @param p3 a point which determines one of the two tanget lines (with p2).
+ * @param radius the radius of the circular arc.
+ */
+ public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double radius) {
+ // Used simple geometric calculations of arc center, radius and angles by tangents
+ double a1 = -Math.atan2(p1.getY() - p2.getY(), p1.getX() - p2.getX());
+ double a2 = -Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX());
+ double am = (a1 + a2) / 2.0;
+ double ah = a1 - am;
+ double d = radius / Math.abs(Math.sin(ah));
+ double x = p2.getX() + d * Math.cos(am);
+ double y = p2.getY() - d * Math.sin(am);
+ ah = ah >= 0.0 ? Math.PI * 1.5 - ah : Math.PI * 0.5 - ah;
+ a1 = getNormAngle(Math.toDegrees(am - ah));
+ a2 = getNormAngle(Math.toDegrees(am + ah));
+ double delta = a2 - a1;
+ if (delta <= 0.0) {
+ delta += 360.0;
+ }
+ setArcByCenter(x, y, radius, a1, delta, type);
+ }
+
+ /**
+ * Sets a new start angle to be the angle given by the the vector
+ * from the current center point to the specified point.
+ *
+ * @param point the point that determines the new start angle.
+ */
+ public void setAngleStart(Point2D point) {
+ double angle = Math.atan2(point.getY() - getCenterY(), point.getX() - getCenterX());
+ setAngleStart(getNormAngle(-Math.toDegrees(angle)));
+ }
+
+ /**
+ * Sets the angles in terms of vectors from the current arc center
+ * to the points (x1, y1) and (x2, y2). The start angle is given
+ * by the vector from the current center to the point (x1, y1) and
+ * the end angle is given by the vector from the center to the point
+ * (x2, y2).
+ *
+ * @param x1 the x coordinate of the point whose vector from the center
+ * point determines the new start angle of the arc.
+ * @param y1 the y coordinate of the point whose vector from the center
+ * point determines the new start angle of the arc.
+ * @param x2 the x coordinate of the point whose vector from the center
+ * point determines the new end angle of the arc.
+ * @param y2 the y coordinate of the point whose vector from the center
+ * point determines the new end angle of the arc.
+ */
+ public void setAngles(double x1, double y1, double x2, double y2) {
+ double cx = getCenterX();
+ double cy = getCenterY();
+ double a1 = getNormAngle(-Math.toDegrees(Math.atan2(y1 - cy, x1 - cx)));
+ double a2 = getNormAngle(-Math.toDegrees(Math.atan2(y2 - cy, x2 - cx)));
+ a2 -= a1;
+ if (a2 <= 0.0) {
+ a2 += 360.0;
+ }
+ setAngleStart(a1);
+ setAngleExtent(a2);
+ }
+
+ /**
+ * Sets the angles in terms of vectors from the current arc center
+ * to the points p1 and p2. The start angle is given
+ * by the vector from the current center to the point p1 and
+ * the end angle is given by the vector from the center to the point
+ * p2.
+ *
+ * @param p1 the point whose vector from the center
+ * point determines the new start angle of the arc.
+ * @param p2 the point whose vector from the center
+ * point determines the new end angle of the arc.
+ */
+ public void setAngles(Point2D p1, Point2D p2) {
+ setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Normalizes the angle by removing extra winding (past 360 degrees)
+ * and placing it in the positive degree range.
+ *
+ * @param angle - the source angle in degrees
+ *
+ * @return an angle between 0 and 360 degrees which corresponds
+ * to the same direction vector as the source angle.
+ */
+ double getNormAngle(double angle) {
+ double n = Math.floor(angle / 360.0);
+ return angle - n * 360.0;
+ }
+
+ /**
+ * Determines whether the given angle is contained in the span of the arc.
+ *
+ * @param angle the angle to test in degrees.
+ *
+ * @return true, if the given angle is between the start angle and
+ * the end angle of the arc.
+ */
+ public boolean containsAngle(double angle) {
+ double extent = getAngleExtent();
+ if (extent >= 360.0) {
+ return true;
+ }
+ angle = getNormAngle(angle);
+ double a1 = getNormAngle(getAngleStart());
+ double a2 = a1 + extent;
+ if (a2 > 360.0) {
+ return angle >= a1 || angle <= a2 - 360.0;
+ }
+ if (a2 < 0.0) {
+ return angle >= a2 + 360.0 || angle <= a1;
+ }
+ return extent > 0.0 ? a1 <= angle && angle <= a2 : a2 <= angle
+ && angle <= a1;
+ }
+
+ public boolean contains(double px, double py) {
+ // Normalize point
+ double nx = (px - getX()) / getWidth() - 0.5;
+ double ny = (py - getY()) / getHeight() - 0.5;
+
+ if ((nx * nx + ny * ny) > 0.25) {
+ return false;
+ }
+
+ double extent = getAngleExtent();
+ double absExtent = Math.abs(extent);
+ if (absExtent >= 360.0) {
+ return true;
+ }
+
+ boolean containsAngle = containsAngle(Math.toDegrees(-Math
+ .atan2(ny, nx)));
+ if (type == PIE) {
+ return containsAngle;
+ }
+ if (absExtent <= 180.0 && !containsAngle) {
+ return false;
+ }
+
+ Line2D l = new Line2D.Double(getStartPoint(), getEndPoint());
+ int ccw1 = l.relativeCCW(px, py);
+ int ccw2 = l.relativeCCW(getCenterX(), getCenterY());
+ return ccw1 == 0 || ccw2 == 0
+ || ((ccw1 + ccw2) == 0 ^ absExtent > 180.0);
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+
+ if (!(contains(rx, ry) && contains(rx + rw, ry)
+ && contains(rx + rw, ry + rh) && contains(rx, ry + rh))) {
+ return false;
+ }
+
+ double absExtent = Math.abs(getAngleExtent());
+ if (type != PIE || absExtent <= 180.0 || absExtent >= 360.0) {
+ return true;
+ }
+
+ Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh);
+
+ double cx = getCenterX();
+ double cy = getCenterY();
+ if (r.contains(cx, cy)) {
+ return false;
+ }
+
+ Point2D p1 = getStartPoint();
+ Point2D p2 = getEndPoint();
+
+ return !r.intersectsLine(cx, cy, p1.getX(), p1.getY())
+ && !r.intersectsLine(cx, cy, p2.getX(), p2.getY());
+ }
+
+ @Override
+ public boolean contains(Rectangle2D rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ // Check: Does arc contain rectangle's points
+ if (contains(rx, ry) || contains(rx + rw, ry) || contains(rx, ry + rh)
+ || contains(rx + rw, ry + rh)) {
+ return true;
+ }
+
+ double cx = getCenterX();
+ double cy = getCenterY();
+ Point2D p1 = getStartPoint();
+ Point2D p2 = getEndPoint();
+ Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh);
+
+ // Check: Does rectangle contain arc's points
+ if (r.contains(p1) || r.contains(p2) || (type == PIE && r.contains(cx, cy))) {
+ return true;
+ }
+
+ if (type == PIE) {
+ if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy) ||
+ r.intersectsLine(p2.getX(), p2.getY(), cx, cy))
+ {
+ return true;
+ }
+ } else {
+ if (r.intersectsLine(p1.getX(), p1.getY(), p2.getX(), p2.getY())) {
+ return true;
+ }
+ }
+
+ // Nearest rectangle point
+ double nx = cx < rx ? rx : (cx > rx + rw ? rx + rw : cx);
+ double ny = cy < ry ? ry : (cy > ry + rh ? ry + rh : cy);
+ return contains(nx, ny);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Area.java b/awt/java/awt/geom/Area.java
new file mode 100644
index 0000000..bc27d4e
--- /dev/null
+++ b/awt/java/awt/geom/Area.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Area provides a minimal implementation for a generic shape.
+ */
+public class Area implements Shape, Cloneable {
+
+ /** The source Shape object. */
+ Shape s;
+
+ /**
+ * The Class NullIterator.
+ */
+ private static class NullIterator implements PathIterator {
+
+ /**
+ * Instantiates a new null iterator.
+ */
+ NullIterator() {
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return true;
+ }
+
+ public void next() {
+ // nothing
+ }
+
+ public int currentSegment(double[] coords) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+
+ public int currentSegment(float[] coords) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Instantiates a new area with no data.
+ */
+ public Area() {
+ }
+
+ /**
+ * Instantiates a new area with data given by the specified shape.
+ *
+ * @param s the shape that gives the data for this Area
+ */
+ public Area(Shape s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ this.s = s;
+ }
+
+ public boolean contains(double x, double y) {
+ return s == null ? false : s.contains(x, y);
+ }
+
+ public boolean contains(double x, double y, double width, double height) {
+ return s == null ? false : s.contains(x, y, width, height);
+ }
+
+ public boolean contains(Point2D p) {
+ if (p == null) {
+ throw new NullPointerException();
+ }
+ return s == null ? false : s.contains(p);
+ }
+
+ public boolean contains(Rectangle2D r) {
+ if (r == null) {
+ throw new NullPointerException();
+ }
+ return s == null ? false : s.contains(r);
+ }
+
+ /**
+ * Tests whether the object is equal to this Area.
+ *
+ * @param obj the object to compare
+ *
+ * @return true, if successful
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean equals(Area obj) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ public boolean intersects(double x, double y, double width, double height) {
+ return s == null ? false : s.intersects(x, y, width, height);
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ if (r == null) {
+ throw new NullPointerException();
+ }
+ return s == null ? false : s.intersects(r);
+ }
+
+ public Rectangle getBounds() {
+ return s == null ? new Rectangle() : s.getBounds();
+ }
+
+ public Rectangle2D getBounds2D() {
+ return s == null ? new Rectangle2D.Double(): s.getBounds2D();
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return s == null ? new NullIterator() : s.getPathIterator(t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return s == null ? new NullIterator() : s.getPathIterator(t, flatness);
+ }
+
+ /**
+ * Adds the specified area to this area.
+ *
+ * @param area the area to add to this area
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void add(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Performs an exclusive or operation between this shape and the
+ * specified shape.
+ *
+ * @param area the area to XOR against this area
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void exclusiveOr(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Extracts a Rectangle2D from the source shape if the underlying shape
+ * data describes a rectangle.
+ *
+ * @return a Rectangle2D object if the source shape is rectangle,
+ * or null if shape is empty or not rectangle.
+ */
+ Rectangle2D extractRectangle() {
+ if (s == null) {
+ return null;
+ }
+ float[] points = new float[12];
+ int count = 0;
+ PathIterator p = s.getPathIterator(null);
+ float[] coords = new float[6];
+ while(!p.isDone()) {
+ int type = p.currentSegment(coords);
+ if (count > 12 || type == PathIterator.SEG_QUADTO || type == PathIterator.SEG_CUBICTO) {
+ return null;
+ }
+ points[count++] = coords[0];
+ points[count++] = coords[1];
+ p.next();
+ }
+ if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4] &&
+ points[1] == points[3] && points[3] == points[9] && points[5] == points[7])
+ {
+ return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7] - points[1]);
+ }
+ return null;
+ }
+
+ /**
+ * Reduces the size of this Area by intersecting it with the
+ * specified Area if they are both rectangles.
+ *
+ * @see java.awt.geom.Rectangle2D#intersect(Rectangle2D, Rectangle2D, Rectangle2D)
+ *
+ * @param area the area
+ */
+ public void intersect(Area area) {
+ Rectangle2D src1 = extractRectangle();
+ Rectangle2D src2 = area.extractRectangle();
+ if (src1 != null && src2 != null) {
+ Rectangle2D.intersect(src1, src2, (Rectangle2D)s);
+ }
+ }
+
+ /**
+ * Subtract the specified area from this area.
+ *
+ * @param area the area to subtract
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void subtract(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is empty.
+ *
+ * @return true, if this Area is empty
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isEmpty() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is polygonal.
+ *
+ * @return true, if this Area is polygonal
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isPolygonal() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is rectangular.
+ *
+ * @return true, if this Area is rectangular
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isRectangular() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is singular.
+ *
+ * @return true, if this Area is singular
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isSingular() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Resets the data of this Area.
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void reset() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Transforms the data of this Area according to the specified
+ * AffineTransform.
+ *
+ * @param t the transform to use to transform the data
+ */
+ public void transform(AffineTransform t) {
+ s = t.createTransformedShape(s);
+ }
+
+ /**
+ * Creates a new Area that is the result of transforming the data
+ * of this Area according to the specified AffineTransform.
+ *
+ * @param t the transform to use to transform the data
+ *
+ * @return the new Area that is the result of transforming the data
+ * of this Area according to the specified AffineTransform.
+ */
+ public Area createTransformedArea(AffineTransform t) {
+ return s == null ? new Area() : new Area(t.createTransformedShape(s));
+ }
+
+ @Override
+ public Object clone() {
+ return new Area(this);
+ }
+
+}
diff --git a/awt/java/awt/geom/CubicCurve2D.java b/awt/java/awt/geom/CubicCurve2D.java
new file mode 100644
index 0000000..3e440c8
--- /dev/null
+++ b/awt/java/awt/geom/CubicCurve2D.java
@@ -0,0 +1,945 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class CubicCurve2D is a Shape that represents a segment of a
+ * quadratic (Bezier) curve. The curved segment is determined by four points:
+ * a start point, an end point, and two control points.
+ * The control points give information about the tangent and next
+ * derivative at the endpoints according to the standard theory of
+ * Bezier curves. For more information on Bezier curves,
+ * see <a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">this article</a>.
+ */
+public abstract class CubicCurve2D implements Shape, Cloneable {
+
+ /**
+ * The Class Float is the subclass of CubicCurve2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends CubicCurve2D {
+
+ /** The x coordinate of the starting point. */
+ public float x1;
+
+ /** The y coordinate of the starting point. */
+ public float y1;
+
+ /** The x coordinate of the first control point. */
+ public float ctrlx1;
+
+ /** The y coordinate of the first control point. */
+ public float ctrly1;
+
+ /** The x coordinate of the second control point. */
+ public float ctrlx2;
+
+ /** The y coordinate of the second control point. */
+ public float ctrly2;
+
+ /** The x coordinate of the end point. */
+ public float x2;
+
+ /** The y coordinate of the end point. */
+ public float y2;
+
+ /**
+ * Instantiates a new float-valued CubicCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued CubicCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x2, float y2) {
+ setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX1() {
+ return ctrlx1;
+ }
+
+ @Override
+ public double getCtrlY1() {
+ return ctrly1;
+ }
+
+ @Override
+ public double getCtrlX2() {
+ return ctrlx2;
+ }
+
+ @Override
+ public double getCtrlY2() {
+ return ctrly2;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Float(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlP1() {
+ return new Point2D.Float(ctrlx1, ctrly1);
+ }
+
+ @Override
+ public Point2D getCtrlP2() {
+ return new Point2D.Float(ctrlx2, ctrly2);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Float(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ this.x1 = (float)x1;
+ this.y1 = (float)y1;
+ this.ctrlx1 = (float)ctrlx1;
+ this.ctrly1 = (float)ctrly1;
+ this.ctrlx2 = (float)ctrlx2;
+ this.ctrly2 = (float)ctrly2;
+ this.x2 = (float)x2;
+ this.y2 = (float)y2;
+ }
+
+ /**
+ * Sets the data values of the curve.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public void setCurve(float x1, float y1, float ctrlx1, float ctrly1,
+ float ctrlx2, float ctrly2, float x2, float y2)
+ {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx1 = ctrlx1;
+ this.ctrly1 = ctrly1;
+ this.ctrlx2 = ctrlx2;
+ this.ctrly2 = ctrly2;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
+ float ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
+ float rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
+ float ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
+ return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of CubicCurve2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends CubicCurve2D {
+
+ /** The x coordinate of the starting point. */
+ public double x1;
+
+ /** The y coordinate of the starting point. */
+ public double y1;
+
+ /** The x coordinate of the first control point. */
+ public double ctrlx1;
+
+ /** The y coordinate of the first control point. */
+ public double ctrly1;
+
+ /** The x coordinate of the second control point. */
+ public double ctrlx2;
+
+ /** The y coordinate of the second control point. */
+ public double ctrly2;
+
+ /** The x coordinate of the end point. */
+ public double x2;
+
+ /** The y coordinate of the end point. */
+ public double y2;
+
+ /**
+ * Instantiates a new double-valued CubicCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued CubicCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Double(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2) {
+ setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX1() {
+ return ctrlx1;
+ }
+
+ @Override
+ public double getCtrlY1() {
+ return ctrly1;
+ }
+
+ @Override
+ public double getCtrlX2() {
+ return ctrlx2;
+ }
+
+ @Override
+ public double getCtrlY2() {
+ return ctrly2;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Double(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlP1() {
+ return new Point2D.Double(ctrlx1, ctrly1);
+ }
+
+ @Override
+ public Point2D getCtrlP2() {
+ return new Point2D.Double(ctrlx2, ctrly2);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Double(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx1 = ctrlx1;
+ this.ctrly1 = ctrly1;
+ this.ctrlx2 = ctrlx2;
+ this.ctrly2 = ctrly2;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ double rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
+ double ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
+ double rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
+ double ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
+ return new Rectangle2D.Double(rx1, ry1, rx2 - rx1, ry2 - ry1);
+ }
+ }
+
+ /*
+ * CubicCurve2D path iterator
+ */
+ /**
+ * The Iterator class for the Shape CubicCurve2D.
+ */
+ class Iterator implements PathIterator {
+
+ /** The source CubicCurve2D object. */
+ CubicCurve2D c;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new CubicCurve2D.Iterator for given line and transformation
+ *
+ * @param c - the source CubicCurve2D object
+ * @param t the t
+ */
+ Iterator(CubicCurve2D c, AffineTransform t) {
+ this.c = c;
+ this.t = t;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 1;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = c.getX1();
+ coords[1] = c.getY1();
+ count = 1;
+ } else {
+ type = SEG_CUBICTO;
+ coords[0] = c.getCtrlX1();
+ coords[1] = c.getCtrlY1();
+ coords[2] = c.getCtrlX2();
+ coords[3] = c.getCtrlY2();
+ coords[4] = c.getX2();
+ coords[5] = c.getY2();
+ count = 3;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = (float)c.getX1();
+ coords[1] = (float)c.getY1();
+ count = 1;
+ } else {
+ type = SEG_CUBICTO;
+ coords[0] = (float)c.getCtrlX1();
+ coords[1] = (float)c.getCtrlY1();
+ coords[2] = (float)c.getCtrlX2();
+ coords[3] = (float)c.getCtrlY2();
+ coords[4] = (float)c.getX2();
+ coords[5] = (float)c.getY2();
+ count = 3;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new 2-D cubic curve.
+ */
+ protected CubicCurve2D() {
+ }
+
+ /**
+ * Gets the x coordinate of the starting point.
+ *
+ * @return the x coordinate of the starting point
+ */
+ public abstract double getX1();
+
+ /**
+ * Gets the y coordinate of the starting point.
+ *
+ * @return the y coordinate of the starting point
+ */
+ public abstract double getY1();
+
+ /**
+ * Gets the starting point.
+ *
+ * @return the starting point
+ */
+ public abstract Point2D getP1();
+
+ /**
+ * Gets the x coordinate of the first control point.
+ *
+ * @return the x coordinate of the first control point
+ */
+ public abstract double getCtrlX1();
+
+ /**
+ * Gets the y coordinate of the first control point.
+ *
+ * @return the y coordinate of the first control point
+ */
+ public abstract double getCtrlY1();
+
+ /**
+ * Gets the second control point.
+ *
+ * @return the second control point
+ */
+ public abstract Point2D getCtrlP1();
+
+ /**
+ * Gets the x coordinate of the second control point.
+ *
+ * @return the x coordinate of the second control point
+ */
+ public abstract double getCtrlX2();
+
+ /**
+ * Gets the y coordinate of the second control point.
+ *
+ * @return the y coordinate of the second control point
+ */
+ public abstract double getCtrlY2();
+
+ /**
+ * Gets the second control point.
+ *
+ * @return the second control point
+ */
+ public abstract Point2D getCtrlP2();
+
+ /**
+ * Gets the x coordinate of the end point.
+ *
+ * @return the x coordinate of the end point
+ */
+ public abstract double getX2();
+
+ /**
+ * Gets the y coordinate of the end point.
+ *
+ * @return the y coordinate of the end point
+ */
+ public abstract double getY2();
+
+ /**
+ * Gets the end point.
+ *
+ * @return the end point
+ */
+ public abstract Point2D getP2();
+
+ /**
+ * Sets the data of the curve.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public abstract void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2);
+
+ /**
+ * Sets the data of the curve as point objects.
+ *
+ * @param p1 the starting point
+ * @param cp1 the first control point
+ * @param cp2 the second control point
+ * @param p2 the end point
+ *
+ * @throws NullPointerException if any of the points is null.
+ */
+ public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
+ setCurve(
+ p1.getX(), p1.getY(),
+ cp1.getX(), cp1.getY(),
+ cp2.getX(), cp2.getY(),
+ p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of values. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#setCurve(double, double, double, double, double, double, double, double)}.
+ *
+ * @param coords the array of values containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 8.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public void setCurve(double[] coords, int offset) {
+ setCurve(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 6], coords[offset + 7]);
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of points. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#setCurve(Point2D, Point2D, Point2D, Point2D)}
+ *
+ * @param points the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + .
+ * @throws NullPointerException if the point array is null.
+ */
+ public void setCurve(Point2D[] points, int offset) {
+ setCurve(
+ points[offset + 0].getX(), points[offset + 0].getY(),
+ points[offset + 1].getX(), points[offset + 1].getY(),
+ points[offset + 2].getX(), points[offset + 2].getY(),
+ points[offset + 3].getX(), points[offset + 3].getY());
+ }
+
+ /**
+ * Sets the data of the curve by copying it from another CubicCurve2D.
+ *
+ * @param curve the curve to copy the data points from
+ *
+ * @throws NullPointerException if the curve is null.
+ */
+ public void setCurve(CubicCurve2D curve) {
+ setCurve(
+ curve.getX1(), curve.getY1(),
+ curve.getCtrlX1(), curve.getCtrlY1(),
+ curve.getCtrlX2(), curve.getCtrlY2(),
+ curve.getX2(), curve.getY2());
+ }
+
+ /**
+ * Gets the square of the flatness of this curve, where the flatness is the
+ * maximum distance from the curves control points to the
+ * line segment connecting the two points.
+ *
+ * @return the square of the flatness
+ */
+ public double getFlatnessSq() {
+ return getFlatnessSq(
+ getX1(), getY1(),
+ getCtrlX1(), getCtrlY1(),
+ getCtrlX2(), getCtrlY2(),
+ getX2(), getY2());
+ }
+
+ /**
+ * Gets the square of the flatness of the cubic curve segment
+ * defined by the specified values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ *
+ * @return the square of the flatness
+ */
+ public static double getFlatnessSq(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ return Math.max(
+ Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1),
+ Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2));
+ }
+
+ /**
+ * Gets the square of the flatness of the cubic curve segment
+ * defined by the specified values. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#getFlatnessSq(double, double, double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the square of the flatness
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + .
+ * @throws NullPointerException if the point array is null.
+ */
+ public static double getFlatnessSq(double coords[], int offset) {
+ return getFlatnessSq(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 6], coords[offset + 7]);
+ }
+
+ /**
+ * Gets the flatness of this curve, where the flatness is the
+ * maximum distance from the curves control points to the
+ * line segment connecting the two points.
+ *
+ * @return the flatness of this curve
+ */
+ public double getFlatness() {
+ return getFlatness(
+ getX1(), getY1(),
+ getCtrlX1(), getCtrlY1(),
+ getCtrlX2(), getCtrlY2(),
+ getX2(), getY2());
+ }
+
+ /**
+ * Gets the flatness of the cubic curve segment
+ * defined by the specified values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ *
+ * @return the flatness
+ */
+ public static double getFlatness(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
+ }
+
+ /**
+ * Gets the flatness of the cubic curve segment
+ * defined by the specified values. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#getFlatness(double, double, double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the flatness
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + .
+ * @throws NullPointerException if the point array is null.
+ */
+ public static double getFlatness(double coords[], int offset) {
+ return getFlatness(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 6], coords[offset + 7]);
+ }
+
+ /**
+ * Creates the data for two cubic curves by dividing this
+ * curve in two. The division point is the point on the curve
+ * that is closest to the average of curve's two control points.
+ * The two new control points (nearest the new endpoint) are computed
+ * by averaging the original control points with the new endpoint.
+ * The data of this curve is left unchanged.
+ *
+ * @param left the CubicCurve2D where the left (start) segment's
+ * data is written
+ * @param right the CubicCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if either curve is null.
+ */
+ public void subdivide(CubicCurve2D left, CubicCurve2D right) {
+ subdivide(this, left, right);
+ }
+
+ /**
+ * Creates the data for two cubic curves by dividing the specified
+ * curve in two. The division point is the point on the curve
+ * that is closest to the average of curve's two control points.
+ * The two new control points (nearest the new endpoint) are computed
+ * by averaging the original control points with the new endpoint.
+ * The data of the source curve is left unchanged.
+ *
+ * @param src the original curve to be divided in two
+ * @param left the CubicCurve2D where the left (start) segment's
+ * data is written
+ * @param right the CubicCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if either curve is null.
+ */
+ public static void subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right) {
+ double x1 = src.getX1();
+ double y1 = src.getY1();
+ double cx1 = src.getCtrlX1();
+ double cy1 = src.getCtrlY1();
+ double cx2 = src.getCtrlX2();
+ double cy2 = src.getCtrlY2();
+ double x2 = src.getX2();
+ double y2 = src.getY2();
+ double cx = (cx1 + cx2) / 2.0;
+ double cy = (cy1 + cy2) / 2.0;
+ cx1 = (x1 + cx1) / 2.0;
+ cy1 = (y1 + cy1) / 2.0;
+ cx2 = (x2 + cx2) / 2.0;
+ cy2 = (y2 + cy2) / 2.0;
+ double ax = (cx1 + cx) / 2.0;
+ double ay = (cy1 + cy) / 2.0;
+ double bx = (cx2 + cx) / 2.0;
+ double by = (cy2 + cy) / 2.0;
+ cx = (ax + bx) / 2.0;
+ cy = (ay + by) / 2.0;
+ if (left != null) {
+ left.setCurve(x1, y1, cx1, cy1, ax, ay, cx, cy);
+ }
+ if (right != null) {
+ right.setCurve(cx, cy, bx, by, cx2, cy2, x2, y2);
+ }
+ }
+
+ /**
+ * Creates the data for two cubic curves by dividing the specified
+ * curve in two. The division point is the point on the curve
+ * that is closest to the average of curve's two control points.
+ * The two new control points (nearest the new endpoint) are computed
+ * by averaging the original control points with the new endpoint.
+ * The data of the source curve is left unchanged. The data for the
+ * three curves is read/written in the usual order: { x1, y1,
+ * ctrlx1, ctrly1, ctrlx2, crtry2, x2, y3 }
+ *
+ * @param src the array that gives the data values for the source curve
+ * @param srcOff the offset in the src array to read the values from
+ * @param left the array where the coordinates of the start curve should be written
+ * @param leftOff the offset in the left array to start writing the values
+ * @param right the array where the coordinates of the end curve should be written
+ * @param rightOff the offset in the right array to start writing the values
+ *
+ * @throws ArrayIndexOutOfBoundsException if src.length < srcoff + 8
+ * or if left.length < leftOff + 8 or if right.length < rightOff + 8.
+ * @throws NullPointerException if one of the arrays is null.
+ */
+ public static void subdivide(double src[], int srcOff, double left[], int leftOff, double right[], int rightOff) {
+ double x1 = src[srcOff + 0];
+ double y1 = src[srcOff + 1];
+ double cx1 = src[srcOff + 2];
+ double cy1 = src[srcOff + 3];
+ double cx2 = src[srcOff + 4];
+ double cy2 = src[srcOff + 5];
+ double x2 = src[srcOff + 6];
+ double y2 = src[srcOff + 7];
+ double cx = (cx1 + cx2) / 2.0;
+ double cy = (cy1 + cy2) / 2.0;
+ cx1 = (x1 + cx1) / 2.0;
+ cy1 = (y1 + cy1) / 2.0;
+ cx2 = (x2 + cx2) / 2.0;
+ cy2 = (y2 + cy2) / 2.0;
+ double ax = (cx1 + cx) / 2.0;
+ double ay = (cy1 + cy) / 2.0;
+ double bx = (cx2 + cx) / 2.0;
+ double by = (cy2 + cy) / 2.0;
+ cx = (ax + bx) / 2.0;
+ cy = (ay + by) / 2.0;
+ if (left != null) {
+ left[leftOff + 0] = x1;
+ left[leftOff + 1] = y1;
+ left[leftOff + 2] = cx1;
+ left[leftOff + 3] = cy1;
+ left[leftOff + 4] = ax;
+ left[leftOff + 5] = ay;
+ left[leftOff + 6] = cx;
+ left[leftOff + 7] = cy;
+ }
+ if (right != null) {
+ right[rightOff + 0] = cx;
+ right[rightOff + 1] = cy;
+ right[rightOff + 2] = bx;
+ right[rightOff + 3] = by;
+ right[rightOff + 4] = cx2;
+ right[rightOff + 5] = cy2;
+ right[rightOff + 6] = x2;
+ right[rightOff + 7] = y2;
+ }
+ }
+
+ /**
+ * Finds the roots of the cubic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[3]*x*x*x + eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written back into the array eqn starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been changed by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * cubic polynomial to solve.
+ *
+ * @return the number of roots of the cubic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 4.
+ * @throws NullPointerException if the array is null.
+ */
+ public static int solveCubic(double eqn[]) {
+ return solveCubic(eqn, eqn);
+ }
+
+ /**
+ * Finds the roots of the cubic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[3]*x*x*x + eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written into the array res starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been changed by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * cubic polynomial to solve.
+ * @param res the array that this method writes the results into
+ *
+ * @return the number of roots of the cubic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 4 or
+ * if res.length is less than the number of roots.
+ * @throws NullPointerException if either array is null.
+ */
+ public static int solveCubic(double eqn[], double res[]) {
+ return Crossing.solveCubic(eqn, res);
+ }
+
+ public boolean contains(double px, double py) {
+ return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(at), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+} \ No newline at end of file
diff --git a/awt/java/awt/geom/Dimension2D.java b/awt/java/awt/geom/Dimension2D.java
new file mode 100644
index 0000000..eef63e6
--- /dev/null
+++ b/awt/java/awt/geom/Dimension2D.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Class Dimension2D represents a size (width and height) of a
+ * geometric object. It stores double-valued data in order to be compatible
+ * with high-precision geometric operations.
+ */
+public abstract class Dimension2D implements Cloneable {
+
+ /**
+ * Instantiates a new dimension 2d with no data.
+ */
+ protected Dimension2D() {
+ }
+
+ /**
+ * Gets the width.
+ *
+ * @return the width
+ */
+ public abstract double getWidth();
+
+ /**
+ * Gets the height.
+ *
+ * @return the height
+ */
+ public abstract double getHeight();
+
+ /**
+ * Sets the width and height.
+ *
+ * @param width the width
+ * @param height the height
+ */
+ public abstract void setSize(double width, double height);
+
+ /**
+ * Sets the width and height based on the data of another
+ * Dimension2D object.
+ *
+ * @param d the Dimension2D object providing the data to copy
+ * into this Dimension2D object
+ */
+ public void setSize(Dimension2D d) {
+ setSize(d.getWidth(), d.getHeight());
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+}
+
diff --git a/awt/java/awt/geom/Ellipse2D.java b/awt/java/awt/geom/Ellipse2D.java
new file mode 100644
index 0000000..33464af
--- /dev/null
+++ b/awt/java/awt/geom/Ellipse2D.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Ellipse2D describes an ellipse defined by a rectangular
+ * area in which it is inscribed.
+ */
+public abstract class Ellipse2D extends RectangularShape {
+
+ /**
+ * The Class Float is the subclass of Ellipse2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends Ellipse2D {
+
+ /** The x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public float x;
+
+ /** The y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public float y;
+
+ /** The width of the ellipse's bounding rectangle. */
+ public float width;
+
+ /** The height of the ellipse's bounding rectangle. */
+ public float height;
+
+ /**
+ * Instantiates a new float-valued Ellipse2D.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued Ellipse2D with the specified data.
+ *
+ * @param x the x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param y the y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param width the width of the ellipse's bounding rectangle
+ * @param height the height of the ellipse's bounding rectangle
+ */
+ public Float(float x, float y, float width, float height) {
+ setFrame(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ /**
+ * Sets the data of the ellipse's bounding rectangle.
+ *
+ * @param x the x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param y the y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param width the width of the ellipse's bounding rectangle
+ * @param height the height of the ellipse's bounding rectangle
+ */
+ public void setFrame(float x, float y, float width, float height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Float(x, y, width, height);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Ellipse2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends Ellipse2D {
+
+ /** The x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public double x;
+
+ /** The y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public double y;
+
+ /** The width of the ellipse's bounding rectangle. */
+ public double width;
+
+ /** The height of the ellipse's bounding rectangle. */
+ public double height;
+
+ /**
+ * Instantiates a new double-valued Ellipse2D.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued Ellipse2D with the specified
+ * data.
+ *
+ * @param x the x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param y the y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param width the width of the ellipse's bounding rectangle
+ * @param height the height of the ellipse's bounding rectangle
+ */
+ public Double(double x, double y, double width, double height) {
+ setFrame(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+ }
+
+ /*
+ * Ellipse2D path iterator
+ */
+ /**
+ * The subclass of PathIterator to traverse an Ellipse2D.
+ */
+ class Iterator implements PathIterator {
+
+ /*
+ * Ellipse is subdivided into four quarters by x and y axis. Each part approximated by
+ * cubic Bezier curve. Arc in first quarter is started in (a, 0) and finished in (0, b) points.
+ * Control points for cubic curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are
+ * calculated based on requirement Bezier curve in point 0.5 should lay on the arc.
+ */
+
+ /** The coefficient to calculate control points of Bezier curves. */
+ final double u = 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+
+ /** The points coordinates calculation table. */
+ final double points[][] = {
+ { 1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0 },
+ { 0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5 },
+ { 0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0 },
+ { 0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5 }
+ };
+
+ /** The x coordinate of left-upper corner of the ellipse bounds. */
+ double x;
+
+ /** The y coordinate of left-upper corner of the ellipse bounds. */
+ double y;
+
+ /** The width of the ellipse bounds. */
+ double width;
+
+ /** The height of the ellipse bounds. */
+ double height;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new Ellipse2D.Iterator for given ellipse and transformation
+ *
+ * @param e - the source Ellipse2D object
+ * @param t the t
+ */
+ Iterator(Ellipse2D e, AffineTransform t) {
+ this.x = e.getX();
+ this.y = e.getY();
+ this.width = e.getWidth();
+ this.height = e.getHeight();
+ this.t = t;
+ if (width < 0.0 || height < 0.0) {
+ index = 6;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 5;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ double p[] = points[3];
+ coords[0] = x + p[4] * width;
+ coords[1] = y + p[5] * height;
+ } else {
+ type = SEG_CUBICTO;
+ count = 3;
+ double p[] = points[index - 1];
+ int j = 0;
+ for (int i = 0; i < 3; i++) {
+ coords[j] = x + p[j++] * width;
+ coords[j] = y + p[j++] * height;
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ double p[] = points[3];
+ coords[0] = (float)(x + p[4] * width);
+ coords[1] = (float)(y + p[5] * height);
+ } else {
+ type = SEG_CUBICTO;
+ count = 3;
+ int j = 0;
+ double p[] = points[index - 1];
+ for (int i = 0; i < 3; i++) {
+ coords[j] = (float)(x + p[j++] * width);
+ coords[j] = (float)(y + p[j++] * height);
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new Ellipse2D.
+ */
+ protected Ellipse2D() {
+ }
+
+ public boolean contains(double px, double py) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double a = (px - getX()) / getWidth() - 0.5;
+ double b = (py - getY()) / getHeight() - 0.5;
+
+ return a * a + b * b < 0.25;
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double cx = getX() + getWidth() / 2.0;
+ double cy = getY() + getHeight() / 2.0;
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
+ double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
+
+ return contains(nx, ny);
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ return
+ contains(rx1, ry1) &&
+ contains(rx2, ry1) &&
+ contains(rx2, ry2) &&
+ contains(rx1, ry2);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+}
+
diff --git a/awt/java/awt/geom/FlatteningPathIterator.java b/awt/java/awt/geom/FlatteningPathIterator.java
new file mode 100644
index 0000000..ca5c7c2
--- /dev/null
+++ b/awt/java/awt/geom/FlatteningPathIterator.java
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class FlatteningPathIterator takes a PathIterator for traversing
+ * a curved shape and flattens it by estimating the curve as a series
+ * of line segments. The flattening factor indicates how far the
+ * estimating line segments are allowed to be from the actual curve:
+ * the FlatteningPathIterator will keep dividing each curved segment
+ * into smaller and smaller flat segments until either the segments
+ * are withing the flattening factor of the curve or until the buffer
+ * limit is reached.
+ */
+public class FlatteningPathIterator implements PathIterator {
+
+ /** The default points buffer size. */
+ private static final int BUFFER_SIZE = 16;
+
+ /** The default curve subdivision limit. */
+ private static final int BUFFER_LIMIT = 16;
+
+ /** The points buffer capacity. */
+ private static final int BUFFER_CAPACITY = 16;
+
+ /** The type of current segment to be flat. */
+ int bufType;
+
+ /** The curve subdivision limit. */
+ int bufLimit;
+
+ /** The current points buffer size. */
+ int bufSize;
+
+ /** The inner cursor position in points buffer. */
+ int bufIndex;
+
+ /** The current subdivision count. */
+ int bufSubdiv;
+
+ /** The points buffer. */
+ double buf[];
+
+ /** The indicator of empty points buffer. */
+ boolean bufEmpty = true;
+
+ /** The source PathIterator. */
+ PathIterator p;
+
+ /** The flatness of new path. */
+ double flatness;
+
+ /** The square of flatness. */
+ double flatness2;
+
+ /** The x coordinate of previous path segment. */
+ double px;
+
+ /** The y coordinate of previous path segment. */
+ double py;
+
+ /** The tamporary buffer for getting points from PathIterator. */
+ double coords[] = new double[6];
+
+ /**
+ * Instantiates a new flattening path iterator given the path
+ * iterator for a (possibly) curved path and a flattening factor
+ * which indicates how close together the points on the curve
+ * should be chosen. The buffer limit defaults to 16 which means
+ * that each curve will be divided into no more than 16 segments
+ * regardless of the flattening factor.
+ *
+ * @param path the path iterator of the original curve
+ * @param flatness the flattening factor that indicates how far the
+ * flat path is allowed to be from the actual curve in order to
+ * decide when to stop dividing the path into smaller and smaller
+ * segments.
+ *
+ * @throws IllegalArgumentException if the flatness is less than zero.
+ * @throws NullPointerException if the path is null.
+ */
+ public FlatteningPathIterator(PathIterator path, double flatness) {
+ this(path, flatness, BUFFER_LIMIT);
+ }
+
+ /**
+ * Instantiates a new flattening path iterator given the path
+ * iterator for a (possibly) curved path and a flattening factor
+ * and a buffer limit. The FlatteningPathIterator will keep
+ * dividing each curved segment into smaller and smaller flat segments
+ * until either the segments are withing the flattening factor of the
+ * curve or until the buffer limit is reached.
+ *
+ * @param path the path iterator of the original curve
+ * @param flatness the flattening factor that indicates how far the
+ * flat path is allowed to be from the actual curve in order to
+ * decide when to stop dividing the path into smaller and smaller
+ * segments.
+ * @param limit the maximum number of flat segments to divide each
+ * curve into
+ *
+ * @throws IllegalArgumentException if the flatness or limit is less than zero.
+ * @throws NullPointerException if the path is null.
+ */
+ public FlatteningPathIterator(PathIterator path, double flatness, int limit) {
+ if (flatness < 0.0) {
+ // awt.206=Flatness is less then zero
+ throw new IllegalArgumentException(Messages.getString("awt.206")); //$NON-NLS-1$
+ }
+ if (limit < 0) {
+ // awt.207=Limit is less then zero
+ throw new IllegalArgumentException(Messages.getString("awt.207")); //$NON-NLS-1$
+ }
+ if (path == null) {
+ // awt.208=Path is null
+ throw new NullPointerException(Messages.getString("awt.208")); //$NON-NLS-1$
+ }
+ this.p = path;
+ this.flatness = flatness;
+ this.flatness2 = flatness * flatness;
+ this.bufLimit = limit;
+ this.bufSize = Math.min(bufLimit, BUFFER_SIZE);
+ this.buf = new double[bufSize];
+ this.bufIndex = bufSize;
+ }
+
+ /**
+ * Gets the flattening factor.
+ *
+ * @return the flattening factor
+ */
+ public double getFlatness() {
+ return flatness;
+ }
+
+ /**
+ * Gets the maximum number of subdivisions per curved segment.
+ *
+ * @return the maximum number of subdivisions per curved segment
+ */
+ public int getRecursionLimit() {
+ return bufLimit;
+ }
+
+ public int getWindingRule() {
+ return p.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return bufEmpty && p.isDone();
+ }
+
+ /**
+ * Calculates flat path points for current segment of the source shape.
+ *
+ * Line segment is flat by itself. Flatness of quad and cubic curves evaluated by getFlatnessSq() method.
+ * Curves subdivided until current flatness is bigger than user defined and subdivision limit isn't exhausted.
+ * Single source segment translated to series of buffer points. The less flatness the bigger serries.
+ * Every currentSegment() call extract one point from the buffer. When series completed evaluate() takes next source shape segment.
+ */
+ void evaluate() {
+ if (bufEmpty) {
+ bufType = p.currentSegment(coords);
+ }
+
+ switch (bufType) {
+ case SEG_MOVETO:
+ case SEG_LINETO:
+ px = coords[0];
+ py = coords[1];
+ break;
+ case SEG_QUADTO:
+ if (bufEmpty) {
+ bufIndex -= 6;
+ buf[bufIndex + 0] = px;
+ buf[bufIndex + 1] = py;
+ System.arraycopy(coords, 0, buf, bufIndex + 2, 4);
+ bufSubdiv = 0;
+ }
+
+ while (bufSubdiv < bufLimit) {
+ if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
+ break;
+ }
+
+ // Realloc buffer
+ if (bufIndex <= 4) {
+ double tmp[] = new double[bufSize + BUFFER_CAPACITY];
+ System.arraycopy(
+ buf, bufIndex,
+ tmp, bufIndex + BUFFER_CAPACITY,
+ bufSize - bufIndex);
+ buf = tmp;
+ bufSize += BUFFER_CAPACITY;
+ bufIndex += BUFFER_CAPACITY;
+ }
+
+ QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex);
+
+ bufIndex -= 4;
+ bufSubdiv++;
+ }
+
+ bufIndex += 4;
+ px = buf[bufIndex];
+ py = buf[bufIndex + 1];
+
+ bufEmpty = (bufIndex == bufSize - 2);
+ if (bufEmpty) {
+ bufIndex = bufSize;
+ bufType = SEG_LINETO;
+ } else {
+ bufSubdiv--;
+ }
+ break;
+ case SEG_CUBICTO:
+ if (bufEmpty) {
+ bufIndex -= 8;
+ buf[bufIndex + 0] = px;
+ buf[bufIndex + 1] = py;
+ System.arraycopy(coords, 0, buf, bufIndex + 2, 6);
+ bufSubdiv = 0;
+ }
+
+ while (bufSubdiv < bufLimit) {
+ if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
+ break;
+ }
+
+ // Realloc buffer
+ if (bufIndex <= 6) {
+ double tmp[] = new double[bufSize + BUFFER_CAPACITY];
+ System.arraycopy(
+ buf, bufIndex,
+ tmp, bufIndex + BUFFER_CAPACITY,
+ bufSize - bufIndex);
+ buf = tmp;
+ bufSize += BUFFER_CAPACITY;
+ bufIndex += BUFFER_CAPACITY;
+ }
+
+ CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex);
+
+ bufIndex -= 6;
+ bufSubdiv++;
+ }
+
+ bufIndex += 6;
+ px = buf[bufIndex];
+ py = buf[bufIndex + 1];
+
+ bufEmpty = (bufIndex == bufSize - 2);
+ if (bufEmpty) {
+ bufIndex = bufSize;
+ bufType = SEG_LINETO;
+ } else {
+ bufSubdiv--;
+ }
+ break;
+ }
+
+ }
+
+ public void next() {
+ if (bufEmpty) {
+ p.next();
+ }
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4Bx")); //$NON-NLS-1$
+ }
+ evaluate();
+ int type = bufType;
+ if (type != SEG_CLOSE) {
+ coords[0] = (float)px;
+ coords[1] = (float)py;
+ if (type != SEG_MOVETO) {
+ type = SEG_LINETO;
+ }
+ }
+ return type;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ evaluate();
+ int type = bufType;
+ if (type != SEG_CLOSE) {
+ coords[0] = px;
+ coords[1] = py;
+ if (type != SEG_MOVETO) {
+ type = SEG_LINETO;
+ }
+ }
+ return type;
+ }
+}
+
diff --git a/awt/java/awt/geom/GeneralPath.java b/awt/java/awt/geom/GeneralPath.java
new file mode 100644
index 0000000..36b01c4
--- /dev/null
+++ b/awt/java/awt/geom/GeneralPath.java
@@ -0,0 +1,566 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class GeneralPath represents a shape whose outline is given
+ * by different types of curved and straight segments.
+ */
+public final class GeneralPath implements Shape, Cloneable {
+
+ /** The Constant WIND_EVEN_ODD see {@link PathIterator#WIND_EVEN_ODD}. */
+ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
+
+ /** The Constant WIND_NON_ZERO see {@link PathIterator#WIND_NON_ZERO}. */
+ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
+
+ /** The buffers size. */
+ private static final int BUFFER_SIZE = 10;
+
+ /** The buffers capacity. */
+ private static final int BUFFER_CAPACITY = 10;
+
+ /** The point's types buffer. */
+ byte[] types;
+
+ /** The points buffer. */
+ float[] points;
+
+ /** The point's type buffer size. */
+ int typeSize;
+
+ /** The points buffer size. */
+ int pointSize;
+
+ /** The path rule. */
+ int rule;
+
+ /** The space amount in points buffer for different segmenet's types. */
+ static int pointShift[] = {
+ 2, // MOVETO
+ 2, // LINETO
+ 4, // QUADTO
+ 6, // CUBICTO
+ 0}; // CLOSE
+
+ /*
+ * GeneralPath path iterator
+ */
+ /**
+ * The Class Iterator is the subclass of Iterator for traversing the
+ * outline of a GeneralPath.
+ */
+ class Iterator implements PathIterator {
+
+ /** The current cursor position in types buffer. */
+ int typeIndex;
+
+ /** The current cursor position in points buffer. */
+ int pointIndex;
+
+ /** The source GeneralPath object. */
+ GeneralPath p;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path
+ *
+ * @param path - the source GeneralPath object
+ */
+ Iterator(GeneralPath path) {
+ this(path, null);
+ }
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path and transformation
+ *
+ * @param path - the source GeneralPath object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(GeneralPath path, AffineTransform at) {
+ this.p = path;
+ this.t = at;
+ }
+
+ public int getWindingRule() {
+ return p.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return typeIndex >= p.typeSize;
+ }
+
+ public void next() {
+ typeIndex++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = p.types[typeIndex];
+ int count = GeneralPath.pointShift[type];
+ for (int i = 0; i < count; i++) {
+ coords[i] = p.points[pointIndex + i];
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count / 2);
+ }
+ pointIndex += count;
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = p.types[typeIndex];
+ int count = GeneralPath.pointShift[type];
+ System.arraycopy(p.points, pointIndex, coords, 0, count);
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count / 2);
+ }
+ pointIndex += count;
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new general path with the winding rule set
+ * to {@link PathIterator#WIND_NON_ZERO} and the initial capacity
+ * (number of segments) set to the default value 10.
+ */
+ public GeneralPath() {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ }
+
+ /**
+ * Instantiates a new general path with the given winding rule
+ * and the initial capacity (number of segments) set to the
+ * default value 10.
+ *
+ * @param rule the winding rule, either {@link PathIterator#WIND_EVEN_ODD}
+ * or {@link PathIterator#WIND_NON_ZERO}
+ */
+ public GeneralPath(int rule) {
+ this(rule, BUFFER_SIZE);
+ }
+
+ /**
+ * Instantiates a new general path with the given winding rule
+ * and initial capacity (number of segments).
+ *
+ * @param rule the winding rule, either {@link PathIterator#WIND_EVEN_ODD}
+ * or {@link PathIterator#WIND_NON_ZERO}
+ * @param initialCapacity the number of segments the path is set to hold
+ */
+ public GeneralPath(int rule, int initialCapacity) {
+ setWindingRule(rule);
+ types = new byte[initialCapacity];
+ points = new float[initialCapacity * 2];
+ }
+
+ /**
+ * Creates a new GeneralPath from the outline of the given shape.
+ *
+ * @param shape the shape
+ */
+ public GeneralPath(Shape shape) {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ PathIterator p = shape.getPathIterator(null);
+ setWindingRule(p.getWindingRule());
+ append(p, false);
+ }
+
+ /**
+ * Sets the winding rule, which determines how to decide whether
+ * a point that isn't on the path itself is inside or outside of
+ * the shape.
+ *
+ * @param rule the new winding rule
+ *
+ * @throws IllegalArgumentException if the winding rule is neither
+ * {@link PathIterator#WIND_EVEN_ODD} nor {@link PathIterator#WIND_NON_ZERO}.
+ */
+ public void setWindingRule(int rule) {
+ if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
+ // awt.209=Invalid winding rule value
+ throw new java.lang.IllegalArgumentException(Messages.getString("awt.209")); //$NON-NLS-1$
+ }
+ this.rule = rule;
+ }
+
+ /**
+ * Gets the winding rule.
+ *
+ * @return the winding rule, either {@link PathIterator#WIND_EVEN_ODD}
+ * or {@link PathIterator#WIND_NON_ZERO}
+ */
+ public int getWindingRule() {
+ return rule;
+ }
+
+ /**
+ * Checks the point data buffer sizes to see whether pointCount additional
+ * point-data elements can fit. (Note that the number of point data
+ * elements to add is more than one per point -- it depends on the type
+ * of point being added.) Reallocates the buffers to enlarge the size if necessary.
+ *
+ * @param pointCount - the number of point data elements to be added
+ * @param checkMove whether to check for existing points
+ *
+ * @throws IllegalPathStateException checkMove is true and the
+ * path is currently empty.
+ */
+ void checkBuf(int pointCount, boolean checkMove) {
+ if (checkMove && typeSize == 0) {
+ // awt.20A=First segment should be SEG_MOVETO type
+ throw new IllegalPathStateException(Messages.getString("awt.20A")); //$NON-NLS-1$
+ }
+ if (typeSize == types.length) {
+ byte tmp[] = new byte[typeSize + BUFFER_CAPACITY];
+ System.arraycopy(types, 0, tmp, 0, typeSize);
+ types = tmp;
+ }
+ if (pointSize + pointCount > points.length) {
+ float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)];
+ System.arraycopy(points, 0, tmp, 0, pointSize);
+ points = tmp;
+ }
+ }
+
+ /**
+ * Appends a new point to the end of this general path, disconnected
+ * from the existing path.
+ *
+ * @param x the x coordinate of the next point to append
+ * @param y the y coordinate of the next point to append
+ */
+ public void moveTo(float x, float y) {
+ if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) {
+ points[pointSize - 2] = x;
+ points[pointSize - 1] = y;
+ } else {
+ checkBuf(2, false);
+ types[typeSize++] = PathIterator.SEG_MOVETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+ }
+
+ /**
+ * Appends a new segment to the end of this general path by making
+ * a straight line segment from the current endpoint to the
+ * given new point.
+ *
+ * @param x the x coordinate of the next point to append
+ * @param y the y coordinate of the next point to append
+ */
+ public void lineTo(float x, float y) {
+ checkBuf(2, true);
+ types[typeSize++] = PathIterator.SEG_LINETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+
+ /**
+ * Appends a new segment to the end of this general path by making
+ * a quadratic curve from the current endpoint to the point (x2, y2)
+ * using the point (x1, y1) as the quadratic curve's control point.
+ *
+ * @param x1 the x coordinate of the quadratic curve's control point
+ * @param y1 the y coordinate of the quadratic curve's control point
+ * @param x2 the x coordinate of the quadratic curve's end point
+ * @param y2 the y coordinate of the quadratic curve's end point
+ */
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ checkBuf(4, true);
+ types[typeSize++] = PathIterator.SEG_QUADTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ }
+
+ /**
+ * Appends a new segment to the end of this general path by making
+ * a cubic curve from the current endpoint to the point (x3, y3)
+ * using (x1, y1) and (x2, y2) as control points.
+ *
+ * @see java.awt.geom.CubicCurve2D
+ *
+ * @param x1 the x coordinate of the new cubic segment's first control point
+ * @param y1 the y coordinate of the new cubic segment's first control point
+ * @param x2 the x coordinate of the new cubic segment's second control point
+ * @param y2 the y coordinate of the new cubic segment's second control point
+ * @param x3 the x coordinate of the new cubic segment's end point
+ * @param y3 the y coordinate of the new cubic segment's end point
+ */
+ public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) {
+ checkBuf(6, true);
+ types[typeSize++] = PathIterator.SEG_CUBICTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ points[pointSize++] = x3;
+ points[pointSize++] = y3;
+ }
+
+ /**
+ * Appends the type information to declare that the current
+ * endpoint closes the curve.
+ */
+ public void closePath() {
+ if (typeSize == 0 || types[typeSize - 1] != PathIterator.SEG_CLOSE) {
+ checkBuf(0, true);
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ }
+ }
+
+ /**
+ * Appends the outline of the specified shape onto the end
+ * of this GeneralPath.
+ *
+ * @param shape the shape whose outline is to be appended
+ * @param connect true to connect this path's current
+ * endpoint to the first point of the shape's outline or
+ * false to append the shape's outline without connecting it
+ *
+ * @throws NullPointerException if the shape parameter is null
+ */
+ public void append(Shape shape, boolean connect) {
+ PathIterator p = shape.getPathIterator(null);
+ append(p, connect);
+ }
+
+ /**
+ * Appends the path defined by the specified PathIterator onto the end
+ * of this GeneralPath.
+ *
+ * @param path the PathIterator that defines the new path to append
+ * @param connect true to connect this path's current
+ * endpoint to the first point of the shape's outline or
+ * false to append the shape's outline without connecting it
+ */
+ public void append(PathIterator path, boolean connect) {
+ while (!path.isDone()) {
+ float coords[] = new float[6];
+ switch (path.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!connect || typeSize == 0) {
+ moveTo(coords[0], coords[1]);
+ break;
+ }
+ if (types[typeSize - 1] != PathIterator.SEG_CLOSE &&
+ points[pointSize - 2] == coords[0] &&
+ points[pointSize - 1] == coords[1])
+ {
+ break;
+ }
+ // NO BREAK;
+ case PathIterator.SEG_LINETO:
+ lineTo(coords[0], coords[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ quadTo(coords[0], coords[1], coords[2], coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ closePath();
+ break;
+ }
+ path.next();
+ connect = false;
+ }
+ }
+
+ /**
+ * Gets the current end point of the path.
+ *
+ * @return the current end point of the path
+ */
+ public Point2D getCurrentPoint() {
+ if (typeSize == 0) {
+ return null;
+ }
+ int j = pointSize - 2;
+ if (types[typeSize - 1] == PathIterator.SEG_CLOSE) {
+
+ for (int i = typeSize - 2; i > 0; i--) {
+ int type = types[i];
+ if (type == PathIterator.SEG_MOVETO) {
+ break;
+ }
+ j -= pointShift[type];
+ }
+ }
+ return new Point2D.Float(points[j], points[j + 1]);
+ }
+
+ /**
+ * Resets the GeneralPath to being an empty path. The underlying
+ * point and segment data is not deleted but rather the end indices
+ * of the data arrays are set to zero.
+ */
+ public void reset() {
+ typeSize = 0;
+ pointSize = 0;
+ }
+
+ /**
+ * Transform all of the coordinates of this path according to the
+ * specified AffineTransform.
+ *
+ * @param t the AffineTransform
+ */
+ public void transform(AffineTransform t) {
+ t.transform(points, 0, points, 0, pointSize / 2);
+ }
+
+ /**
+ * Creates a new GeneralPath whose data is given by this path's
+ * data transformed according to the specified AffineTransform.
+ *
+ * @param t the AffineTransform
+ *
+ * @return the new GeneralPath whose data is given by this path's
+ * data transformed according to the specified AffineTransform
+ */
+ public Shape createTransformedShape(AffineTransform t) {
+ GeneralPath p = (GeneralPath)clone();
+ if (t != null) {
+ p.transform(t);
+ }
+ return p;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx1, ry1, rx2, ry2;
+ if (pointSize == 0) {
+ rx1 = ry1 = rx2 = ry2 = 0.0f;
+ } else {
+ int i = pointSize - 1;
+ ry1 = ry2 = points[i--];
+ rx1 = rx2 = points[i--];
+ while (i > 0) {
+ float y = points[i--];
+ float x = points[i--];
+ if (x < rx1) {
+ rx1 = x;
+ } else
+ if (x > rx2) {
+ rx2 = x;
+ }
+ if (y < ry1) {
+ ry1 = y;
+ } else
+ if (y > ry2) {
+ ry2 = y;
+ }
+ }
+ }
+ return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1);
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ /**
+ * Checks the cross count (number of times a ray from the point
+ * crosses the shape's boundary) to determine whether the number
+ * of crossings corresponds to a point inside the shape or not
+ * (according to the shape's path rule).
+ *
+ * @param cross - the point's cross count
+ *
+ * @return true if the point is inside the path, or false otherwise
+ */
+ boolean isInside(int cross) {
+ if (rule == WIND_NON_ZERO) {
+ return Crossing.isInsideNonZero(cross);
+ }
+ return Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(double px, double py) {
+ return isInside(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && isInside(cross);
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || isInside(cross);
+ }
+
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ GeneralPath p = (GeneralPath) super.clone();
+ p.types = types.clone();
+ p.points = points.clone();
+ return p;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/geom/IllegalPathStateException.java b/awt/java/awt/geom/IllegalPathStateException.java
new file mode 100644
index 0000000..7f459e7
--- /dev/null
+++ b/awt/java/awt/geom/IllegalPathStateException.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Class IllegalPathStateException indicates errors where the
+ * current state of a path object is imcompatible with the desired
+ * action, such as performing non-trivial actions on an empty path.
+ */
+public class IllegalPathStateException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -5158084205220481094L;
+
+ /**
+ * Instantiates a new illegal path state exception.
+ */
+ public IllegalPathStateException() {
+ }
+
+ /**
+ * Instantiates a new illegal path state exception with the
+ * specified detail message.
+ *
+ * @param s the details of the error
+ */
+ public IllegalPathStateException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Line2D.java b/awt/java/awt/geom/Line2D.java
new file mode 100644
index 0000000..a53c470
--- /dev/null
+++ b/awt/java/awt/geom/Line2D.java
@@ -0,0 +1,871 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Line2D represents a line whose data is given in
+ * high-precision values appropriate for graphical operations.
+ */
+public abstract class Line2D implements Shape, Cloneable {
+
+ /**
+ * The Class Float is the subclass of Line2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends Line2D {
+
+ /** The x coordinate of the starting point. */
+ public float x1;
+
+ /** The y coordinate of the starting point. */
+ public float y1;
+
+ /** The x coordinate of the end point. */
+ public float x2;
+
+ /** The y coordinate of the end point. */
+ public float y2;
+
+ /**
+ * Instantiates a new float-valued Line2D with
+ * its data values set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Float(float x1, float y1, float x2, float y2) {
+ setLine(x1, y1, x2, y2);
+ }
+
+ /**
+ * Instantiates a new float-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param p1 the starting point
+ * @param p2 the end point
+ */
+ public Float(Point2D p1, Point2D p2) {
+ setLine(p1, p2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Float(x1, y1);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Float(x2, y2);
+ }
+
+ @Override
+ public void setLine(double x1, double y1, double x2, double y2) {
+ this.x1 = (float)x1;
+ this.y1 = (float)y1;
+ this.x2 = (float)x2;
+ this.y2 = (float)y2;
+ }
+
+ /**
+ * Sets the data values that define the line.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public void setLine(float x1, float y1, float x2, float y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx, ry, rw, rh;
+ if (x1 < x2) {
+ rx = x1;
+ rw = x2 - x1;
+ } else {
+ rx = x2;
+ rw = x1 - x2;
+ }
+ if (y1 < y2) {
+ ry = y1;
+ rh = y2 - y1;
+ } else {
+ ry = y2;
+ rh = y1 - y2;
+ }
+ return new Rectangle2D.Float(rx, ry, rw, rh);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Line2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends Line2D {
+
+ /** The x coordinate of the starting point. */
+ public double x1;
+
+ /** The y coordinate of the starting point. */
+ public double y1;
+
+ /** The x coordinate of the end point. */
+ public double x2;
+
+ /** The y coordinate of the end point. */
+ public double y2;
+
+ /**
+ * Instantiates a new double-valued Line2D with
+ * its data values set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Double(double x1, double y1, double x2, double y2) {
+ setLine(x1, y1, x2, y2);
+ }
+
+ /**
+ * Instantiates a new double-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param p1 the starting point
+ * @param p2 the end point
+ */
+ public Double(Point2D p1, Point2D p2) {
+ setLine(p1, p2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Double(x1, y1);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Double(x2, y2);
+ }
+
+ @Override
+ public void setLine(double x1, double y1, double x2, double y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ double rx, ry, rw, rh;
+ if (x1 < x2) {
+ rx = x1;
+ rw = x2 - x1;
+ } else {
+ rx = x2;
+ rw = x1 - x2;
+ }
+ if (y1 < y2) {
+ ry = y1;
+ rh = y2 - y1;
+ } else {
+ ry = y2;
+ rh = y1 - y2;
+ }
+ return new Rectangle2D.Double(rx, ry, rw, rh);
+ }
+ }
+
+ /*
+ * Line2D path iterator
+ */
+ /**
+ * The subclass of PathIterator to traverse a Line2D.
+ */
+ class Iterator implements PathIterator {
+
+ /** The x coordinate of the start line point. */
+ double x1;
+
+ /** The y coordinate of the start line point. */
+ double y1;
+
+ /** The x coordinate of the end line point. */
+ double x2;
+
+ /** The y coordinate of the end line point. */
+ double y2;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new Line2D.Iterator for given line and transformation
+ *
+ * @param l - the source Line2D object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(Line2D l, AffineTransform at) {
+ this.x1 = l.getX1();
+ this.y1 = l.getY1();
+ this.x2 = l.getX2();
+ this.y2 = l.getY2();
+ this.t = at;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 1;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = x1;
+ coords[1] = y1;
+ } else {
+ type = SEG_LINETO;
+ coords[0] = x2;
+ coords[1] = y2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = (float)x1;
+ coords[1] = (float)y1;
+ } else {
+ type = SEG_LINETO;
+ coords[0] = (float)x2;
+ coords[1] = (float)y2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new Line2D.
+ */
+ protected Line2D() {
+ }
+
+ /**
+ * Gets the x coordinate of the starting point.
+ *
+ * @return the x coordinate of the starting point
+ */
+ public abstract double getX1();
+
+ /**
+ * Gets the y coordinate of the starting point.
+ *
+ * @return the y coordinate of the starting point
+ */
+ public abstract double getY1();
+
+ /**
+ * Gets the x coordinate of the end point.
+ *
+ * @return the x2
+ */
+ public abstract double getX2();
+
+ /**
+ * Gets the y coordinate of the end point.
+ *
+ * @return the y coordinate of the end point
+ */
+ public abstract double getY2();
+
+ /**
+ * Gets the p the starting point.
+ *
+ * @return the p the starting point
+ */
+ public abstract Point2D getP1();
+
+ /**
+ * Gets the p end point.
+ *
+ * @return the p end point
+ */
+ public abstract Point2D getP2();
+
+ /**
+ * Sets the line's endpoints.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public abstract void setLine(double x1, double y1, double x2, double y2);
+
+ /**
+ * Sets the line's endpoints.
+ *
+ * @param p1 the starting point
+ * @param p2 the end point
+ */
+ public void setLine(Point2D p1, Point2D p2) {
+ setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the line's endpoints by copying the data from another Line2D.
+ *
+ * @param line the Line2D to copy the endpoint data from
+ */
+ public void setLine(Line2D line) {
+ setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2());
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ /**
+ * Tells where the point is with respect to the line segment,
+ * given the orientation of the line segment. If the ray
+ * found by extending the line segment from its starting point
+ * is rotated, this method tells whether the ray
+ * should rotate in a clockwise direction or a counter-clockwise
+ * direction to hit the point first. The return value is 0 if the
+ * point is on the line segment, it's 1 if the point is on the ray
+ * or if the ray should rotate in a counter-clockwise direction to get to the
+ * point, and it's -1 if the ray should rotate in a clockwise
+ * direction to get to the point or if the point is on the line
+ * determined by the line segment but not on the ray from the
+ * segment's starting point and through its end point.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the p coordinate of the test point
+ *
+ * @return the value that describes where the point is with respect to the line segment,
+ * given the orientation of the line segment
+ */
+ public static int relativeCCW(double x1, double y1, double x2, double y2, double px, double py) {
+ /*
+ * A = (x2-x1, y2-y1) P = (px-x1, py-y1)
+ */
+ x2 -= x1;
+ y2 -= y1;
+ px -= x1;
+ py -= y1;
+ double t = px * y2 - py * x2; // PxA
+ if (t == 0.0) {
+ t = px * x2 + py * y2; // P*A
+ if (t > 0.0) {
+ px -= x2; // B-A
+ py -= y2;
+ t = px * x2 + py * y2; // (P-A)*A
+ if (t < 0.0) {
+ t = 0.0;
+ }
+ }
+ }
+
+ return t < 0.0 ? -1 : (t > 0.0 ? 1 : 0);
+ }
+
+ /**
+ * Tells where the point is with respect to this line segment,
+ * given the orientation of this line segment. If the ray
+ * found by extending the line segment from its starting point
+ * is rotated, this method tells whether the ray
+ * should rotate in a clockwise direction or a counter-clockwise
+ * direction to hit the point first. The return value is 0 if the
+ * point is on the line segment, it's 1 if the point is on the ray
+ * or if the ray should rotate in a counter-clockwise direction to get to the
+ * point, and it's -1 if the ray should rotate in a clockwise
+ * direction to get to the point or if the point is on the line
+ * determined by the line segment but not on the ray from the
+ * segment's starting point and through its end point.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the p coordinate of the test point
+ *
+ * @return the value that describes where the point is with respect to
+ * this line segment, given the orientation of this line segment
+ */
+ public int relativeCCW(double px, double py) {
+ return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Tells where the point is with respect to this line segment,
+ * given the orientation of this line segment. If the ray
+ * found by extending the line segment from its starting point
+ * is rotated, this method tells whether the ray
+ * should rotate in a clockwise direction or a counter-clockwise
+ * direction to hit the point first. The return value is 0 if the
+ * point is on the line segment, it's 1 if the point is on the ray
+ * or if the ray should rotate in a counter-clockwise direction to get to the
+ * point, and it's -1 if the ray should rotate in a clockwise
+ * direction to get to the point or if the point is on the line
+ * determined by the line segment but not on the ray from the
+ * segment's starting point and through its end point.
+ *
+ * @param p the test point
+ *
+ * @return the value that describes where the point is with respect to
+ * this line segment, given the orientation of this line segment
+ */
+ public int relativeCCW(Point2D p) {
+ return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Tells whether the two line segments cross.
+ *
+ * @param x1 the x coordinate of the starting point of the first segment
+ * @param y1 the y coordinate of the starting point of the first segment
+ * @param x2 the x coordinate of the end point of the first segment
+ * @param y2 the y coordinate of the end point of the first segment
+ * @param x3 the x coordinate of the starting point of the second segment
+ * @param y3 the y coordinate of the starting point of the second segment
+ * @param x4 the x coordinate of the end point of the second segment
+ * @param y4 the y coordinate of the end point of the second segment
+ *
+ * @return true, if the two line segments cross
+ */
+ public static boolean linesIntersect(double x1, double y1, double x2,
+ double y2, double x3, double y3, double x4, double y4)
+ {
+ /*
+ * A = (x2-x1, y2-y1) B = (x3-x1, y3-y1) C = (x4-x1, y4-y1) D = (x4-x3,
+ * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B
+ *
+ * Result is ((AxB) * (AxC) <=0) and ((DxE) * (DxF) <= 0)
+ *
+ * DxE = (C-B)x(-B) = BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB =
+ * AxB+BxC-AxC
+ */
+
+ x2 -= x1; // A
+ y2 -= y1;
+ x3 -= x1; // B
+ y3 -= y1;
+ x4 -= x1; // C
+ y4 -= y1;
+
+ double AvB = x2 * y3 - x3 * y2;
+ double AvC = x2 * y4 - x4 * y2;
+
+ // Online
+ if (AvB == 0.0 && AvC == 0.0) {
+ if (x2 != 0.0) {
+ return
+ (x4 * x3 <= 0.0) ||
+ ((x3 * x2 >= 0.0) &&
+ (x2 > 0.0 ? x3 <= x2 || x4 <= x2 : x3 >= x2 || x4 >= x2));
+ }
+ if (y2 != 0.0) {
+ return
+ (y4 * y3 <= 0.0) ||
+ ((y3 * y2 >= 0.0) &&
+ (y2 > 0.0 ? y3 <= y2 || y4 <= y2 : y3 >= y2 || y4 >= y2));
+ }
+ return false;
+ }
+
+ double BvC = x3 * y4 - x4 * y3;
+
+ return (AvB * AvC <= 0.0) && (BvC * (AvB + BvC - AvC) <= 0.0);
+ }
+
+ /**
+ * Tells whether the specified line segments crosses this line segment.
+ *
+ * @param x1 the x coordinate of the starting point of the test segment
+ * @param y1 the y coordinate of the starting point of the test segment
+ * @param x2 the x coordinate of the end point of the test segment
+ * @param y2 the y coordinate of the end point of the test segment
+ *
+ * @return true, if the specified line segments crosses this line segment
+ */
+ public boolean intersectsLine(double x1, double y1, double x2, double y2) {
+ return linesIntersect(x1, y1, x2, y2, getX1(), getY1(), getX2(), getY2());
+ }
+
+ /**
+ * Tells whether the specified line segments crosses this line segment.
+ *
+ * @param l the test segment
+ *
+ * @return true, if the specified line segments crosses this line segment
+ *
+ * @throws NullPointerException if l is null
+ */
+ public boolean intersectsLine(Line2D l) {
+ return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(), getX2(), getY2());
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line segment.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the the square of the distance between the point and the
+ * line segment
+ */
+ public static double ptSegDistSq(double x1, double y1, double x2, double y2, double px, double py) {
+ /*
+ * A = (x2 - x1, y2 - y1) P = (px - x1, py - y1)
+ */
+ x2 -= x1; // A = (x2, y2)
+ y2 -= y1;
+ px -= x1; // P = (px, py)
+ py -= y1;
+ double dist;
+ if (px * x2 + py * y2 <= 0.0) { // P*A
+ dist = px * px + py * py;
+ } else {
+ px = x2 - px; // P = A - P = (x2 - px, y2 - py)
+ py = y2 - py;
+ if (px * x2 + py * y2 <= 0.0) { // P*A
+ dist = px * px + py * py;
+ } else {
+ dist = px * y2 - py * x2;
+ dist = dist * dist / (x2 * x2 + y2 * y2); // pxA/|A|
+ }
+ }
+ if (dist < 0) {
+ dist = 0;
+ }
+ return dist;
+ }
+
+ /**
+ * Gives the distance between the point and the
+ * line segment.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the the distance between the point and the
+ * line segment
+ */
+ public static double ptSegDist(double x1, double y1, double x2, double y2, double px, double py) {
+ return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py));
+ }
+
+ /**
+ * Gives the square of the distance between the point and this
+ * line segment.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the the square of the distance between the point and this
+ * line segment
+ */
+ public double ptSegDistSq(double px, double py) {
+ return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the square of the distance between the point and this
+ * line segment.
+ *
+ * @param p the test point
+ *
+ * @return the square of the distance between the point and this
+ * line segment
+ */
+ public double ptSegDistSq(Point2D p) {
+ return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Gives the distance between the point and this
+ * line segment.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the distance between the point and this
+ * line segment
+ */
+ public double ptSegDist(double px, double py) {
+ return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the distance between the point and this
+ * line segment.
+ *
+ * @param p the test point
+ *
+ * @return the distance between the point and this
+ * line segment
+ */
+ public double ptSegDist(Point2D p) {
+ return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the square of the distance between the point and the
+ * line
+ */
+ public static double ptLineDistSq(double x1, double y1, double x2, double y2, double px, double py) {
+ x2 -= x1;
+ y2 -= y1;
+ px -= x1;
+ py -= y1;
+ double s = px * y2 - py * x2;
+ return s * s / (x2 * x2 + y2 * y2);
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the square of the distance between the point and the
+ * line
+ */
+ public static double ptLineDist(double x1, double y1, double x2, double y2, double px, double py) {
+ return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py));
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the square of the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDistSq(double px, double py) {
+ return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param p the test point
+ *
+ * @return the square of the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDistSq(Point2D p) {
+ return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Gives the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDist(double px, double py) {
+ return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param p the test point
+ *
+ * @return the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDist(Point2D p) {
+ return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ public boolean contains(double px, double py) {
+ return false;
+ }
+
+ public boolean contains(Point2D p) {
+ return false;
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return false;
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ return false;
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ return intersects(new Rectangle2D.Double(rx, ry, rw, rh));
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
+ return new Iterator(this, at);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
diff --git a/awt/java/awt/geom/NoninvertibleTransformException.java b/awt/java/awt/geom/NoninvertibleTransformException.java
new file mode 100644
index 0000000..2b7b542
--- /dev/null
+++ b/awt/java/awt/geom/NoninvertibleTransformException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Class NoninvertibleTransformException is the exception that is thrown
+ * when an action requires inverting an {@link AffineTransform} that is
+ * not invertible (has determinant 0).
+ */
+public class NoninvertibleTransformException extends java.lang.Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 6137225240503990466L;
+
+ /**
+ * Instantiates a new noninvertible transform exception.
+ *
+ * @param s the error message
+ */
+ public NoninvertibleTransformException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/PathIterator.java b/awt/java/awt/geom/PathIterator.java
new file mode 100644
index 0000000..5a98083
--- /dev/null
+++ b/awt/java/awt/geom/PathIterator.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Interface PathIterator represents an iterator object that can
+ * be used to traverse the outline of a {@link java.awt.Shape}.
+ * It returns points along the boundary of the Shape
+ * which may be actual vertices (in the case of a shape made of line
+ * segments) or may be points on a curved segment with the distance
+ * between the points determined by a chosen flattening factor.
+ * <p>
+ * If the shape is closed, the outline is traversed in the counter-clockwise
+ * direction. That means that moving forward along the boundary is to travel
+ * in such a way that the interior of the shape is to the left of the
+ * outline path and the exterior of the shape is to the right of the outline
+ * path. The interior and exterior of the shape are determined by a
+ * winding rule.
+ */
+public interface PathIterator {
+
+ /** The Constant WIND_EVEN_ODD indicates the winding rule that says
+ * that a point is outside the shape if any infinite ray from the point
+ * crosses the outline of the shape an even number of times, otherwise
+ * it is inside. */
+ public static final int WIND_EVEN_ODD = 0;
+
+ /** The Constant WIND_NON_ZERO indicates the winding rule that says that
+ * a point is inside the shape if every infinite ray starting from that
+ * point crosses the outline of the shape a non-zero number of times. */
+ public static final int WIND_NON_ZERO = 1;
+
+ /** The Constant SEG_MOVETO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should be placed directly on the current point. */
+ public static final int SEG_MOVETO = 0;
+
+ /** The Constant SEG_LINETO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should follow a straight line. */
+ public static final int SEG_LINETO = 1;
+
+ /** The Constant SEG_QUADTO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should follow a quadratic curve. */
+ public static final int SEG_QUADTO = 2;
+
+ /** The Constant SEG_CUBICTO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should follow a cubic curve. */
+ public static final int SEG_CUBICTO = 3;
+
+ /** The Constant SEG_CLOSE indicates that the previous point was the end
+ * of the shape's outline. */
+ public static final int SEG_CLOSE = 4;
+
+ /**
+ * Gets the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or
+ * {@link PathIterator#WIND_NON_ZERO}.
+ *
+ * @return the winding rule
+ */
+ public int getWindingRule();
+
+ /**
+ * Checks if this PathIterator has been completely traversed.
+ *
+ * @return true, if this PathIterator has been completely traversed
+ */
+ public boolean isDone();
+
+ /**
+ * Tells this PathIterator to skip to the next segment.
+ */
+ public void next();
+
+ /**
+ * Gets the coordinates of the next vertex point along the shape's outline
+ * and a flag that indicates what kind of segment to use in order to
+ * connect the previous vertex point to the current vertex point to form
+ * the current segment.
+ *
+ * @param coords the array that the coordinates of the end point of the current
+ * segment are written into.
+ *
+ * @return the flag that indicates how to follow the shape's outline
+ * from the previous point to the current one, chosen from
+ * the following constants:
+ * {@link PathIterator#SEG_MOVETO}, {@link PathIterator#SEG_LINETO},
+ * {@link PathIterator#SEG_QUADTO}, {@link PathIterator#SEG_CUBICTO},
+ * or {@link PathIterator#SEG_CLOSE}
+ */
+ public int currentSegment(float[] coords);
+
+ /**
+ * Gets the coordinates of the next vertex point along the shape's outline
+ * and a flag that indicates what kind of segment to use in order to
+ * connect the previous vertex point to the current vertex point to form
+ * the current segment.
+ *
+ * @param coords the array that the coordinates of the end point of the current
+ * segment are written into.
+ *
+ * @return the flag that indicates how to follow the shape's outline
+ * from the previous point to the current one, chosen from
+ * the following constants:
+ * {@link PathIterator#SEG_MOVETO}, {@link PathIterator#SEG_LINETO},
+ * {@link PathIterator#SEG_QUADTO}, {@link PathIterator#SEG_CUBICTO},
+ * or {@link PathIterator#SEG_CLOSE}
+ */
+ public int currentSegment(double[] coords);
+
+}
+
diff --git a/awt/java/awt/geom/Point2D.java b/awt/java/awt/geom/Point2D.java
new file mode 100644
index 0000000..7719e67
--- /dev/null
+++ b/awt/java/awt/geom/Point2D.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class Point2D represents a point whose data is given in
+ * high-precision values appropriate for graphical operations.
+ */
+public abstract class Point2D implements Cloneable {
+
+ /**
+ * The Class Float is the subclass of Point2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends Point2D {
+
+ /** The x coordinate. */
+ public float x;
+
+ /** The y coordinate. */
+ public float y;
+
+ /**
+ * Instantiates a new float-valued Point2D with its data
+ * set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued Point2D with the specified coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public Float(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Sets the point's coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public void setLocation(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public void setLocation(double x, double y) {
+ this.x = (float)x;
+ this.y = (float)y;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Point2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends Point2D {
+
+ /** The x coordinate. */
+ public double x;
+
+ /** The y coordinate. */
+ public double y;
+
+ /**
+ * Instantiates a new double-valued Point2D with its data
+ * set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued Point2D with the specified coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public Double(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public void setLocation(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ /**
+ * Instantiates a new Point2D.
+ */
+ protected Point2D() {
+ }
+
+ /**
+ * Gets the x coordinate.
+ *
+ * @return the x coordinate
+ */
+ public abstract double getX();
+
+ /**
+ * Gets the y coordinate.
+ *
+ * @return the y coordinate
+ */
+ public abstract double getY();
+
+ /**
+ * Sets the point's coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public abstract void setLocation(double x, double y);
+
+ /**
+ * Sets the point's coordinates by copying them from another point.
+ *
+ * @param p the point to copy the data from
+ */
+ public void setLocation(Point2D p) {
+ setLocation(p.getX(), p.getY());
+ }
+
+ /**
+ * Finds the square of the distance between the two specified points.
+ *
+ * @param x1 the x coordinate of the first point
+ * @param y1 the y coordinate of the first point
+ * @param x2 the x coordinate of the second point
+ * @param y2 the y coordinate of the second point
+ *
+ * @return the square of the distance between the two specified points
+ */
+ public static double distanceSq(double x1, double y1, double x2, double y2) {
+ x2 -= x1;
+ y2 -= y1;
+ return x2 * x2 + y2 * y2;
+ }
+
+ /**
+ * Finds the square of the distance between this point and the specified point.
+ *
+ * @param px the x coordinate of the point
+ * @param py the y coordinate of the point
+ *
+ * @return the square of the distance between this point and the specified point
+ */
+ public double distanceSq(double px, double py) {
+ return Point2D.distanceSq(getX(), getY(), px, py);
+ }
+
+ /**
+ * Finds the square of the distance between this point and the specified point.
+ *
+ * @param p the other point
+ *
+ * @return the square of the distance between this point and the specified point
+ */
+ public double distanceSq(Point2D p) {
+ return Point2D.distanceSq(getX(), getY(), p.getX(), p.getY());
+ }
+
+ /**
+ * Finds the distance between the two specified points.
+ *
+ * @param x1 the x coordinate of the first point
+ * @param y1 the y coordinate of the first point
+ * @param x2 the x coordinate of the second point
+ * @param y2 the y coordinate of the second point
+ *
+ * @return the distance between the two specified points
+ */
+ public static double distance(double x1, double y1, double x2, double y2) {
+ return Math.sqrt(distanceSq(x1, y1, x2, y2));
+ }
+
+ /**
+ * Finds the distance between this point and the specified point.
+ *
+ * @param px the x coordinate of the point
+ * @param py the y coordinate of the point
+ *
+ * @return the distance between this point and the specified point
+ */
+ public double distance(double px, double py) {
+ return Math.sqrt(distanceSq(px, py));
+ }
+
+ /**
+ * Finds the distance between this point and the specified point.
+ *
+ * @param p the other point
+ *
+ * @return the distance between this point and the specified point
+ */
+ public double distance(Point2D p) {
+ return Math.sqrt(distanceSq(p));
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(getX());
+ hash.append(getY());
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Point2D) {
+ Point2D p = (Point2D) obj;
+ return getX() == p.getX() && getY() == p.getY();
+ }
+ return false;
+ }
+}
+
diff --git a/awt/java/awt/geom/QuadCurve2D.java b/awt/java/awt/geom/QuadCurve2D.java
new file mode 100644
index 0000000..64ea6d6
--- /dev/null
+++ b/awt/java/awt/geom/QuadCurve2D.java
@@ -0,0 +1,824 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class QuadCurve2D is a Shape that represents a segment of a
+ * quadratic (Bezier) curve. The curved segment is determined by three points:
+ * a start point, an end point, and a control point. The line from the control
+ * point to the starting point gives the tangent to the curve at the
+ * starting point, and the line from the control point to the end point
+ * gives the tangent to the curve at the end point.
+ */
+public abstract class QuadCurve2D implements Shape, Cloneable {
+
+ /**
+ * The Class Float is the subclass of QuadCurve2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends QuadCurve2D {
+
+ /** The x coordinate of the starting point of the curved segment. */
+ public float x1;
+
+ /** The y coordinate of the starting point of the curved segment. */
+ public float y1;
+
+ /** The x coordinate of the control point. */
+ public float ctrlx;
+
+ /** The y coordinate of the control point. */
+ public float ctrly;
+
+ /** The x coordinate of the end point of the curved segment. */
+ public float x2;
+
+ /** The y coordinate of the end point of the curved segment. */
+ public float y2;
+
+ /**
+ * Instantiates a new float-valued QuadCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued QuadCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public Float(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
+ setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX() {
+ return ctrlx;
+ }
+
+ @Override
+ public double getCtrlY() {
+ return ctrly;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Float(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlPt() {
+ return new Point2D.Float(ctrlx, ctrly);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Float(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ this.x1 = (float)x1;
+ this.y1 = (float)y1;
+ this.ctrlx = (float)ctrlx;
+ this.ctrly = (float)ctrly;
+ this.x2 = (float)x2;
+ this.y2 = (float)y2;
+ }
+
+ /**
+ * Sets the data values of the curve.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public void setCurve(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx = ctrlx;
+ this.ctrly = ctrly;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx0 = Math.min(Math.min(x1, x2), ctrlx);
+ float ry0 = Math.min(Math.min(y1, y2), ctrly);
+ float rx1 = Math.max(Math.max(x1, x2), ctrlx);
+ float ry1 = Math.max(Math.max(y1, y2), ctrly);
+ return new Rectangle2D.Float(rx0, ry0, rx1 - rx0, ry1 - ry0);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of QuadCurve2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends QuadCurve2D {
+
+ /** The x coordinate of the starting point of the curved segment. */
+ public double x1;
+
+ /** The y coordinate of the starting point of the curved segment. */
+ public double y1;
+
+ /** The x coordinate of the control point. */
+ public double ctrlx;
+
+ /** The y coordinate of the control point. */
+ public double ctrly;
+
+ /** The x coordinate of the end point of the curved segment. */
+ public double x2;
+
+ /** The y coordinate of the end point of the curved segment. */
+ public double y2;
+
+ /**
+ * Instantiates a new double-valued QuadCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued QuadCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public Double(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX() {
+ return ctrlx;
+ }
+
+ @Override
+ public double getCtrlY() {
+ return ctrly;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Double(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlPt() {
+ return new Point2D.Double(ctrlx, ctrly);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Double(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx = ctrlx;
+ this.ctrly = ctrly;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ double rx0 = Math.min(Math.min(x1, x2), ctrlx);
+ double ry0 = Math.min(Math.min(y1, y2), ctrly);
+ double rx1 = Math.max(Math.max(x1, x2), ctrlx);
+ double ry1 = Math.max(Math.max(y1, y2), ctrly);
+ return new Rectangle2D.Double(rx0, ry0, rx1 - rx0, ry1 - ry0);
+ }
+ }
+
+ /*
+ * QuadCurve2D path iterator
+ */
+ /**
+ * The PathIterator for a Quad2D curve.
+ */
+ class Iterator implements PathIterator {
+
+ /** The source QuadCurve2D object. */
+ QuadCurve2D c;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segment index. */
+ int index;
+
+ /**
+ * Constructs a new QuadCurve2D.Iterator for given curve and transformation
+ *
+ * @param q - the source QuadCurve2D object
+ * @param t the AffineTransform that acts on the coordinates before
+ * returning them (or null)
+ */
+ Iterator(QuadCurve2D q, AffineTransform t) {
+ this.c = q;
+ this.t = t;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return (index > 1);
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = c.getX1();
+ coords[1] = c.getY1();
+ count = 1;
+ } else {
+ type = SEG_QUADTO;
+ coords[0] = c.getCtrlX();
+ coords[1] = c.getCtrlY();
+ coords[2] = c.getX2();
+ coords[3] = c.getY2();
+ count = 2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = (float)c.getX1();
+ coords[1] = (float)c.getY1();
+ count = 1;
+ } else {
+ type = SEG_QUADTO;
+ coords[0] = (float)c.getCtrlX();
+ coords[1] = (float)c.getCtrlY();
+ coords[2] = (float)c.getX2();
+ coords[3] = (float)c.getY2();
+ count = 2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new quadratic curve.
+ */
+ protected QuadCurve2D() {
+ }
+
+ /**
+ * Gets the x coordinate of the starting point.
+ *
+ * @return the x coordinate of the starting point
+ */
+ public abstract double getX1();
+
+ /**
+ * Gets the y coordinate of the starting point.
+ *
+ * @return the y coordinate of the starting point
+ */
+ public abstract double getY1();
+
+ /**
+ * Gets the starting point.
+ *
+ * @return the starting point
+ */
+ public abstract Point2D getP1();
+
+ /**
+ * Gets the x coordinate of the control point.
+ *
+ * @return the x coordinate of the control point
+ */
+ public abstract double getCtrlX();
+
+ /**
+ * Gets the y coordinate of the control point.
+ *
+ * @return y coordinate of the control point
+ */
+ public abstract double getCtrlY();
+
+ /**
+ * Gets the control point.
+ *
+ * @return the control point
+ */
+ public abstract Point2D getCtrlPt();
+
+ /**
+ * Gets the x coordinate of the end point.
+ *
+ * @return the x coordinate of the end point
+ */
+ public abstract double getX2();
+
+ /**
+ * Gets the y coordinate of the end point.
+ *
+ * @return the y coordinate of the end point
+ */
+ public abstract double getY2();
+
+ /**
+ * Gets the end point.
+ *
+ * @return the end point
+ */
+ public abstract Point2D getP2();
+
+ /**
+ * Sets the data of the curve.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public abstract void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2);
+
+ /**
+ * Sets the data of the curve.
+ *
+ * @param p1 the starting point of the curved segment
+ * @param cp the control point
+ * @param p2 the end point of the curved segment
+ *
+ * @throws NullPointerException if any of the three points is null.
+ */
+ public void setCurve(Point2D p1, Point2D cp, Point2D p2) {
+ setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of values. The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#setCurve(double, double, double, double, double, double)}.
+ *
+ * @param coords the array of values containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public void setCurve(double[] coords, int offset) {
+ setCurve(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5]);
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of points. The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#setCurve(Point2D, Point2D, Point2D)}
+ *
+ * @param points the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + 3.
+ * @throws NullPointerException if the point array is null.
+ */
+ public void setCurve(Point2D[] points, int offset) {
+ setCurve(
+ points[offset + 0].getX(), points[offset + 0].getY(),
+ points[offset + 1].getX(), points[offset + 1].getY(),
+ points[offset + 2].getX(), points[offset + 2].getY());
+ }
+
+ /**
+ * Sets the data of the curve by copying it from another QuadCurve2D.
+ *
+ * @param curve the curve to copy the data points from
+ *
+ * @throws NullPointerException if the curve is null.
+ */
+ public void setCurve(QuadCurve2D curve) {
+ setCurve(
+ curve.getX1(), curve.getY1(),
+ curve.getCtrlX(), curve.getCtrlY(),
+ curve.getX2(), curve.getY2());
+ }
+
+ /**
+ * Gets the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * for this curve.
+ *
+ * @return the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ */
+ public double getFlatnessSq() {
+ return Line2D.ptSegDistSq(
+ getX1(), getY1(),
+ getX2(), getY2(),
+ getCtrlX(), getCtrlY());
+ }
+
+ /**
+ * Gets the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ *
+ * @return the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ */
+ public static double getFlatnessSq(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly);
+ }
+
+ /**
+ * Gets the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * by reading the coordinates of the points from an array of values.
+ * The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#getFlatnessSq(double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the coordinates to use for
+ * the calculation
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public static double getFlatnessSq(double coords[], int offset) {
+ return Line2D.ptSegDistSq(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 2], coords[offset + 3]);
+ }
+
+ /**
+ * Gets the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * of this QuadCurve2D.
+ *
+ * @return the the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * of this QuadCurve2D
+ */
+ public double getFlatness() {
+ return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY());
+ }
+
+ /**
+ * Gets the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ *
+ * @return the the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ */
+ public static double getFlatness(double x1, double y1, double ctrlx,
+ double ctrly, double x2, double y2)
+ {
+ return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly);
+ }
+
+ /**
+ * Gets the the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ * The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#getFlatness(double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the coordinates to use for
+ * the calculation
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public static double getFlatness(double coords[], int offset) {
+ return Line2D.ptSegDist(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 2], coords[offset + 3]);
+ }
+
+ /**
+ * Creates the data for two quadratic curves by dividing this
+ * curve in two. The division point is the point on the curve
+ * that is closest to this curve's control point. The data of
+ * this curve is left unchanged.
+ *
+ * @param left the QuadCurve2D where the left (start) segment's
+ * data is written
+ * @param right the QuadCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if either curve is null.
+ */
+ public void subdivide(QuadCurve2D left, QuadCurve2D right) {
+ subdivide(this, left, right);
+ }
+
+ /**
+ * Creates the data for two quadratic curves by dividing a source
+ * curve in two. The division point is the point on the curve
+ * that is closest to the source curve's control point. The data of
+ * the source curve is left unchanged.
+ *
+ * @param src the curve that provides the initial data
+ * @param left the QuadCurve2D where the left (start) segment's
+ * data is written
+ * @param right the QuadCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if one of the curves is null.
+ */
+ public static void subdivide(QuadCurve2D src, QuadCurve2D left, QuadCurve2D right) {
+ double x1 = src.getX1();
+ double y1 = src.getY1();
+ double cx = src.getCtrlX();
+ double cy = src.getCtrlY();
+ double x2 = src.getX2();
+ double y2 = src.getY2();
+ double cx1 = (x1 + cx) / 2.0;
+ double cy1 = (y1 + cy) / 2.0;
+ double cx2 = (x2 + cx) / 2.0;
+ double cy2 = (y2 + cy) / 2.0;
+ cx = (cx1 + cx2) / 2.0;
+ cy = (cy1 + cy2) / 2.0;
+ if (left != null) {
+ left.setCurve(x1, y1, cx1, cy1, cx, cy);
+ }
+ if (right != null) {
+ right.setCurve(cx, cy, cx2, cy2, x2, y2);
+ }
+ }
+
+ /**
+ * Creates the data for two quadratic curves by dividing a source
+ * curve in two. The division point is the point on the curve
+ * that is closest to the source curve's control point. The data
+ * for the three curves is read and written from arrays of values in
+ * the usual order: x1, y1, cx, cy, x2, y2.
+ *
+ * @param src the array that gives the data values for the source curve
+ * @param srcoff the offset in the src array to read the values from
+ * @param left the array where the coordinates of the start curve should be written
+ * @param leftOff the offset in the left array to start writing the values
+ * @param right the array where the coordinates of the end curve should be written
+ * @param rightOff the offset in the right array to start writing the values
+ *
+ * @throws ArrayIndexOutOfBoundsException if src.length < srcoff + 6
+ * or if left.length < leftOff + 6 or if right.length < rightOff + 6.
+ * @throws NullPointerException if one of the arrays is null.
+ */
+ public static void subdivide(double src[], int srcoff, double left[],
+ int leftOff, double right[], int rightOff)
+ {
+ double x1 = src[srcoff + 0];
+ double y1 = src[srcoff + 1];
+ double cx = src[srcoff + 2];
+ double cy = src[srcoff + 3];
+ double x2 = src[srcoff + 4];
+ double y2 = src[srcoff + 5];
+ double cx1 = (x1 + cx) / 2.0;
+ double cy1 = (y1 + cy) / 2.0;
+ double cx2 = (x2 + cx) / 2.0;
+ double cy2 = (y2 + cy) / 2.0;
+ cx = (cx1 + cx2) / 2.0;
+ cy = (cy1 + cy2) / 2.0;
+ if (left != null) {
+ left[leftOff + 0] = x1;
+ left[leftOff + 1] = y1;
+ left[leftOff + 2] = cx1;
+ left[leftOff + 3] = cy1;
+ left[leftOff + 4] = cx;
+ left[leftOff + 5] = cy;
+ }
+ if (right != null) {
+ right[rightOff + 0] = cx;
+ right[rightOff + 1] = cy;
+ right[rightOff + 2] = cx2;
+ right[rightOff + 3] = cy2;
+ right[rightOff + 4] = x2;
+ right[rightOff + 5] = y2;
+ }
+ }
+
+ /**
+ * Finds the roots of the quadratic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written back into the array eqn starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been changed by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * quadratic polynomial to solve.
+ *
+ * @return the number of roots of the quadratic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 3.
+ * @throws NullPointerException if the array is null.
+ */
+ public static int solveQuadratic(double eqn[]) {
+ return solveQuadratic(eqn, eqn);
+ }
+
+ /**
+ * Finds the roots of the quadratic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written into the array res starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been written by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * quadratic polynomial to solve.
+ * @param res the array that this method writes the results into
+ *
+ * @return the number of roots of the quadratic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 3 or
+ * if res.length is less than the number of roots.
+ * @throws NullPointerException if either array is null.
+ */
+ public static int solveQuadratic(double eqn[], double res[]) {
+ return Crossing.solveQuad(eqn, res);
+ }
+
+ public boolean contains(double px, double py) {
+ return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Rectangle2D.java b/awt/java/awt/geom/Rectangle2D.java
new file mode 100644
index 0000000..d33dd91
--- /dev/null
+++ b/awt/java/awt/geom/Rectangle2D.java
@@ -0,0 +1,761 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class Rectangle2D represents a rectangle whose coordinates are given
+ * with the correct precision to be used with the Graphics2D classes.
+ */
+public abstract class Rectangle2D extends RectangularShape {
+
+ /** The Constant OUT_LEFT is a mask that is used to indicate that a
+ * given point is outside the rectangle and to its left. */
+ public static final int OUT_LEFT = 1;
+
+ /** The Constant OUT_TOP is a mask that is used to indicate that a
+ * given point is outside the rectangle and above it. */
+ public static final int OUT_TOP = 2;
+
+ /** The Constant OUT_RIGHT is a mask that is used to indicate that a
+ * given point is outside the rectangle and to its right. */
+ public static final int OUT_RIGHT = 4;
+
+ /** The Constant OUT_BOTTOM is a mask that is used to indicate that a
+ * given point is outside the rectangle and above it. */
+ public static final int OUT_BOTTOM = 8;
+
+ /**
+ * The Class Float is the subclass of Rectangle2D that represents a
+ * rectangle whose data values are given as floats (with float-level
+ * precision).
+ */
+ public static class Float extends Rectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public float x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public float y;
+
+ /** The width of the rectangle. */
+ public float width;
+
+ /** The height of the rectangle. */
+ public float height;
+
+ /**
+ * Instantiates a new empty rectangle with float-precision data fields.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new rectangle with the specified float-precision data.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public Float(float x, float y, float width, float height) {
+ setRect(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0f || height <= 0.0f;
+ }
+
+ /**
+ * Sets the rectangle's data to the given values.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public void setRect(float x, float y, float width, float height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void setRect(double x, double y, double width, double height) {
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ }
+
+ @Override
+ public void setRect(Rectangle2D r) {
+ this.x = (float)r.getX();
+ this.y = (float)r.getY();
+ this.width = (float)r.getWidth();
+ this.height = (float)r.getHeight();
+ }
+
+ @Override
+ public int outcode(double px, double py) {
+ int code = 0;
+
+ if (width <= 0.0f) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else
+ if (px < x) {
+ code |= OUT_LEFT;
+ } else
+ if (px > x + width) {
+ code |= OUT_RIGHT;
+ }
+
+ if (height <= 0.0f) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else
+ if (py < y) {
+ code |= OUT_TOP;
+ } else
+ if (py > y + height) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ @Override
+ public Rectangle2D getBounds2D() {
+ return new Float(x, y, width, height);
+ }
+
+ @Override
+ public Rectangle2D createIntersection(Rectangle2D r) {
+ Rectangle2D dst;
+ if (r instanceof Double) {
+ dst = new Rectangle2D.Double();
+ } else {
+ dst = new Rectangle2D.Float();
+ }
+ Rectangle2D.intersect(this, r, dst);
+ return dst;
+ }
+
+ @Override
+ public Rectangle2D createUnion(Rectangle2D r) {
+ Rectangle2D dst;
+ if (r instanceof Double) {
+ dst = new Rectangle2D.Double();
+ } else {
+ dst = new Rectangle2D.Float();
+ }
+ Rectangle2D.union(this, r, dst);
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Rectangle2D.Float().toString())
+ return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Rectangle2D that represents a
+ * rectangle whose data values are given as doubles (with double-precision-level
+ * precision).
+ */
+ public static class Double extends Rectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public double x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public double y;
+
+ /** The width of the rectangle. */
+ public double width;
+
+ /** The height of the rectangle. */
+ public double height;
+
+ /**
+ * Instantiates a new empty rectangle with double-precision data fields.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new rectangle with the given double values.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public Double(double x, double y, double width, double height) {
+ setRect(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setRect(double x, double y, double width, double height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void setRect(Rectangle2D r) {
+ this.x = r.getX();
+ this.y = r.getY();
+ this.width = r.getWidth();
+ this.height = r.getHeight();
+ }
+
+ @Override
+ public int outcode(double px, double py) {
+ int code = 0;
+
+ if (width <= 0.0) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else
+ if (px < x) {
+ code |= OUT_LEFT;
+ } else
+ if (px > x + width) {
+ code |= OUT_RIGHT;
+ }
+
+ if (height <= 0.0) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else
+ if (py < y) {
+ code |= OUT_TOP;
+ } else
+ if (py > y + height) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ @Override
+ public Rectangle2D getBounds2D() {
+ return new Double(x, y, width, height);
+ }
+
+ @Override
+ public Rectangle2D createIntersection(Rectangle2D r) {
+ Rectangle2D dst = new Rectangle2D.Double();
+ Rectangle2D.intersect(this, r, dst);
+ return dst;
+ }
+
+ @Override
+ public Rectangle2D createUnion(Rectangle2D r) {
+ Rectangle2D dest = new Rectangle2D.Double();
+ Rectangle2D.union(this, r, dest);
+ return dest;
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Rectangle2D.Double().toString())
+ return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ }
+
+ /**
+ * The Class Iterator provides
+ * access to the coordinates of the Rectangle2D's boundary modified
+ * by an AffineTransform.
+ */
+ class Iterator implements PathIterator {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ double x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ double y;
+
+
+ /** The width of the rectangle. */
+ double width;
+
+ /** The height of the rectangle. */
+ double height;
+
+ /** The AffineTransform that is used to modify the coordinates
+ * that are returned by the path iterator. */
+ AffineTransform t;
+
+ /** The current segment index. */
+ int index;
+
+ /**
+ * Constructs a new Rectangle2D.Iterator for given rectangle and transformation.
+ *
+ * @param r - the source Rectangle2D object
+ * @param at - the AffineTransform object to apply to the coordinates
+ * before returning them
+ */
+ Iterator(Rectangle2D r, AffineTransform at) {
+ this.x = r.getX();
+ this.y = r.getY();
+ this.width = r.getWidth();
+ this.height = r.getHeight();
+ this.t = at;
+ if (width < 0.0 || height < 0.0) {
+ index = 6;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 5;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = x;
+ coords[1] = y;
+ } else {
+ type = SEG_LINETO;
+ switch(index) {
+ case 1:
+ coords[0] = x + width;
+ coords[1] = y;
+ break;
+ case 2:
+ coords[0] = x + width;
+ coords[1] = y + height;
+ break;
+ case 3:
+ coords[0] = x;
+ coords[1] = y + height;
+ break;
+ case 4:
+ coords[0] = x;
+ coords[1] = y;
+ break;
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ if (index == 0) {
+ coords[0] = (float)x;
+ coords[1] = (float)y;
+ type = SEG_MOVETO;
+ } else {
+ type = SEG_LINETO;
+ switch(index) {
+ case 1:
+ coords[0] = (float)(x + width);
+ coords[1] = (float)y;
+ break;
+ case 2:
+ coords[0] = (float)(x + width);
+ coords[1] = (float)(y + height);
+ break;
+ case 3:
+ coords[0] = (float)x;
+ coords[1] = (float)(y + height);
+ break;
+ case 4:
+ coords[0] = (float)x;
+ coords[1] = (float)y;
+ break;
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new rectangle2 d.
+ */
+ protected Rectangle2D() {
+ }
+
+ /**
+ * Sets the rectangle's location and dimension.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public abstract void setRect(double x, double y, double width, double height);
+
+ /**
+ * Gets the location of the point with respect to the rectangle and
+ * packs the information into a single int using the bitmasks
+ * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT},
+ * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}.
+ * If the rectangle has zero or negative width, then every point
+ * is regarded as being both to the left and to the right of the
+ * rectangle. Similarly, if the height is zero or negative then
+ * all points are considered to be both both above and below it.
+ *
+ * @param x the x coordinate of the point to check
+ * @param y the y coordinate of the point to check
+ *
+ * @return the point's location with respect to the rectangle.
+ */
+ public abstract int outcode(double x, double y);
+
+ /**
+ * Creates an new rectangle that is the intersection of this rectangle
+ * with the given rectangle. The resulting rectangle may be empty.
+ * The data of this rectangle is left unchanged.
+ *
+ * @param r the rectangle to intersect with this rectangle.
+ *
+ * @return the new rectangle given by intersection.
+ */
+ public abstract Rectangle2D createIntersection(Rectangle2D r);
+
+ /**
+ * Creates an new rectangle that is the union of this rectangle
+ * with the given rectangle. The new rectangle is the smallest
+ * rectangle which contains both this rectangle and the rectangle
+ * specified as a parameter. The data of this rectangle is left unchanged.
+ *
+ * @param r the rectangle to combine with this rectangle
+ *
+ * @return the new rectangle given by union
+ */
+ public abstract Rectangle2D createUnion(Rectangle2D r);
+
+ /**
+ * Sets the data of this rectangle to match the data of the given
+ * rectangle.
+ *
+ * @param r the rectangle whose data is to be copied into this rectangle's fields.
+ */
+ public void setRect(Rectangle2D r) {
+ setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ setRect(x, y, width, height);
+ }
+
+ public Rectangle2D getBounds2D() {
+ return (Rectangle2D)clone();
+ }
+
+ /**
+ * Determines whether any part of the line segment between (and including)
+ * the two given points touches any
+ * part of the rectangle, including its boundary.
+ *
+ * @param x1 the x coordinate of one of the points that determines the
+ * line segment to test
+ * @param y1 the y coordinate of one of the points that determines the
+ * line segment to test
+ * @param x2 the x coordinate of one of the points that determines the
+ * line segment to test
+ * @param y2 the y coordinate of one of the points that determines the
+ * line segment to test
+ *
+ * @return true, if at least one point of the line segment between the
+ * two points matches any point of the interior of the rectangle or the
+ * rectangle's boundary.
+ */
+ public boolean intersectsLine(double x1, double y1, double x2, double y2) {
+ double rx1 = getX();
+ double ry1 = getY();
+ double rx2 = rx1 + getWidth();
+ double ry2 = ry1 + getHeight();
+ return
+ (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2) ||
+ (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2) ||
+ Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1, x2, y2) ||
+ Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1, x2, y2);
+ }
+
+ /**
+ * Determines whether any part of the specified line segment touches any
+ * part of the rectangle, including its boundary.
+ *
+ * @param l the line segment to test
+ *
+ * @return true, if at least one point of the given line segment
+ * matches any point of the interior of the rectangle or the
+ * rectangle's boundary.
+ */
+ public boolean intersectsLine(Line2D l) {
+ return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
+ }
+
+ /**
+ * Gets the location of the point with respect to the rectangle and
+ * packs the information into a single int using the bitmasks
+ * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT},
+ * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}.
+ * If the rectangle has zero or negative width, then every point
+ * is regarded as being both to the left and to the right of the
+ * rectangle. Similarly, if the height is zero or negative then
+ * all points are considered to be both both above and below it.
+ *
+ * @param p the point to check
+ *
+ * @return the point's location with respect to the rectangle.
+ */
+ public int outcode(Point2D p) {
+ return outcode(p.getX(), p.getY());
+ }
+
+ public boolean contains(double x, double y) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ return
+ x1 <= x && x < x2 &&
+ y1 <= y && y < y2;
+ }
+
+ public boolean intersects(double x, double y, double width, double height) {
+ if (isEmpty() || width <= 0.0 || height <= 0.0) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ return
+ x + width > x1 && x < x2 &&
+ y + height > y1 && y < y2;
+ }
+
+ public boolean contains(double x, double y, double width, double height) {
+ if (isEmpty() || width <= 0.0 || height <= 0.0) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ return
+ x1 <= x && x + width <= x2 &&
+ y1 <= y && y + height <= y2;
+ }
+
+ /**
+ * Changes the data values of the destination rectangle to match
+ * the intersection of the two source rectangles, leaving the
+ * two source rectangles unchanged. The resulting rectangle may be empty.
+ *
+ * @param src1 one of the two source rectangles giving the data to intersect
+ * @param src2 one of the two source rectangles giving the data to intersect
+ * @param dst the destination object where the data of the intersection is written
+ */
+ public static void intersect(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) {
+ double x1 = Math.max(src1.getMinX(), src2.getMinX());
+ double y1 = Math.max(src1.getMinY(), src2.getMinY());
+ double x2 = Math.min(src1.getMaxX(), src2.getMaxX());
+ double y2 = Math.min(src1.getMaxY(), src2.getMaxY());
+ dst.setFrame(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Changes the data values of the destination rectangle to match
+ * the union of the two source rectangles, leaving the
+ * two source rectangles unchanged. The union is the smallest rectangle
+ * tha completely covers the two source rectangles.
+ *
+ * @param src1 one of the two source rectangles giving the data
+ * @param src2 one of the two source rectangles giving the data
+ * @param dst the destination object where the data of the union is written
+ */
+ public static void union(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) {
+ double x1 = Math.min(src1.getMinX(), src2.getMinX());
+ double y1 = Math.min(src1.getMinY(), src2.getMinY());
+ double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
+ double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
+ dst.setFrame(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Enlarges the rectangle so that it includes the given point.
+ *
+ * @param x the x coordinate of the new point to be covered by the rectangle
+ * @param y the y coordinate of the new point to be covered by the rectangle
+ */
+ public void add(double x, double y) {
+ double x1 = Math.min(getMinX(), x);
+ double y1 = Math.min(getMinY(), y);
+ double x2 = Math.max(getMaxX(), x);
+ double y2 = Math.max(getMaxY(), y);
+ setRect(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Enlarges the rectangle so that it includes the given point.
+ *
+ * @param p the new point to be covered by the rectangle
+ */
+ public void add(Point2D p) {
+ add(p.getX(), p.getY());
+ }
+
+ /**
+ * Enlarges the rectangle so that it covers the given rectangle.
+ *
+ * @param r the new rectangle to be covered by this rectangle
+ */
+ public void add(Rectangle2D r) {
+ union(this, r, this);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ @Override
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new Iterator(this, t);
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(getX());
+ hash.append(getY());
+ hash.append(getWidth());
+ hash.append(getHeight());
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Rectangle2D) {
+ Rectangle2D r = (Rectangle2D)obj;
+ return
+ getX() == r.getX() &&
+ getY() == r.getY() &&
+ getWidth() == r.getWidth() &&
+ getHeight() == r.getHeight();
+ }
+ return false;
+ }
+
+}
+
diff --git a/awt/java/awt/geom/RectangularShape.java b/awt/java/awt/geom/RectangularShape.java
new file mode 100644
index 0000000..0a77dfd
--- /dev/null
+++ b/awt/java/awt/geom/RectangularShape.java
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+/**
+ * The Class RectangularShape represents a Shape whose data is
+ * (at least partially) described by a rectangular frame. This includes
+ * shapes which are obviously rectangular (such as Rectangle2D) as well as
+ * shapes like Arc2D which are largely determined by the rectangle they
+ * fit inside.
+ */
+public abstract class RectangularShape implements Shape, Cloneable {
+
+ /**
+ * Instantiates a new rectangular shape.
+ */
+ protected RectangularShape() {
+ }
+
+ /**
+ * Gets the x coordinate of the upper left corner of the rectangle.
+ *
+ * @return the x coordinate of the upper left corner of the rectangle.
+ */
+ public abstract double getX();
+
+ /**
+ * Gets the y coordinate of the upper left corner of the rectangle.
+ *
+ * @return the y coordinate of the upper left corner of the rectangle.
+ */
+ public abstract double getY();
+
+ /**
+ * Gets the width of the rectangle.
+ *
+ * @return the width of the rectangle.
+ */
+ public abstract double getWidth();
+
+ /**
+ * Gets the height of the rectangle.
+ *
+ * @return the height of the rectangle.
+ */
+ public abstract double getHeight();
+
+ /**
+ * Checks if this is an empty rectangle: one with zero as its width or height.
+ *
+ * @return true, if the width or height is empty.
+ */
+ public abstract boolean isEmpty();
+
+ /**
+ * Sets the data for the bounding rectangle in terms of double values.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle.
+ * @param y the y coordinate of the upper left corner of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ */
+ public abstract void setFrame(double x, double y, double w, double h);
+
+ /**
+ * Gets the minimum x value of the bounding rectangle (the x
+ * coordinate of the upper left corner of the rectangle).
+ *
+ * @return the minimum x value of the bounding rectangle.
+ */
+ public double getMinX() {
+ return getX();
+ }
+
+ /**
+ * Gets the minimum y value of the bounding rectangle (the y
+ * coordinate of the upper left corner of the rectangle).
+ *
+ * @return the minimum y value of the bounding rectangle.
+ */
+ public double getMinY() {
+ return getY();
+ }
+
+ /**
+ * Gets the maximum x value of the bounding rectangle (the x
+ * coordinate of the upper left corner of the rectangle plus the
+ * rectangle's width).
+ *
+ * @return the maximum x value of the bounding rectangle.
+ */
+ public double getMaxX() {
+ return getX() + getWidth();
+ }
+
+ /**
+ * Gets the maximum y value of the bounding rectangle (the y
+ * coordinate of the upper left corner of the rectangle plus the
+ * rectangle's height).
+ *
+ * @return the maximum y value of the bounding rectangle.
+ */
+ public double getMaxY() {
+ return getY() + getHeight();
+ }
+
+ /**
+ * Gets the x coordinate of the center of the rectangle.
+ *
+ * @return the x coordinate of the center of the rectangle.
+ */
+ public double getCenterX() {
+ return getX() + getWidth() / 2.0;
+ }
+
+ /**
+ * Gets the y coordinate of the center of the rectangle.
+ *
+ * @return the y coordinate of the center of the rectangle.
+ */
+ public double getCenterY() {
+ return getY() + getHeight() / 2.0;
+ }
+
+ /**
+ * Places the rectangle's size and location data in a new Rectangle2D
+ * object and returns it.
+ *
+ * @return the bounding rectangle as a new Rectangle2D object.
+ */
+ public Rectangle2D getFrame() {
+ return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
+ }
+
+ /**
+ * Sets the bounding rectangle in terms of a Point2D which gives its
+ * upper left corner and a Dimension2D object giving its width and height.
+ *
+ * @param loc the new upper left corner coordinate.
+ * @param size the new size dimensions.
+ */
+ public void setFrame(Point2D loc, Dimension2D size) {
+ setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
+ }
+
+ /**
+ * Sets the bounding rectangle to match the data contained in the
+ * specified Rectangle2D.
+ *
+ * @param r the rectangle that gives the new frame data.
+ */
+ public void setFrame(Rectangle2D r) {
+ setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ /**
+ * Sets the framing rectangle given two opposite corners. Any two corners
+ * may be used in any order as long as they are diagonally opposite one another.
+ *
+ * @param x1 the x coordinate of one of the corner points.
+ * @param y1 the y coordinate of one of the corner points.
+ * @param x2 the x coordinate of the other corner point.
+ * @param y2 the y coordinate of the other corner point.
+ */
+ public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) {
+ double rx, ry, rw, rh;
+ if (x1 < x2) {
+ rx = x1;
+ rw = x2 - x1;
+ } else {
+ rx = x2;
+ rw = x1 - x2;
+ }
+ if (y1 < y2) {
+ ry = y1;
+ rh = y2 - y1;
+ } else {
+ ry = y2;
+ rh = y1 - y2;
+ }
+ setFrame(rx, ry, rw, rh);
+ }
+
+ /**
+ * Sets the framing rectangle given two opposite corners. Any two corners
+ * may be used in any order as long as they are diagonally opposite one another.
+ *
+ * @param p1 one of the corner points.
+ * @param p2 the other corner point.
+ */
+ public void setFrameFromDiagonal(Point2D p1, Point2D p2) {
+ setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the framing rectangle given the center point and one corner. Any
+ * corner may be used.
+ *
+ * @param centerX the x coordinate of the center point.
+ * @param centerY the y coordinate of the center point.
+ * @param cornerX the x coordinate of one of the corner points.
+ * @param cornerY the y coordinate of one of the corner points.
+ */
+ public void setFrameFromCenter(double centerX, double centerY, double cornerX, double cornerY) {
+ double width = Math.abs(cornerX - centerX);
+ double height = Math.abs(cornerY - centerY);
+ setFrame(centerX - width, centerY - height, width * 2.0, height * 2.0);
+ }
+
+ /**
+ * Sets the framing rectangle given the center point and one corner. Any
+ * corner may be used.
+ *
+ * @param center the center point.
+ * @param corner a corner point.
+ */
+ public void setFrameFromCenter(Point2D center, Point2D corner) {
+ setFrameFromCenter(center.getX(), center.getY(), corner.getX(), corner.getY());
+ }
+
+ public boolean contains(Point2D point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ public boolean intersects(Rectangle2D rect) {
+ return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ public boolean contains(Rectangle2D rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ public Rectangle getBounds() {
+ int x1 = (int)Math.floor(getMinX());
+ int y1 = (int)Math.floor(getMinY());
+ int x2 = (int)Math.ceil(getMaxX());
+ int y2 = (int)Math.ceil(getMaxY());
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/geom/RoundRectangle2D.java b/awt/java/awt/geom/RoundRectangle2D.java
new file mode 100644
index 0000000..680a146
--- /dev/null
+++ b/awt/java/awt/geom/RoundRectangle2D.java
@@ -0,0 +1,552 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RoundRectangle2D describes a rectangle with rounded
+ * corners with high-precision data that is appropriate for geometric
+ * operations.
+ */
+public abstract class RoundRectangle2D extends RectangularShape {
+
+ /**
+ * The Class Float is the subclass of RoundRectangle2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends RoundRectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public float x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public float y;
+
+ /** The width of the rectangle. */
+ public float width;
+
+ /** The height of the rectangle. */
+ public float height;
+
+ /** The arcwidth of the rounded corners. */
+ public float arcwidth;
+
+ /** The archeight of the rounded corners. */
+ public float archeight;
+
+ /**
+ * Instantiates a new float-valued RoundRectangle2D with
+ * its data-values set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued RoundRectangle2D with
+ * the specified data values
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcwidth the arcwidth of the rounded corners
+ * @param archeight the archeight of the rounded corners
+ */
+ public Float(float x, float y, float width, float height, float arcwidth, float archeight) {
+ setRoundRect(x, y, width, height, arcwidth, archeight);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getArcWidth() {
+ return arcwidth;
+ }
+
+ @Override
+ public double getArcHeight() {
+ return archeight;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0f || height <= 0.0f;
+ }
+
+ /**
+ * Sets the data of the round rect.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcwidth the arcwidth of the rounded corners
+ * @param archeight the archeight of the rounded corners
+ */
+ public void setRoundRect(float x, float y, float width, float height, float arcwidth, float archeight) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.arcwidth = arcwidth;
+ this.archeight = archeight;
+ }
+
+ @Override
+ public void setRoundRect(double x, double y, double width, double height, double arcwidth, double archeight) {
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ this.arcwidth = (float)arcwidth;
+ this.archeight = (float)archeight;
+ }
+
+ @Override
+ public void setRoundRect(RoundRectangle2D rr) {
+ this.x = (float)rr.getX();
+ this.y = (float)rr.getY();
+ this.width = (float)rr.getWidth();
+ this.height = (float)rr.getHeight();
+ this.arcwidth = (float)rr.getArcWidth();
+ this.archeight = (float)rr.getArcHeight();
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Float(x, y, width, height);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of RoundRectangle2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends RoundRectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public double x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public double y;
+
+ /** The width of the rectangle. */
+ public double width;
+
+ /** The height of the rectangle. */
+ public double height;
+
+ /** The arcwidth of the rounded corners. */
+ public double arcwidth;
+
+ /** The archeight of the rounded corners. */
+ public double archeight;
+
+ /**
+ * Instantiates a new double-valued RoundRectangle2D with
+ * its data-values set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued RoundRectangle2D with
+ * the specified data values.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcwidth the arcwidth of the rounded corners
+ * @param archeight the archeight of the rounded corners
+ */
+ public Double(double x, double y, double width, double height, double arcwidth, double archeight) {
+ setRoundRect(x, y, width, height, arcwidth, archeight);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getArcWidth() {
+ return arcwidth;
+ }
+
+ @Override
+ public double getArcHeight() {
+ return archeight;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setRoundRect(double x, double y, double width, double height, double arcwidth, double archeight) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.arcwidth = arcwidth;
+ this.archeight = archeight;
+ }
+
+ @Override
+ public void setRoundRect(RoundRectangle2D rr) {
+ this.x = rr.getX();
+ this.y = rr.getY();
+ this.width = rr.getWidth();
+ this.height = rr.getHeight();
+ this.arcwidth = rr.getArcWidth();
+ this.archeight = rr.getArcHeight();
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+ }
+
+ /*
+ * RoundRectangle2D path iterator
+ */
+ /**
+ * The subclass of PathIterator to traverse a RoundRectangle2D.
+ */
+ class Iterator implements PathIterator {
+
+ /*
+ * Path for round corners generated the same way as Ellipse2D
+ */
+
+ /** The coefficient to calculate control points of Bezier curves. */
+ double u = 0.5 - 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+
+ /** The points coordinates calculation table. */
+ double points[][] = {
+ { 0.0, 0.5, 0.0, 0.0 }, // MOVETO
+ { 1.0, -0.5, 0.0, 0.0 }, // LINETO
+ { 1.0, -u, 0.0, 0.0, // CUBICTO
+ 1.0, 0.0, 0.0, u,
+ 1.0, 0.0, 0.0, 0.5 },
+ { 1.0, 0.0, 1.0, -0.5 }, // LINETO
+ { 1.0, 0.0, 1.0, -u, // CUBICTO
+ 1.0, -u, 1.0, 0.0,
+ 1.0, -0.5, 1.0, 0.0 },
+ { 0.0, 0.5, 1.0, 0.0 }, // LINETO
+ { 0.0, u, 1.0, 0.0, // CUBICTO
+ 0.0, 0.0, 1.0, -u,
+ 0.0, 0.0, 1.0, -0.5 },
+ { 0.0, 0.0, 0.0, 0.5 }, // LINETO
+ { 0.0, 0.0, 0.0, u, // CUBICTO
+ 0.0, u, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0 } };
+
+ /** The segment types correspond to points array. */
+ int types[] = {
+ SEG_MOVETO,
+ SEG_LINETO,
+ SEG_CUBICTO,
+ SEG_LINETO,
+ SEG_CUBICTO,
+ SEG_LINETO,
+ SEG_CUBICTO,
+ SEG_LINETO,
+ SEG_CUBICTO};
+
+ /** The x coordinate of left-upper corner of the round rectangle bounds. */
+ double x;
+
+ /** The y coordinate of left-upper corner of the round rectangle bounds. */
+ double y;
+
+ /** The width of the round rectangle bounds. */
+ double width;
+
+ /** The height of the round rectangle bounds. */
+ double height;
+
+ /** The width of arc corners of the round rectangle. */
+ double aw;
+
+ /** The height of arc corners of the round rectangle. */
+ double ah;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new RoundRectangle2D.Iterator for given round rectangle and transformation.
+ *
+ * @param rr - the source RoundRectangle2D object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(RoundRectangle2D rr, AffineTransform at) {
+ this.x = rr.getX();
+ this.y = rr.getY();
+ this.width = rr.getWidth();
+ this.height = rr.getHeight();
+ this.aw = Math.min(width, rr.getArcWidth());
+ this.ah = Math.min(height, rr.getArcHeight());
+ this.t = at;
+ if (width < 0.0 || height < 0.0 || aw < 0.0 || ah < 0.0) {
+ index = points.length;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > points.length;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == points.length) {
+ return SEG_CLOSE;
+ }
+ int j = 0;
+ double p[] = points[index];
+ for (int i = 0; i < p.length; i += 4) {
+ coords[j++] = x + p[i + 0] * width + p[i + 1] * aw;
+ coords[j++] = y + p[i + 2] * height + p[i + 3] * ah;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, j / 2);
+ }
+ return types[index];
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == points.length) {
+ return SEG_CLOSE;
+ }
+ int j = 0;
+ double p[] = points[index];
+ for (int i = 0; i < p.length; i += 4) {
+ coords[j++] = (float)(x + p[i + 0] * width + p[i + 1] * aw);
+ coords[j++] = (float)(y + p[i + 2] * height + p[i + 3] * ah);
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, j / 2);
+ }
+ return types[index];
+ }
+
+ }
+
+ /**
+ * Instantiates a new RoundRectangle2D.
+ */
+ protected RoundRectangle2D() {
+ }
+
+ /**
+ * Gets the arc width.
+ *
+ * @return the arc width
+ */
+ public abstract double getArcWidth();
+
+ /**
+ * Gets the arc height.
+ *
+ * @return the arc height
+ */
+ public abstract double getArcHeight();
+
+ /**
+ * Sets the data of the RoundRectangle2D.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcWidth the arcwidth of the rounded corners
+ * @param arcHeight the archeight of the rounded corners
+ */
+ public abstract void setRoundRect(double x, double y, double width, double height,
+ double arcWidth, double arcHeight);
+
+ /**
+ * Sets the data of the RoundRectangle2D by copying the values
+ * from an existing RoundRectangle2D.
+ *
+ * @param rr the round rectangle to copy the data from
+ *
+ * @throws NullPointerException if rr is null
+ */
+ public void setRoundRect(RoundRectangle2D rr) {
+ setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), rr
+ .getArcWidth(), rr.getArcHeight());
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ setRoundRect(x, y, width, height, getArcWidth(), getArcHeight());
+ }
+
+ public boolean contains(double px, double py) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double rx1 = getX();
+ double ry1 = getY();
+ double rx2 = rx1 + getWidth();
+ double ry2 = ry1 + getHeight();
+
+ if (px < rx1 || px >= rx2 || py < ry1 || py >= ry2) {
+ return false;
+ }
+
+ double aw = getArcWidth() / 2.0;
+ double ah = getArcHeight() / 2.0;
+
+ double cx, cy;
+
+ if (px < rx1 + aw) {
+ cx = rx1 + aw;
+ } else
+ if (px > rx2 - aw) {
+ cx = rx2 - aw;
+ } else {
+ return true;
+ }
+
+ if (py < ry1 + ah) {
+ cy = ry1 + ah;
+ } else
+ if (py > ry2 - ah) {
+ cy = ry2 - ah;
+ } else {
+ return true;
+ }
+
+ px = (px - cx) / aw;
+ py = (py - cy) / ah;
+ return px * px + py * py <= 1.0;
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ if (rx2 < x1 || x2 < rx1 || ry2 < y1 || y2 < ry1) {
+ return false;
+ }
+
+ double cx = (x1 + x2) / 2.0;
+ double cy = (y1 + y2) / 2.0;
+
+ double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
+ double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
+
+ return contains(nx, ny);
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ return
+ contains(rx1, ry1) &&
+ contains(rx2, ry1) &&
+ contains(rx2, ry2) &&
+ contains(rx1, ry2);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+
+}
+
diff --git a/awt/java/awt/im/InputContext.java b/awt/java/awt/im/InputContext.java
new file mode 100644
index 0000000..3468474
--- /dev/null
+++ b/awt/java/awt/im/InputContext.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.awt.AWTEvent;
+//???AWT: import java.awt.Component;
+import java.util.Locale;
+
+import org.apache.harmony.awt.im.InputMethodContext;
+
+public class InputContext {
+ protected InputContext() {
+ }
+
+ public static InputContext getInstance() {
+ return new InputMethodContext();
+ }
+
+ public void dispatchEvent(AWTEvent event) {
+ }
+
+ public void dispose() {
+ }
+
+ public void endComposition() {
+ }
+
+ public Object getInputMethodControlObject() {
+ return null;
+ }
+
+ public Locale getLocale() {
+ return null;
+ }
+
+ public boolean isCompositionEnabled() {
+ return false;
+ }
+
+ public void reconvert() {
+ }
+
+ //???AWT
+ /*
+ public void removeNotify(Component client) {
+ }
+ */
+
+ public boolean selectInputMethod(Locale locale) {
+ return false;
+ }
+
+ public void setCharacterSubsets(Character.Subset[] subsets) {
+ }
+
+ public void setCompositionEnabled(boolean enable) {
+ }
+}
+
diff --git a/awt/java/awt/im/InputMethodHighlight.java b/awt/java/awt/im/InputMethodHighlight.java
new file mode 100644
index 0000000..53bb20b
--- /dev/null
+++ b/awt/java/awt/im/InputMethodHighlight.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.util.Map;
+import java.awt.font.TextAttribute;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class InputMethodHighlight {
+
+ public static final int RAW_TEXT = 0;
+
+ public static final int CONVERTED_TEXT = 1;
+
+ public static final InputMethodHighlight
+ UNSELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(false, RAW_TEXT);
+
+ public static final InputMethodHighlight
+ SELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(true, RAW_TEXT);
+
+ public static final InputMethodHighlight
+ UNSELECTED_CONVERTED_TEXT_HIGHLIGHT =
+ new InputMethodHighlight(false, CONVERTED_TEXT);
+
+ public static final InputMethodHighlight
+ SELECTED_CONVERTED_TEXT_HIGHLIGHT =
+ new InputMethodHighlight(true, CONVERTED_TEXT);
+
+ private boolean selected;
+ private int state;
+ private int variation;
+ private Map<TextAttribute,?> style;
+
+ public InputMethodHighlight(boolean selected, int state, int variation) {
+ this(selected, state, variation, null);
+ }
+
+ public InputMethodHighlight(boolean selected, int state,
+ int variation, Map<java.awt.font.TextAttribute, ?> style) {
+ if ((state != RAW_TEXT) && (state != CONVERTED_TEXT)) {
+ // awt.20B=unknown input method highlight state
+ throw new IllegalArgumentException(Messages.getString("awt.20B")); //$NON-NLS-1$
+ }
+ this.selected = selected;
+ this.state = state;
+ this.variation = variation;
+ this.style = style;
+ }
+
+ public InputMethodHighlight(boolean selected, int state) {
+ this(selected, state, 0, null);
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public Map<java.awt.font.TextAttribute, ?> getStyle() {
+ return style;
+ }
+
+ public int getVariation() {
+ return variation;
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+}
+
diff --git a/awt/java/awt/im/InputMethodRequests.java b/awt/java/awt/im/InputMethodRequests.java
new file mode 100644
index 0000000..bdd25e6
--- /dev/null
+++ b/awt/java/awt/im/InputMethodRequests.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.awt.Rectangle;
+import java.awt.font.TextHitInfo;
+import java.text.AttributedCharacterIterator;
+
+public interface InputMethodRequests {
+
+ public AttributedCharacterIterator cancelLatestCommittedText(AttributedCharacterIterator.Attribute[] attributes);
+
+ public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, AttributedCharacterIterator.Attribute[] attributes);
+
+ public int getCommittedTextLength();
+
+ public int getInsertPositionOffset();
+
+ public TextHitInfo getLocationOffset(int x, int y);
+
+ public AttributedCharacterIterator getSelectedText(AttributedCharacterIterator.Attribute[] attributes);
+
+ public Rectangle getTextLocation(TextHitInfo offset);
+}
+
diff --git a/awt/java/awt/im/InputSubset.java b/awt/java/awt/im/InputSubset.java
new file mode 100644
index 0000000..02a1049
--- /dev/null
+++ b/awt/java/awt/im/InputSubset.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt.im;
+
+public final class InputSubset extends Character.Subset {
+
+ public static final InputSubset LATIN = new InputSubset("LATIN"); //$NON-NLS-1$
+
+ public static final InputSubset
+ LATIN_DIGITS = new InputSubset("LATIN_DIGITS"); //$NON-NLS-1$
+
+ public static final InputSubset
+ TRADITIONAL_HANZI = new InputSubset("TRADITIONAL_HANZI"); //$NON-NLS-1$
+
+ public static final InputSubset
+ SIMPLIFIED_HANZI = new InputSubset("SIMPLIFIED_HANZI"); //$NON-NLS-1$
+
+ public static final InputSubset KANJI = new InputSubset("KANJI"); //$NON-NLS-1$
+
+ public static final InputSubset HANJA = new InputSubset("HANJA"); //$NON-NLS-1$
+
+ public static final InputSubset
+ HALFWIDTH_KATAKANA = new InputSubset("HALFWIDTH_KATAKANA"); //$NON-NLS-1$
+
+ public static final InputSubset
+ FULLWIDTH_LATIN = new InputSubset("FULLWIDTH_LATIN"); //$NON-NLS-1$
+
+ public static final InputSubset
+ FULLWIDTH_DIGITS = new InputSubset("FULLWIDTH_DIGITS"); //$NON-NLS-1$
+
+ private InputSubset(String name) {
+ super(name);
+ }
+}
+
diff --git a/awt/java/awt/im/spi/InputMethod.java b/awt/java/awt/im/spi/InputMethod.java
new file mode 100644
index 0000000..2c98c46
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethod.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+import java.awt.AWTEvent;
+import java.awt.Rectangle;
+import java.util.Locale;
+
+public interface InputMethod {
+
+ public void activate();
+
+ public void deactivate(boolean isTemporary);
+
+ public void dispatchEvent(AWTEvent event);
+
+ public void dispose();
+
+ public void endComposition();
+
+ public Object getControlObject();
+
+ public Locale getLocale();
+
+ public void hideWindows();
+
+ public boolean isCompositionEnabled();
+
+ public void notifyClientWindowChange(Rectangle bounds);
+
+ public void reconvert();
+
+ public void removeNotify();
+
+ public void setCharacterSubsets(Character.Subset[] subsets);
+
+ public void setCompositionEnabled(boolean enable);
+
+ public void setInputMethodContext(InputMethodContext context);
+
+ public boolean setLocale(Locale locale);
+}
+
diff --git a/awt/java/awt/im/spi/InputMethodContext.java b/awt/java/awt/im/spi/InputMethodContext.java
new file mode 100644
index 0000000..ca33e87
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethodContext.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+//???AWT: import java.awt.Window;
+import java.awt.font.TextHitInfo;
+import java.awt.im.InputMethodRequests;
+import java.text.AttributedCharacterIterator;
+//???AWT: import javax.swing.JFrame;
+
+public interface InputMethodContext extends InputMethodRequests {
+
+// ???AWT: public JFrame createInputMethodJFrame(String title, boolean attachToInputContext);
+
+// ???AWT: public Window createInputMethodWindow(String title, boolean attachToInputContext);
+
+ public void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition);
+
+ public void enableClientWindowNotification(InputMethod inputMethod, boolean enable);
+
+}
+
diff --git a/awt/java/awt/im/spi/InputMethodDescriptor.java b/awt/java/awt/im/spi/InputMethodDescriptor.java
new file mode 100644
index 0000000..3068cac
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethodDescriptor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+import java.awt.AWTException;
+import java.awt.Image;
+import java.util.Locale;
+
+public interface InputMethodDescriptor {
+
+ public Locale[] getAvailableLocales() throws AWTException;
+
+ public InputMethod createInputMethod() throws Exception;
+
+ public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage);
+
+ public Image getInputMethodIcon(Locale inputLocale);
+
+ public boolean hasDynamicLocaleList();
+
+}
+
diff --git a/awt/java/awt/image/AffineTransformOp.java b/awt/java/awt/image/AffineTransformOp.java
new file mode 100644
index 0000000..546837a
--- /dev/null
+++ b/awt/java/awt/image/AffineTransformOp.java
@@ -0,0 +1,617 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky, Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.*;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AffineTransform class translates coordinates from 2D coordinates
+ * in the source image or Raster to 2D coordinates in the destination
+ * image or Raster using Affine transformation. The number of bands in
+ * the source Raster should equal to the number of bands in the destination
+ * Raster.
+ */
+public class AffineTransformOp implements BufferedImageOp, RasterOp {
+
+ /**
+ * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor
+ * interpolation type.
+ */
+ public static final int TYPE_NEAREST_NEIGHBOR = 1;
+
+ /**
+ * The Constant TYPE_BILINEAR indicates bilinear interpolation type.
+ */
+ public static final int TYPE_BILINEAR = 2;
+
+ /** The Constant TYPE_BICUBIC indicates bicubic interpolation type. */
+ public static final int TYPE_BICUBIC = 3;
+
+ /** The i type. */
+ private int iType; // interpolation type
+
+ /** The at. */
+ private AffineTransform at;
+
+ /** The hints. */
+ private RenderingHints hints;
+
+ static {
+ // TODO - uncomment
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new AffineTransformOp with the specified
+ * AffineTransform and RenderingHints object which defines
+ * the interpolation type.
+ *
+ * @param xform the AffineTransform.
+ * @param hints the RenderingHints object which defines
+ * the interpolation type.
+ */
+ public AffineTransformOp(AffineTransform xform, RenderingHints hints) {
+ this(xform, TYPE_NEAREST_NEIGHBOR);
+ this.hints = hints;
+
+ if (hints != null) {
+ Object hint = hints.get(RenderingHints.KEY_INTERPOLATION);
+ if (hint != null) {
+ // Nearest neighbor is default
+ if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) {
+ this.iType = TYPE_BILINEAR;
+ } else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) {
+ this.iType = TYPE_BICUBIC;
+ }
+ } else {
+ hint = hints.get(RenderingHints.KEY_RENDERING);
+ // Determine from rendering quality
+ if (hint == RenderingHints.VALUE_RENDER_QUALITY) {
+ this.iType = TYPE_BILINEAR;
+ // For speed use nearest neighbor
+ }
+ }
+ }
+ }
+
+ /**
+ * Instantiates a new AffineTransformOp with the specified
+ * AffineTransform and a specified interpolation type from the
+ * list of predefined interpolation types.
+ *
+ * @param xform the AffineTransform.
+ * @param interp the one of predefined interpolation types:
+ * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC.
+ */
+ public AffineTransformOp(AffineTransform xform, int interp) {
+ if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) {
+ // awt.24F=Unable to invert transform {0}
+ throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$
+ }
+
+ this.at = (AffineTransform) xform.clone();
+
+ if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) {
+ // awt.250=Unknown interpolation type: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.250", interp)); //$NON-NLS-1$
+ }
+
+ this.iType = interp;
+ }
+
+ /**
+ * Gets the interpolation type.
+ *
+ * @return the interpolation type
+ */
+ public final int getInterpolationType() {
+ return iType;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ if (hints == null) {
+ Object value = null;
+
+ switch (iType) {
+ case TYPE_NEAREST_NEIGHBOR:
+ value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+ break;
+ case TYPE_BILINEAR:
+ value = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
+ break;
+ case TYPE_BICUBIC:
+ value = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
+ break;
+ default:
+ value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+ }
+
+ hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, value);
+ }
+
+ return hints;
+ }
+
+ /**
+ * Gets the affine transform associated with this AffineTransformOp.
+ *
+ * @return the AffineTransform.
+ */
+ public final AffineTransform getTransform() {
+ return (AffineTransform) at.clone();
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ return at.transform(srcPt, dstPt);
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ // We position source raster to (0,0) even if it is translated child raster.
+ // This means that we need only width and height of the src
+ int width = src.getWidth();
+ int height = src.getHeight();
+
+ float[] corners = {
+ 0, 0,
+ width, 0,
+ width, height,
+ 0, height
+ };
+
+ at.transform(corners, 0, corners, 0, 4);
+
+ Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+ bounds.add(corners[2], corners[3]);
+ bounds.add(corners[4], corners[5]);
+ bounds.add(corners[6], corners[7]);
+
+ return bounds;
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+ Rectangle2D newBounds = getBounds2D(src);
+
+ // Destination image should include (0,0) + positive part
+ // of the area bounded by newBounds (in source coordinate system).
+ double dstWidth = newBounds.getX() + newBounds.getWidth();
+ double dstHeight = newBounds.getY() + newBounds.getHeight();
+
+ if (dstWidth <= 0 || dstHeight <= 0) {
+ // awt.251=Transformed width ({0}) and height ({1}) should be greater than 0
+ throw new RasterFormatException(
+ Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$
+ }
+
+ if (destCM != null) {
+ return new BufferedImage(destCM,
+ destCM.createCompatibleWritableRaster((int)dstWidth, (int)dstHeight),
+ destCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ ColorModel cm = src.getColorModel();
+
+ // Interpolation other than NN doesn't make any sense for index color
+ if (iType != TYPE_NEAREST_NEIGHBOR && cm instanceof IndexColorModel) {
+ return new BufferedImage((int)dstWidth, (int)dstHeight, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ // OK, we can get source color model
+ return new BufferedImage(cm,
+ src.getRaster().createCompatibleWritableRaster((int)dstWidth, (int)dstHeight),
+ cm.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public WritableRaster createCompatibleDestRaster (Raster src) {
+ // Here approach is other then in createCompatibleDestImage -
+ // destination should include only
+ // transformed image, but not (0,0) in source coordinate system
+
+ Rectangle2D newBounds = getBounds2D(src);
+ return src.createCompatibleWritableRaster(
+ (int) newBounds.getX(), (int) newBounds.getY(),
+ (int) newBounds.getWidth(), (int)newBounds.getHeight()
+ );
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ if (src == dst) {
+ // awt.252=Source can't be same as the destination
+ throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$
+ }
+
+ ColorModel srcCM = src.getColorModel();
+ BufferedImage finalDst = null;
+
+ if (
+ srcCM instanceof IndexColorModel &&
+ (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0)
+ ) {
+ src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true);
+ srcCM = src.getColorModel();
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestImage(src, srcCM);
+ } else {
+ if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same
+ if (
+ !(
+ (src.getType() == BufferedImage.TYPE_INT_RGB ||
+ src.getType() == BufferedImage.TYPE_INT_ARGB) &&
+ (dst.getType() == BufferedImage.TYPE_INT_RGB ||
+ dst.getType() == BufferedImage.TYPE_INT_ARGB)
+ )
+ ) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ }
+ }
+ }
+
+ // Skip alpha channel for TYPE_INT_RGB images
+ if (slowFilter(src.getRaster(), dst.getRaster()) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ // TODO - uncomment
+ //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0)
+ //throw new ImagingOpException ("Unable to transform source");
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return finalDst;
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (src == dst) {
+ // awt.252=Source can't be same as the destination
+ throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else if (src.getNumBands() != dst.getNumBands()) {
+ // awt.253=Different number of bands in source and destination
+ throw new IllegalArgumentException(Messages.getString("awt.253")); //$NON-NLS-1$
+ }
+
+ if (slowFilter(src, dst) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+ // TODO - uncomment
+ //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0)
+ // throw new ImagingOpException("Unable to transform source");
+ }
+
+ return dst;
+ }
+
+ // TODO remove when method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private int ippFilter(Raster src, WritableRaster dst, int imageType) {
+ int srcStride, dstStride;
+ boolean skipChannel = false;
+ int channels;
+ int offsets[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_RGB:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ skipChannel = true;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY:
+ case BufferedImage.TYPE_BYTE_INDEXED: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code?
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels
+ if (channels != 1 && channels != 3 && channels != 4) {
+ return slowFilter(src, dst);
+ }
+
+ int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8;
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride() * dataTypeSize;
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride() * dataTypeSize;
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ // No IPP function for this type
+ if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) {
+ return slowFilter(src, dst);
+ }
+
+ channels = sppsm1.getNumBands();
+ // Have IPP functions for 1, 3 and 4 channels
+ if (channels != 1 && channels != 3 && channels != 4) {
+ return slowFilter(src, dst);
+ }
+
+ // Check compatibility of sample models
+ if (
+ sppsm1.getDataType() != sppsm2.getDataType() ||
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst);
+ }
+ }
+
+ if (channels == 3) {
+ channels = 4;
+ }
+
+ int dataTypeSize = DataBuffer.getDataTypeSize(sppsm1.getDataType()) / 8;
+
+ srcStride = sppsm1.getScanlineStride() * dataTypeSize;
+ dstStride = sppsm2.getScanlineStride() * dataTypeSize;
+ } else {
+ return slowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ double m00 = at.getScaleX();
+ double m01 = at.getShearX();
+ double m02 = at.getTranslateX();
+ double m10 = at.getShearY();
+ double m11 = at.getScaleY();
+ double m12 = at.getTranslateY();
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ return ippAffineTransform(
+ m00, m01, m02, m10, m11, m12,
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ iType, channels, skipChannel, offsets);
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private int slowFilter(Raster src, WritableRaster dst) {
+ // TODO: make correct interpolation
+ // TODO: what if there are different data types?
+
+ Rectangle srcBounds = src.getBounds();
+ Rectangle dstBounds = dst.getBounds();
+ Rectangle normDstBounds = new Rectangle(0, 0, dstBounds.width, dstBounds.height);
+ Rectangle bounds = getBounds2D(src).getBounds().intersection(normDstBounds);
+
+ AffineTransform inv = null;
+ try {
+ inv = at.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ return -1;
+ }
+
+ double[] m = new double[6];
+ inv.getMatrix(m);
+
+ int minSrcX = srcBounds.x;
+ int minSrcY = srcBounds.y;
+ int maxSrcX = srcBounds.x + srcBounds.width;
+ int maxSrcY = srcBounds.y + srcBounds.height;
+
+ int minX = bounds.x + dstBounds.x;
+ int minY = bounds.y + dstBounds.y;
+ int maxX = minX + bounds.width;
+ int maxY = minY + bounds.height;
+
+ int hx = (int)(m[0] * 256);
+ int hy = (int)(m[1] * 256);
+ int vx = (int)(m[2] * 256);
+ int vy = (int)(m[3] * 256);
+ int sx = (int)(m[4] * 256) + hx * bounds.x + vx * bounds.y + (srcBounds.x) * 256;
+ int sy = (int)(m[5] * 256) + hy * bounds.x + vy * bounds.y + (srcBounds.y) * 256;
+
+ vx -= hx * bounds.width;
+ vy -= hy * bounds.width;
+
+ if (src.getTransferType() == dst.getTransferType()) {
+ for (int y = minY; y < maxY; y++) {
+ for (int x = minX; x < maxX; x++) {
+ int px = sx >> 8;
+ int py = sy >> 8;
+ if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+ Object val = src.getDataElements(px , py , null);
+ dst.setDataElements(x, y, val);
+ }
+ sx += hx;
+ sy += hy;
+ }
+ sx += vx;
+ sy += vy;
+ }
+ } else {
+ float pixel[] = null;
+ for (int y = minY; y < maxY; y++) {
+ for (int x = minX; x < maxX; x++) {
+ int px = sx >> 8;
+ int py = sy >> 8;
+ if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+ pixel = src.getPixel(px, py, pixel);
+ dst.setPixel(x, y, pixel);
+ }
+ sx += hx;
+ sy += hy;
+ }
+ sx += vx;
+ sy += vy;
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Ipp affine transform.
+ *
+ * @param m00 the m00
+ * @param m01 the m01
+ * @param m02 the m02
+ * @param m10 the m10
+ * @param m11 the m11
+ * @param m12 the m12
+ * @param src the src
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dst the dst
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param iType the i type
+ * @param channels the channels
+ * @param skipChannel the skip channel
+ * @param offsets the offsets
+ *
+ * @return the int
+ */
+ private native int ippAffineTransform(
+ double m00, double m01,
+ double m02, double m10,
+ double m11, double m12,
+ Object src, int srcWidth, int srcHeight, int srcStride,
+ Object dst, int dstWidth, int dstHeight, int dstStride,
+ int iType, int channels, boolean skipChannel,
+ int offsets[]);
+} \ No newline at end of file
diff --git a/awt/java/awt/image/AreaAveragingScaleFilter.java b/awt/java/awt/image/AreaAveragingScaleFilter.java
new file mode 100644
index 0000000..f4933db
--- /dev/null
+++ b/awt/java/awt/image/AreaAveragingScaleFilter.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Arrays;
+
+
+/**
+ * The AreaAveragingScaleFilter class scales the source image using
+ * area averaging algorithm. This algorithm provides a source image
+ * with a new image containing the resampled image.
+ */
+public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
+
+ /** The Constant rgbCM. */
+ private static final ColorModel rgbCM = ColorModel.getRGBdefault();
+
+ /** The Constant averagingFlags. */
+ private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES);
+
+ /** The reset. */
+ private boolean reset = true; // Flag for used superclass filter
+
+ /** The inited. */
+ private boolean inited = false; // All data inited
+
+ /** The sum_r. */
+ private int sum_r[]; // Array for average Red samples
+
+ /** The sum_g. */
+ private int sum_g[]; // Array for average Green samples
+
+ /** The sum_b. */
+ private int sum_b[]; // Array for average Blue samples
+
+ /** The sum_a. */
+ private int sum_a[]; // Array for average Alpha samples
+
+ /** The buff. */
+ private int buff[]; // Stride buffer
+
+ /** The avg factor. */
+ private int avgFactor; // Global averaging factor
+
+ /** The cached dy. */
+ private int cachedDY; // Cached number of the destination scanline
+
+ /** The cached dv rest. */
+ private int cachedDVRest; // Cached value of rest src scanlines for sum
+ // pixel samples
+ // Because data if transfering by whole scanlines
+ // we are caching only Y coordinate values
+
+ /**
+ * Instantiates a new AreaAveragingScaleFilter object which scales
+ * a source image with the specified width and height.
+ *
+ * @param width the scaled width of the image.
+ * @param height the scaled height of the image.
+ */
+ public AreaAveragingScaleFilter(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) {
+ if(reset) {
+ super.setPixels(x, y, w, h, model, pixels, off, scansize);
+ } else {
+ setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) {
+ if(reset) {
+ super.setPixels(x, y, w, h, model, pixels, off, scansize);
+ } else {
+ setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+ }
+
+ @Override
+ public void setHints(int hints) {
+ super.setHints(hints);
+ reset = ((hints & averagingFlags) != averagingFlags);
+ }
+
+ /**
+ * This method implements the Area Averaging Scale filter.
+ * The description of algorithm is presented in Java API Specification.
+ *
+ * Arrays sum_r, sum_g, sum_b, sum_a have length equals width of destination
+ * image. In each array's element is accumulating pixel's component values,
+ * proportional to the area which source pixels will occupy in destination
+ * image. Then that values will divide by Global averaging
+ * factor (area of the destination image) for receiving
+ * average values of destination pixels.
+ *
+ * @param x - Src pixels X coordinate
+ * @param y - Src pixels Y coordinate
+ * @param w - width of the area of Src pixels
+ * @param h - height of the area of Src pixels
+ * @param model - Color Model of Src pixels
+ * @param pixels - array of Src pixels
+ * @param off - offset into the Src pixels array
+ * @param scansize - length of scanline in the pixels array
+ */
+ private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, int scansize){
+ if(!inited){
+ initialize();
+ }
+
+ int srcX, srcY, dx, dy;
+ int svRest, dvRest, shRest, dhRest, vDif, hDif;
+
+ if(y == 0){
+ dy = 0;
+ dvRest = srcHeight;
+ }else{
+ dy = cachedDY;
+ dvRest = cachedDVRest;
+ }
+
+ srcY = y;
+ svRest = destHeight;
+
+ int srcOff = off;
+ while (srcY < y + h) {
+ if (svRest < dvRest) {
+ vDif = svRest;
+ } else {
+ vDif = dvRest;
+ }
+
+ srcX = 0;
+ dx = 0;
+ shRest = destWidth;
+ dhRest = srcWidth;
+ while (srcX < w) {
+ if (shRest < dhRest) {
+ hDif = shRest;
+ } else {
+ hDif = dhRest;
+ }
+ int avg = hDif * vDif; // calculation of contribution factor
+
+ int rgb, pix;
+ if (pixels instanceof int[]) {
+ pix = ((int[]) pixels)[srcOff + srcX];
+ } else {
+ pix = ((byte[]) pixels)[srcOff + srcX] & 0xff;
+ }
+
+ rgb = model.getRGB(pix);
+ int a = rgb >>> 24;
+ int r = (rgb >> 16) & 0xff;
+ int g = (rgb >> 8) & 0xff;
+ int b = rgb & 0xff;
+
+ // accumulating pixel's component values
+ sum_a[dx] += a * avg;
+ sum_r[dx] += r * avg;
+ sum_g[dx] += g * avg;
+ sum_b[dx] += b * avg;
+
+ shRest -= hDif;
+ dhRest -= hDif;
+
+ if (shRest == 0) {
+ srcX++;
+ shRest = destWidth;
+ }
+
+ if (dhRest == 0) {
+ dx++;
+ dhRest = srcWidth;
+ }
+ }
+
+ svRest -= vDif;
+ dvRest -= vDif;
+
+ if (svRest == 0) {
+ svRest = destHeight;
+ srcY++;
+ srcOff += scansize;
+ }
+
+ if (dvRest == 0) {
+ // averaging destination pixel's values
+ for(int i = 0; i < destWidth; i++){
+ int a = (sum_a[i] / avgFactor) & 0xff;
+ int r = (sum_r[i] / avgFactor) & 0xff;
+ int g = (sum_g[i] / avgFactor) & 0xff;
+ int b = (sum_b[i] / avgFactor) & 0xff;
+ int frgb = (a << 24) | (r << 16) | (g << 8) | b;
+ buff[i] = frgb;
+ }
+ consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0,
+ destWidth);
+ dy++;
+ dvRest = srcHeight;
+ Arrays.fill(sum_a, 0);
+ Arrays.fill(sum_r, 0);
+ Arrays.fill(sum_g, 0);
+ Arrays.fill(sum_b, 0);
+ }
+
+ }
+
+ cachedDY = dy;
+ cachedDVRest = dvRest;
+
+ }
+
+ /**
+ * Initialization of the auxiliary data.
+ */
+ private void initialize(){
+
+ sum_a = new int[destWidth];
+ sum_r = new int[destWidth];
+ sum_g = new int[destWidth];
+ sum_b = new int[destWidth];
+
+ buff = new int[destWidth];
+ outpixbuf = buff;
+ avgFactor = srcWidth * srcHeight;
+
+ inited = true;
+ }
+}
+
diff --git a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
new file mode 100644
index 0000000..ce85ddd
--- /dev/null
+++ b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 23.11.2005
+ *
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferDouble;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferShort;
+import java.awt.image.DataBufferUShort;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.gl.GLVolatileImage;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class not part of public API. It useful for receiving package private
+ * data from other packages.
+ */
+class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor {
+
+ static void init(){
+ inst = new AwtImageBackdoorAccessorImpl();
+ }
+
+ @Override
+ public Surface getImageSurface(Image image) {
+ if (image instanceof BufferedImage){
+ return ((BufferedImage)image).getImageSurface();
+ } else if (image instanceof GLVolatileImage){
+ return ((GLVolatileImage)image).getImageSurface();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isGrayPallete(IndexColorModel icm){
+ return icm.isGrayPallete();
+ }
+
+ @Override
+ public Object getData(DataBuffer db) {
+ if (db instanceof DataBufferByte){
+ return ((DataBufferByte)db).getData();
+ } else if (db instanceof DataBufferUShort){
+ return ((DataBufferUShort)db).getData();
+ } else if (db instanceof DataBufferShort){
+ return ((DataBufferShort)db).getData();
+ } else if (db instanceof DataBufferInt){
+ return ((DataBufferInt)db).getData();
+ } else if (db instanceof DataBufferFloat){
+ return ((DataBufferFloat)db).getData();
+ } else if (db instanceof DataBufferDouble){
+ return ((DataBufferDouble)db).getData();
+ } else {
+ // awt.235=Wrong Data Buffer type : {0}
+ throw new IllegalArgumentException(Messages.getString("awt.235", //$NON-NLS-1$
+ db.getClass()));
+ }
+ }
+
+ @Override
+ public int[] getDataInt(DataBuffer db) {
+ if (db instanceof DataBufferInt){
+ return ((DataBufferInt)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public byte[] getDataByte(DataBuffer db) {
+ if (db instanceof DataBufferByte){
+ return ((DataBufferByte)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public short[] getDataShort(DataBuffer db) {
+ if (db instanceof DataBufferShort){
+ return ((DataBufferShort)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public short[] getDataUShort(DataBuffer db) {
+ if (db instanceof DataBufferUShort){
+ return ((DataBufferUShort)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public double[] getDataDouble(DataBuffer db) {
+ if (db instanceof DataBufferDouble){
+ return ((DataBufferDouble)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public float[] getDataFloat(DataBuffer db) {
+ if (db instanceof DataBufferFloat){
+ return ((DataBufferFloat)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public void addDataBufferListener(DataBuffer db, DataBufferListener listener) {
+ db.addDataBufferListener(listener);
+ }
+
+ @Override
+ public void removeDataBufferListener(DataBuffer db) {
+ db.removeDataBufferListener();
+ }
+
+ @Override
+ public void validate(DataBuffer db) {
+ db.validate();
+ }
+
+ @Override
+ public void releaseData(DataBuffer db) {
+ db.releaseData();
+ }
+}
diff --git a/awt/java/awt/image/BandCombineOp.java b/awt/java/awt/image/BandCombineOp.java
new file mode 100644
index 0000000..cd77a21
--- /dev/null
+++ b/awt/java/awt/image/BandCombineOp.java
@@ -0,0 +1,610 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 20, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BandCombineOp class translates coordinates from
+ * coordinates in the source Raster to coordinates in
+ * the destination Raster by an arbitrary linear combination
+ * of the bands in a source Raster, using a specified matrix.
+ * The number of bands in the matrix should equal to
+ * the number of bands in the source Raster plus 1.
+ */
+public class BandCombineOp implements RasterOp {
+
+ /** The Constant offsets3c. */
+ static final int offsets3c[] = {16, 8, 0};
+
+ /** The Constant offsets4ac. */
+ static final int offsets4ac[] = {16, 8, 0, 24};
+
+ /** The Constant masks3c. */
+ static final int masks3c[] = {0xFF0000, 0xFF00, 0xFF};
+
+ /** The Constant masks4ac. */
+ static final int masks4ac[] = {0xFF0000, 0xFF00, 0xFF, 0xFF000000};
+
+ /** The Constant piOffsets. */
+ private static final int piOffsets[] = {0, 1, 2};
+
+ /** The Constant piInvOffsets. */
+ private static final int piInvOffsets[] = {2, 1, 0};
+
+ /** The Constant TYPE_BYTE3C. */
+ private static final int TYPE_BYTE3C = 0;
+
+ /** The Constant TYPE_BYTE4AC. */
+ private static final int TYPE_BYTE4AC = 1;
+
+ /** The Constant TYPE_USHORT3C. */
+ private static final int TYPE_USHORT3C = 2;
+
+ /** The Constant TYPE_SHORT3C. */
+ private static final int TYPE_SHORT3C = 3;
+
+ /** The mx width. */
+ private int mxWidth;
+
+ /** The mx height. */
+ private int mxHeight;
+
+ /** The matrix. */
+ private float matrix[][];
+
+ /** The r hints. */
+ private RenderingHints rHints;
+
+ static {
+ // XXX - todo
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new BandCombineOp object with the specified
+ * matrix.
+ *
+ * @param matrix the specified matrix for band combining.
+ * @param hints the RenderingHints.
+ */
+ public BandCombineOp(float matrix[][], RenderingHints hints) {
+ this.mxHeight = matrix.length;
+ this.mxWidth = matrix[0].length;
+ this.matrix = new float[mxHeight][mxWidth];
+
+ for (int i=0; i<mxHeight; i++){
+ System.arraycopy(matrix[i], 0, this.matrix[i], 0, mxWidth);
+ }
+
+ this.rHints = hints;
+ }
+
+ public final RenderingHints getRenderingHints(){
+ return this.rHints;
+ }
+
+ /**
+ * Gets the matrix associated with this BandCombineOp object.
+ *
+ * @return the matrix associated with this BandCombineOp object.
+ */
+ public final float[][] getMatrix() {
+ float res[][] = new float[mxHeight][mxWidth];
+
+ for (int i=0; i<mxHeight; i++) {
+ System.arraycopy(matrix[i], 0, res[i], 0, mxWidth);
+ }
+
+ return res;
+ }
+
+ public final Point2D getPoint2D (Point2D srcPoint, Point2D dstPoint) {
+ if (dstPoint == null) {
+ dstPoint = new Point2D.Float();
+ }
+
+ dstPoint.setLocation(srcPoint);
+ return dstPoint;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src){
+ return src.getBounds();
+ }
+
+ public WritableRaster createCompatibleDestRaster (Raster src) {
+ int numBands = src.getNumBands();
+ if (mxWidth != numBands && mxWidth != (numBands+1) || numBands != mxHeight) {
+ // awt.254=Number of bands in the source raster ({0}) is
+ // incompatible with the matrix [{1}x{2}]
+ throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$
+ new Object[]{numBands, mxWidth, mxHeight}));
+ }
+
+ return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+ }
+
+ public WritableRaster filter(Raster src, WritableRaster dst) {
+ int numBands = src.getNumBands();
+
+ if (mxWidth != numBands && mxWidth != (numBands+1)) {
+ // awt.254=Number of bands in the source raster ({0}) is
+ // incompatible with the matrix [{1}x{2}]
+ throw new IllegalArgumentException(
+ Messages.getString("awt.254", //$NON-NLS-1$
+ new Object[]{numBands, mxWidth, mxHeight}));
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else if (dst.getNumBands() != mxHeight) {
+ // awt.255=Number of bands in the destination raster ({0}) is incompatible with the matrix [{1}x{2}]
+ throw new IllegalArgumentException(Messages.getString("awt.255", //$NON-NLS-1$
+ new Object[]{dst.getNumBands(), mxWidth, mxHeight}));
+ }
+
+ // XXX - todo
+ //if (ippFilter(src, dst) != 0)
+ if (verySlowFilter(src, dst) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ /**
+ * The Class SampleModelInfo.
+ */
+ private static final class SampleModelInfo {
+
+ /** The channels. */
+ int channels;
+
+ /** The channels order. */
+ int channelsOrder[];
+
+ /** The stride. */
+ int stride;
+ }
+
+ /**
+ * Check sample model.
+ *
+ * @param sm the sm
+ *
+ * @return the sample model info
+ */
+ private final SampleModelInfo checkSampleModel(SampleModel sm) {
+ SampleModelInfo ret = new SampleModelInfo();
+
+ if (sm instanceof PixelInterleavedSampleModel) {
+ // Check PixelInterleavedSampleModel
+ if (sm.getDataType() != DataBuffer.TYPE_BYTE) {
+ return null;
+ }
+
+ ret.channels = sm.getNumBands();
+ ret.stride = ((ComponentSampleModel) sm).getScanlineStride();
+ ret.channelsOrder = ((ComponentSampleModel) sm).getBandOffsets();
+
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) sm;
+
+ ret.channels = sppsm1.getNumBands();
+ if (sppsm1.getDataType() != DataBuffer.TYPE_INT) {
+ return null;
+ }
+
+ // Check sample models
+ for (int i=0; i<ret.channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return null;
+ }
+ }
+
+ ret.channelsOrder = new int[ret.channels];
+ int bitOffsets[] = sppsm1.getBitOffsets();
+ for (int i=0; i<ret.channels; i++) {
+ if (bitOffsets[i] % 8 != 0) {
+ return null;
+ }
+
+ ret.channelsOrder[i] = bitOffsets[i] / 8;
+ }
+
+ ret.channels = 4;
+ ret.stride = sppsm1.getScanlineStride() * 4;
+ } else {
+ return null;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private final int slowFilter(Raster src, WritableRaster dst) {
+ int res = 0;
+
+ SampleModelInfo srcInfo, dstInfo;
+ int offsets[] = null;
+
+ srcInfo = checkSampleModel(src.getSampleModel());
+ dstInfo = checkSampleModel(dst.getSampleModel());
+ if (srcInfo == null || dstInfo == null) {
+ return verySlowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+
+ int rmxWidth = (srcInfo.channels+1); // width of the reordered matrix
+ float reorderedMatrix[] = new float[rmxWidth*dstInfo.channels];
+ for (int j=0; j<dstInfo.channels; j++) {
+ if (j >= dstInfo.channelsOrder.length) {
+ continue;
+ }
+
+ for (int i=0; i<srcInfo.channels; i++) {
+ if (i >= srcInfo.channelsOrder.length) {
+ break;
+ }
+
+ reorderedMatrix[dstInfo.channelsOrder[j]*rmxWidth + srcInfo.channelsOrder[i]] =
+ matrix[j][i];
+ }
+ if (mxWidth == rmxWidth) {
+ reorderedMatrix[(dstInfo.channelsOrder[j]+1)*rmxWidth - 1] = matrix[j][mxWidth-1];
+ }
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ simpleCombineBands(
+ srcData, src.getWidth(), src.getHeight(), srcInfo.stride, srcInfo.channels,
+ dstData, dstInfo.stride, dstInfo.channels,
+ reorderedMatrix, offsets
+ );
+
+ return res;
+ }
+
+ /**
+ * Very slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private int verySlowFilter(Raster src, WritableRaster dst) {
+ int numBands = src.getNumBands();
+
+ int srcMinX = src.getMinX();
+ int srcY = src.getMinY();
+
+ int dstMinX = dst.getMinX();
+ int dstY = dst.getMinY();
+
+ int dX = src.getWidth();//< dst.getWidth() ? src.getWidth() : dst.getWidth();
+ int dY = src.getHeight();//< dst.getHeight() ? src.getHeight() : dst.getHeight();
+
+ float sample;
+ int srcPixels[] = new int[numBands*dX*dY];
+ int dstPixels[] = new int[mxHeight*dX*dY];
+
+ srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels);
+
+ if (numBands == mxWidth) {
+ for (int i=0, j=0; i<srcPixels.length; i+=numBands) {
+ for (int dstB = 0; dstB < mxHeight; dstB++) {
+ sample = 0f;
+ for (int srcB = 0; srcB < numBands; srcB++) {
+ sample += matrix[dstB][srcB] * srcPixels[i+srcB];
+ }
+ dstPixels[j++] = (int) sample;
+ }
+ }
+ } else {
+ for (int i=0, j=0; i<srcPixels.length; i+=numBands) {
+ for (int dstB = 0; dstB < mxHeight; dstB++) {
+ sample = 0f;
+ for (int srcB = 0; srcB < numBands; srcB++) {
+ sample += matrix[dstB][srcB] * srcPixels[i+srcB];
+ }
+ dstPixels[j++] = (int) (sample + matrix[dstB][numBands]);
+ }
+ }
+ }
+
+ dst.setPixels(dstMinX, dstY, dX, dY, dstPixels);
+
+ return 0;
+ }
+
+ //TODO remove when method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private int ippFilter(Raster src, WritableRaster dst) {
+ boolean invertChannels;
+ boolean inPlace = (src == dst);
+ int type;
+ int srcStride, dstStride;
+ int offsets[] = null;
+
+ int srcBands = src.getNumBands();
+ int dstBands = dst.getNumBands();
+
+ if (
+ dstBands != 3 ||
+ (srcBands != 3 &&
+ !(srcBands == 4 &&
+ matrix[0][3] == 0 &&
+ matrix[1][3] == 0 &&
+ matrix[2][3] == 0)
+ )
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ // Check sample models
+ if (
+ !Arrays.equals(sppsm2.getBitOffsets(), offsets3c) ||
+ !Arrays.equals(sppsm2.getBitMasks(), masks3c)
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ if (srcBands == 3) {
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), offsets3c) ||
+ !Arrays.equals(sppsm1.getBitMasks(), masks3c)
+ ) {
+ return slowFilter(src, dst);
+ }
+ } else if (srcBands == 4) {
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), offsets4ac) ||
+ !Arrays.equals(sppsm1.getBitMasks(), masks4ac)
+ ) {
+ return slowFilter(src, dst);
+ }
+ }
+
+ type = TYPE_BYTE4AC;
+ invertChannels = true;
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ if (srcBands != 3) {
+ return slowFilter(src, dst);
+ }
+
+ int srcDataType = srcSM.getDataType();
+
+ switch (srcDataType) {
+ case DataBuffer.TYPE_BYTE:
+ type = TYPE_BYTE3C;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ type = TYPE_USHORT3C;
+ break;
+ case DataBuffer.TYPE_SHORT:
+ type = TYPE_SHORT3C;
+ break;
+ default:
+ return slowFilter(src, dst);
+ }
+
+ // Check PixelInterleavedSampleModel
+ PixelInterleavedSampleModel pism1 = (PixelInterleavedSampleModel) srcSM;
+ PixelInterleavedSampleModel pism2 = (PixelInterleavedSampleModel) dstSM;
+
+ if (
+ srcDataType != pism2.getDataType() ||
+ pism1.getPixelStride() != 3 ||
+ pism2.getPixelStride() != 3 ||
+ !Arrays.equals(pism1.getBandOffsets(), pism2.getBandOffsets())
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ if (Arrays.equals(pism1.getBandOffsets(), piInvOffsets)) {
+ invertChannels = true;
+ } else if (Arrays.equals(pism1.getBandOffsets(), piOffsets)) {
+ invertChannels = false;
+ } else {
+ return slowFilter(src, dst);
+ }
+
+ int dataTypeSize = DataBuffer.getDataTypeSize(srcDataType) / 8;
+
+ srcStride = pism1.getScanlineStride() * dataTypeSize;
+ dstStride = pism2.getScanlineStride() * dataTypeSize;
+ } else { // XXX - todo - IPP allows support for planar data also
+ return slowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ float ippMatrix[] = new float[12];
+
+ if (invertChannels) {
+ // IPP treats big endian integers like BGR, so we have to
+ // swap columns 1 and 3 and rows 1 and 3
+ for (int i = 0; i < mxHeight; i++) {
+ ippMatrix[i*4] = matrix[2-i][2];
+ ippMatrix[i*4+1] = matrix[2-i][1];
+ ippMatrix[i*4+2] = matrix[2-i][0];
+
+ if (mxWidth == 4) {
+ ippMatrix[i*4+3] = matrix[2-i][3];
+ } else if (mxWidth == 5) {
+ ippMatrix[i*4+3] = matrix[2-i][4];
+ }
+ }
+ } else {
+ for (int i = 0; i < mxHeight; i++) {
+ ippMatrix[i*4] = matrix[i][0];
+ ippMatrix[i*4+1] = matrix[i][1];
+ ippMatrix[i*4+2] = matrix[i][2];
+
+ if (mxWidth == 4) {
+ ippMatrix[i*4+3] = matrix[i][3];
+ } else if (mxWidth == 5) {
+ ippMatrix[i*4+3] = matrix[i][4];
+ }
+ }
+ }
+
+ return ippColorTwist(
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ ippMatrix, type, offsets, inPlace);
+ }
+
+ /**
+ * Ipp color twist.
+ *
+ * @param srcData the src data
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dstData the dst data
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param ippMatrix the ipp matrix
+ * @param type the type
+ * @param offsets the offsets
+ * @param inPlace the in place
+ *
+ * @return the int
+ */
+ private final native int ippColorTwist(
+ Object srcData, int srcWidth, int srcHeight, int srcStride,
+ Object dstData, int dstWidth, int dstHeight, int dstStride,
+ float ippMatrix[], int type, int offsets[], boolean inPlace
+ );
+
+ /**
+ * Simple combine bands.
+ *
+ * @param srcData the src data
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param srcChannels the src channels
+ * @param dstData the dst data
+ * @param dstStride the dst stride
+ * @param dstChannels the dst channels
+ * @param m the m
+ * @param offsets the offsets
+ *
+ * @return the int
+ */
+ private final native int simpleCombineBands(
+ Object srcData, int srcWidth, int srcHeight, int srcStride, int srcChannels,
+ Object dstData, int dstStride, int dstChannels,
+ float m[], int offsets[]
+ );
+}
diff --git a/awt/java/awt/image/BandedSampleModel.java b/awt/java/awt/image/BandedSampleModel.java
new file mode 100644
index 0000000..392e44c
--- /dev/null
+++ b/awt/java/awt/image/BandedSampleModel.java
@@ -0,0 +1,426 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BandedSampleModel class provides samples of pixels in an image
+ * which is stored in a band interleaved method. Each pixel's sample
+ * takes one data element of the DataBuffer. The pixel stride for a
+ * BandedSampleModel is one.
+ */
+public final class BandedSampleModel extends ComponentSampleModel {
+
+ /**
+ * Creates the indices.
+ *
+ * @param numBands the num bands
+ *
+ * @return the int[]
+ */
+ private static int[] createIndices(int numBands) {
+ int indices[] = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ indices[i] = i;
+ }
+ return indices;
+ }
+
+ /**
+ * Creates the offsets.
+ *
+ * @param numBands the num bands
+ *
+ * @return the int[]
+ */
+ private static int[] createOffsets(int numBands) {
+ int offsets[] = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ offsets[i] = 0;
+ }
+ return offsets;
+ }
+
+ /**
+ * Instantiates a new BandedSampleModel object with the specified
+ * data type of samples, the width, height and bands number
+ * of image data.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param numBands the number of bands.
+ */
+ public BandedSampleModel(int dataType, int w, int h, int numBands) {
+ this(dataType, w, h, w, BandedSampleModel.createIndices(numBands),
+ BandedSampleModel.createOffsets(numBands));
+ }
+
+ /**
+ * Instantiates a new BandedSampleModel object with the specified
+ * data type of samples, the width, height and bands number
+ * of image data.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param scanlineStride the scanline stride of the of the image data.
+ * @param bankIndices the array of the bank indecies.
+ * @param bandOffsets the array of the band offsets.
+ */
+ public BandedSampleModel(int dataType, int w, int h, int scanlineStride,
+ int bankIndices[], int bandOffsets[]) {
+ super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new BandedSampleModel(dataType, w, h, w, bankIndices,
+ bandOffsets);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer data = null;
+ int size = scanlineStride * height;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size, numBanks);
+ break;
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size, numBanks);
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ data = new DataBufferFloat(size, numBanks);
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ data = new DataBufferDouble(size, numBanks);
+ break;
+ }
+
+ return data;
+
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int[] bands) {
+ if (bands.length > numBands) {
+ // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+ throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+ }
+
+ int indices[] = new int[bands.length];
+ int offsets[] = new int[bands.length];
+
+ for (int i = 0; i < bands.length; i++) {
+ indices[i] = bankIndices[bands[i]];
+ offsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new BandedSampleModel(dataType, width, height, scanlineStride,
+ indices, offsets);
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE: {
+ byte bdata[];
+
+ if (obj == null) {
+ bdata = new byte[numBands];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ bdata[i] = (byte) getSample(x, y, i, data);
+ }
+
+ obj = bdata;
+ break;
+ }
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT: {
+ short sdata[];
+
+ if (obj == null) {
+ sdata = new short[numBands];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ sdata[i] = (short) getSample(x, y, i, data);
+ }
+
+ obj = sdata;
+ break;
+ }
+ case DataBuffer.TYPE_INT: {
+ int idata[];
+
+ if (obj == null) {
+ idata = new int[numBands];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ idata[i] = getSample(x, y, i, data);
+ }
+
+ obj = idata;
+ break;
+ }
+ case DataBuffer.TYPE_FLOAT: {
+ float fdata[];
+
+ if (obj == null) {
+ fdata = new float[numBands];
+ } else {
+ fdata = (float[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ fdata[i] = getSampleFloat(x, y, i, data);
+ }
+
+ obj = fdata;
+ break;
+ }
+ case DataBuffer.TYPE_DOUBLE: {
+ double ddata[];
+
+ if (obj == null) {
+ ddata = new double[numBands];
+ } else {
+ ddata = (double[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ ddata[i] = getSampleDouble(x, y, i, data);
+ }
+
+ obj = ddata;
+ break;
+ }
+ }
+
+ return obj;
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ int pixel[];
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElem(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b]);
+ }
+
+ @Override
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemDouble(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b]);
+ }
+
+ @Override
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemFloat(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b]);
+ }
+
+ @Override
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ int tmp = hash >>> 8;
+ hash <<= 8;
+ hash |= tmp;
+
+ return hash ^ 0x55;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[] = (byte[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, bdata[i] & 0xff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sdata[] = (short[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, sdata[i] & 0xffff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int idata[] = (int[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, idata[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fdata[] = (float[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, fdata[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double ddata[] = (double[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, ddata[i], data);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemDouble(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemFloat(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElem(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, iArray[idx++], data);
+ }
+ }
+
+ }
+
+}
+
diff --git a/awt/java/awt/image/BufferStrategy.java b/awt/java/awt/image/BufferStrategy.java
new file mode 100644
index 0000000..e0508f0
--- /dev/null
+++ b/awt/java/awt/image/BufferStrategy.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.BufferCapabilities;
+import java.awt.Graphics;
+
+/**
+ * The BufferStrategy abstract class provides an opportunity
+ * to organize the buffers for a Canvas or Window. The BufferStrategy
+ * implementation depends on hardware and software limitations.
+ * These limitations are detectible through the capabilities
+ * object which can be obtained by the GraphicsConfiguration of the Canvas
+ * or Window.
+ */
+public abstract class BufferStrategy {
+
+ /**
+ * Returns true if the drawing buffer was lost since the last call
+ * of getDrawGraphics.
+ *
+ * @return true if the drawing buffer was lost since the last call
+ * of getDrawGraphics, false otherwise.
+ */
+ public abstract boolean contentsLost();
+
+ /**
+ * Returns true if the drawing buffer is restored from a lost state.
+ *
+ * @return true if the drawing buffer is restored from a lost state,
+ * false otherwise.
+ */
+ public abstract boolean contentsRestored();
+
+ /**
+ * Gets the BufferCapabilities of BufferStrategy.
+ *
+ * @return the BufferCapabilities of BufferStrategy.
+ */
+ public abstract BufferCapabilities getCapabilities();
+
+ /**
+ * Gets the Graphics object to use to draw to the buffer.
+ *
+ * @return the Graphics object to use to draw to the buffer.
+ */
+ public abstract Graphics getDrawGraphics();
+
+ /**
+ * Shows the next available buffer.
+ */
+ public abstract void show();
+
+}
diff --git a/awt/java/awt/image/BufferedImage.java b/awt/java/awt/image/BufferedImage.java
new file mode 100644
index 0000000..d305d66
--- /dev/null
+++ b/awt/java/awt/image/BufferedImage.java
@@ -0,0 +1,931 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.BufferedImageSource;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * The BufferedImage class describes an Image which contains a buffer
+ * of image data and includes a ColorModel and a Raster for this data.
+ * This class provides methods for obtaining and setting the Raster
+ * and for manipulating the ColorModel parameters.
+ */
+public class BufferedImage extends
+Image implements WritableRenderedImage, Transparency{
+
+ /**
+ * The Constant TYPE_CUSTOM indicates that Image type
+ * is unknown.
+ */
+ public static final int TYPE_CUSTOM = 0;
+
+ /**
+ * The Constant TYPE_INT_RGB indicates an image with
+ * 8 bit RGB color components, it has a DirectColorModel
+ * without alpha.
+ */
+ public static final int TYPE_INT_RGB = 1;
+
+ /**
+ * The Constant TYPE_INT_ARGB indicates an image with
+ * 8 bit RGBA color components, it has a DirectColorModel
+ * with alpha.
+ */
+ public static final int TYPE_INT_ARGB = 2;
+
+ /**
+ * The Constant TYPE_INT_ARGB_PRE indicates an image with
+ * 8 bit RGBA color components, it has a DirectColorModel
+ * with alpha, and image data is premultiplied by alpha.
+ */
+ public static final int TYPE_INT_ARGB_PRE = 3;
+
+ /**
+ * The Constant TYPE_INT_BGR indicates an image with
+ * 8 bit RGB color components, BGR color model
+ * (with the colors Blue, Green, and Red). There is no
+ * alpha. The image has a DirectColorModel.
+ */
+ public static final int TYPE_INT_BGR = 4;
+
+ /**
+ * The Constant TYPE_3BYTE_BGR indicates an image with
+ * 8 bit RGB color components, BGR color model
+ * (with the colors Blue, Green, and Red stored in 3 bytes).
+ * There is no alpha. The image has a ComponentColorModel.
+ */
+ public static final int TYPE_3BYTE_BGR = 5;
+
+ /**
+ * The Constant TYPE_4BYTE_ABGR indicates an image with
+ * 8 bit RGBA color components stored in 3 bytes and 1 byte of alpha.
+ * It has a ComponentColorModel with alpha.
+ */
+ public static final int TYPE_4BYTE_ABGR = 6;
+
+ /**
+ * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with
+ * 8 bit RGBA color components stored in 3 bytes and 1 byte
+ * for alpha. The image has a ComponentColorModel with alpha.
+ * The color data is premultiplied with alpha.
+ */
+ public static final int TYPE_4BYTE_ABGR_PRE = 7;
+
+ /**
+ * The Constant TYPE_USHORT_565_RGB indicates an image with
+ * 565 RGB color components (5-bits red, 6-bits green, 5-bits blue)
+ * with no alpha. This image has a DirectColorModel.
+ */
+ public static final int TYPE_USHORT_565_RGB = 8;
+
+ /**
+ * The Constant TYPE_USHORT_555_RGB indicates an image with
+ * 555 RGB color components (5-bits red, 5-bits green, 5-bits blue)
+ * with no alpha. This image has a DirectColorModel.
+ */
+ public static final int TYPE_USHORT_555_RGB = 9;
+
+ /**
+ * The Constant TYPE_BYTE_GRAY indicates a unsigned byte
+ * image. This image has a ComponentColorModel with
+ * a CS_GRAY ColorSpace.
+ */
+ public static final int TYPE_BYTE_GRAY = 10;
+
+ /**
+ * The Constant TYPE_USHORT_GRAY indicates an unsigned short
+ * image. This image has a ComponentColorModel with a CS_GRAY
+ * ColorSpace.
+ */
+ public static final int TYPE_USHORT_GRAY = 11;
+
+ /**
+ * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed
+ * 1, 2 or 4 bit image. The image has an IndexColorModel without
+ * alpha.
+ */
+ public static final int TYPE_BYTE_BINARY = 12;
+
+ /**
+ * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image.
+ */
+ public static final int TYPE_BYTE_INDEXED = 13;
+
+ /** The Constant ALPHA_MASK. */
+ private static final int ALPHA_MASK = 0xff000000;
+
+ /** The Constant RED_MASK. */
+ private static final int RED_MASK = 0x00ff0000;
+
+ /** The Constant GREEN_MASK. */
+ private static final int GREEN_MASK = 0x0000ff00;
+
+ /** The Constant BLUE_MASK. */
+ private static final int BLUE_MASK = 0x000000ff;
+
+ /** The Constant RED_BGR_MASK. */
+ private static final int RED_BGR_MASK = 0x000000ff;
+
+ /** The Constant GREEN_BGR_MASK. */
+ private static final int GREEN_BGR_MASK = 0x0000ff00;
+
+ /** The Constant BLUE_BGR_MASK. */
+ private static final int BLUE_BGR_MASK = 0x00ff0000;
+
+ /** The Constant RED_565_MASK. */
+ private static final int RED_565_MASK = 0xf800;
+
+ /** The Constant GREEN_565_MASK. */
+ private static final int GREEN_565_MASK = 0x07e0;
+
+ /** The Constant BLUE_565_MASK. */
+ private static final int BLUE_565_MASK = 0x001f;
+
+ /** The Constant RED_555_MASK. */
+ private static final int RED_555_MASK = 0x7c00;
+
+ /** The Constant GREEN_555_MASK. */
+ private static final int GREEN_555_MASK = 0x03e0;
+
+ /** The Constant BLUE_555_MASK. */
+ private static final int BLUE_555_MASK = 0x001f;
+
+ /** The cm. */
+ private ColorModel cm;
+
+ /** The raster. */
+ private final WritableRaster raster;
+
+ /** The image type. */
+ private final int imageType;
+
+ /** The properties. */
+ private Hashtable<?, ?> properties;
+
+ // Surface of the Buffered Image - used for blitting one Buffered Image
+ // on the other one or on the Component
+ /** The image surf. */
+ private final ImageSurface imageSurf;
+
+ /**
+ * Instantiates a new BufferedImage with the specified ColorModel,
+ * and WritableRaster objects. The Raster data can be
+ * be divided or multiplied by alpha. It depends on the
+ * alphaPremultiplied state in the ColorModel.
+ *
+ * @param cm the ColorModel of the new image.
+ * @param raster the WritableRaster of the new image.
+ * @param isRasterPremultiplied if true the data of the specified
+ * Raster is premultiplied by alpha.
+ * @param properties the properties of new Image.
+ */
+ public BufferedImage(ColorModel cm, WritableRaster raster,
+ boolean isRasterPremultiplied, Hashtable<?, ?> properties) {
+ if (!cm.isCompatibleRaster(raster)) {
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+
+ if (raster.getMinX() != 0 || raster.getMinY() != 0) {
+ // awt.228=minX or minY of this raster not equal to zero
+ throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$
+ }
+
+ this.cm = cm;
+ this.raster = raster;
+ this.properties = properties;
+
+ coerceData(isRasterPremultiplied);
+
+ imageType = Surface.getType(cm, raster);
+
+ imageSurf = createImageSurface(imageType);
+ }
+
+ /**
+ * Instantiates a new BufferedImage with the specified width, height
+ * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED)
+ * and the specified IndexColorModel.
+ *
+ * @param width the width of new image.
+ * @param height the height of new image.
+ * @param imageType the predefined image type.
+ * @param cm the specified IndexColorModel.
+ */
+ public BufferedImage(int width, int height, int imageType,
+ IndexColorModel cm) {
+ switch (imageType) {
+ case TYPE_BYTE_BINARY:
+ if (cm.hasAlpha()) {
+ // awt.227=This image type can't have alpha
+ throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$
+ }
+ int pixel_bits = 0;
+ int mapSize = cm.getMapSize();
+ if (mapSize <= 2) {
+ pixel_bits = 1;
+ } else if (mapSize <= 4) {
+ pixel_bits = 2;
+ } else if (mapSize <= 16) {
+ pixel_bits = 4;
+ } else {
+ // awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries
+ throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$
+ }
+
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width,
+ height, 1, pixel_bits, null);
+ break;
+
+ case TYPE_BYTE_INDEXED:
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, 1, null);
+ break;
+
+ default:
+ // awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
+ throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$
+
+ }
+
+ if (!cm.isCompatibleRaster(raster)) {
+ // awt.223=The imageType is not compatible with ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$
+ }
+
+ this.cm = cm;
+ this.imageType = imageType;
+ imageSurf = createImageSurface(imageType);
+
+ }
+
+ /**
+ * Instantiates a new BufferedImage with the specified width, height
+ * and predefined image type.
+ *
+ * @param width the width of new image.
+ * @param height the height of new image.
+ * @param imageType the predefined image type.
+ */
+ public BufferedImage(int width, int height, int imageType) {
+
+ switch (imageType) {
+ case TYPE_INT_RGB:
+ cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK);
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_INT_ARGB:
+ cm = ColorModel.getRGBdefault();
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_INT_ARGB_PRE:
+ cm = new DirectColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 32,
+ RED_MASK,
+ GREEN_MASK,
+ BLUE_MASK,
+ ALPHA_MASK,
+ true,
+ DataBuffer.TYPE_INT);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_INT_BGR:
+ cm = new DirectColorModel(24,
+ RED_BGR_MASK,
+ GREEN_BGR_MASK,
+ BLUE_BGR_MASK);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_3BYTE_BGR: {
+ int bits[] = { 8, 8, 8 };
+ int bandOffsets[] = { 2, 1, 0 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ bits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, width * 3, 3, bandOffsets, null);
+ }
+ break;
+
+ case TYPE_4BYTE_ABGR: {
+ int bits[] = { 8, 8, 8, 8 };
+ int bandOffsets[] = { 3, 2, 1, 0 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ bits,
+ true,
+ false,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, width * 4, 4, bandOffsets, null);
+ }
+ break;
+
+ case TYPE_4BYTE_ABGR_PRE: {
+ int bits[] = { 8, 8, 8, 8 };
+ int bandOffsets[] = { 3, 2, 1, 0 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ bits,
+ true,
+ true,
+ Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, width * 4, 4, bandOffsets, null);
+ }
+ break;
+
+ case TYPE_USHORT_565_RGB:
+ cm = new DirectColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 16,
+ RED_565_MASK,
+ GREEN_565_MASK,
+ BLUE_565_MASK,
+ 0,
+ false,
+ DataBuffer.TYPE_USHORT);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_USHORT_555_RGB:
+ cm = new DirectColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 15,
+ RED_555_MASK,
+ GREEN_555_MASK,
+ BLUE_555_MASK,
+ 0,
+ false,
+ DataBuffer.TYPE_USHORT);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_BYTE_GRAY: {
+ int bits[] = { 8 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ bits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ }
+ break;
+
+ case TYPE_USHORT_GRAY: {
+ int bits[] = { 16 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ bits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_USHORT);
+ raster = cm.createCompatibleWritableRaster(width, height);
+ }
+ break;
+
+ case TYPE_BYTE_BINARY: {
+ int colorMap[] = { 0, 0xffffff };
+ cm = new IndexColorModel(1, 2, colorMap, 0, false, -1,
+ DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width,
+ height, 1, 1, null);
+ }
+ break;
+
+ case TYPE_BYTE_INDEXED: {
+ int colorMap[] = new int[256];
+ int i = 0;
+ for (int r = 0; r < 256; r += 51) {
+ for (int g = 0; g < 256; g += 51) {
+ for (int b = 0; b < 256; b += 51) {
+ colorMap[i] = (r << 16) | (g << 8) | b;
+ i++;
+ }
+ }
+ }
+
+ int gray = 0x12;
+ for (; i < 256; i++, gray += 6) {
+ colorMap[i] = (gray << 16) | (gray << 8) | gray;
+ }
+ cm = new IndexColorModel(8, 256, colorMap, 0, false, -1,
+ DataBuffer.TYPE_BYTE);
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, 1, null);
+
+ }
+ break;
+ default:
+ // awt.224=Unknown image type
+ throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$
+ }
+ this.imageType = imageType;
+ imageSurf = createImageSurface(imageType);
+ }
+
+ @Override
+ public Object getProperty(String name, ImageObserver observer) {
+ return getProperty(name);
+ }
+
+ public Object getProperty(String name) {
+ if(name == null) {
+ // awt.225=Property name is null
+ throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$
+ }
+ if (properties == null) {
+ return Image.UndefinedProperty;
+ }
+ Object property = properties.get(name);
+ if (property == null) {
+ property = Image.UndefinedProperty;
+ }
+ return property;
+ }
+
+ public WritableRaster copyData(WritableRaster outRaster) {
+ if (outRaster == null) {
+ outRaster = Raster.createWritableRaster(raster.getSampleModel(),
+ new Point(raster.getSampleModelTranslateX(),
+ raster.getSampleModelTranslateY()));
+ }
+
+ int w = outRaster.getWidth();
+ int h = outRaster.getHeight();
+ int minX = outRaster.getMinX();
+ int minY = outRaster.getMinY();
+
+ Object data = null;
+
+ data = raster.getDataElements(minX, minY, w, h, data);
+ outRaster.setDataElements(minX, minY, w, h, data);
+
+ return outRaster;
+ }
+
+ public Raster getData(Rectangle rect) {
+ int minX = rect.x;
+ int minY = rect.y;
+ int w = rect.width;
+ int h = rect.height;
+
+ SampleModel sm = raster.getSampleModel();
+ SampleModel nsm = sm.createCompatibleSampleModel(w, h);
+ WritableRaster outr = Raster.createWritableRaster(nsm,
+ rect.getLocation());
+ Object data = null;
+
+ data = raster.getDataElements(minX, minY, w, h, data);
+ outr.setDataElements(minX, minY, w, h, data);
+ return outr;
+ }
+
+ public Vector<RenderedImage> getSources() {
+ return null;
+ }
+
+ public String[] getPropertyNames() {
+ if (properties == null) {
+ return null;
+ }
+ Vector<String> v = new Vector<String>();
+ for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) {
+ try {
+ v.add((String) e.nextElement());
+ } catch (ClassCastException ex) {
+ }
+ }
+ int size = v.size();
+ if (size > 0) {
+ String names[] = new String[size];
+ for (int i = 0; i < size; i++) {
+ names[i] = v.elementAt(i);
+ }
+ return names;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the string representation of this BufferedImage object.
+ *
+ * @return the string representation of this BufferedImage object.
+ */
+ @Override
+ public String toString() {
+ return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$
+ ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ public WritableRaster getWritableTile(int tileX, int tileY) {
+ return raster;
+ }
+
+ /**
+ * Gets the WritableRaster of this BufferedImage.
+ *
+ * @return the WritableRaster of this BufferedImage.
+ */
+ public WritableRaster getRaster() {
+ return raster;
+ }
+
+ /**
+ * Gets a WritableRaster object which contains the alpha channel of
+ * BufferedImage object with ColorModel objects that supports
+ * a separate alpha channel such as ComponentColorModel
+ * or DirectColorModel.
+ *
+ * @return the WritableRaster object which contains the alpha
+ * channel of this BufferedImage.
+ */
+ public WritableRaster getAlphaRaster() {
+ return cm.getAlphaRaster(raster);
+ }
+
+ public void removeTileObserver(TileObserver to) {
+ }
+
+ public void addTileObserver(TileObserver to) {
+ }
+
+ public SampleModel getSampleModel() {
+ return raster.getSampleModel();
+ }
+
+ public void setData(Raster r) {
+
+ Rectangle from = r.getBounds();
+ Rectangle to = raster.getBounds();
+ Rectangle intersection = to.intersection(from);
+
+ int minX = intersection.x;
+ int minY = intersection.y;
+ int w = intersection.width;
+ int h = intersection.height;
+
+ Object data = null;
+
+ data = r.getDataElements(minX, minY, w, h, data);
+ raster.setDataElements(minX, minY, w, h, data);
+ }
+
+ public Raster getTile(int tileX, int tileY) {
+ if (tileX == 0 && tileY == 0) {
+ return raster;
+ }
+ // awt.226=Both tileX and tileY are not equal to 0
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
+ }
+
+ public Raster getData() {
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+
+ WritableRaster outr = Raster.createWritableRaster(
+ raster.getSampleModel(),
+ new Point(raster.getSampleModelTranslateX(),
+ raster.getSampleModelTranslateY()));
+
+ Object data = null;
+
+ data = raster.getDataElements(minX, minY, w, h, data);
+ outr.setDataElements(minX, minY, w, h, data);
+
+ return outr;
+ }
+
+ @Override
+ public ImageProducer getSource() {
+ return new BufferedImageSource(this, properties);
+ }
+
+ @Override
+ public int getWidth(ImageObserver observer) {
+ return raster.getWidth();
+ }
+
+ @Override
+ public int getHeight(ImageObserver observer) {
+ return raster.getHeight();
+ }
+
+ public ColorModel getColorModel() {
+ return cm;
+ }
+
+ /**
+ * Gets the rectangular area of this BufferedImage as a subimage.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param w the width of the subimage.
+ * @param h the height of the subimage.
+ *
+ * @return the BufferedImage.
+ */
+ public BufferedImage getSubimage(int x, int y, int w, int h) {
+ WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null);
+ return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties);
+ }
+
+ public Point[] getWritableTileIndices() {
+ Point points[] = new Point[1];
+ points[0] = new Point(0, 0);
+ return points;
+ }
+
+ /**
+ * Creates the Graphics2D object which allows to draw into
+ * this BufferedImage.
+ *
+ * @return the graphics2D object.
+ */
+ public Graphics2D createGraphics() {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ //return ge.createGraphics(this);
+ //???AWT hack, FIXME
+ //return AndroidGraphics2D.getInstance();
+ //throw new RuntimeException("Not implemented!");
+ return null;
+ }
+
+ @Override
+ public Graphics getGraphics() {
+ return createGraphics();
+ }
+
+ /**
+ * Coerces the data to achieve the state which is specified by
+ * the isAlphaPremultiplied variable.
+ *
+ * @param isAlphaPremultiplied the is alpha premultiplied state.
+ */
+ public void coerceData(boolean isAlphaPremultiplied) {
+ if (cm.hasAlpha() &&
+ cm.isAlphaPremultiplied() != isAlphaPremultiplied) {
+ cm = cm.coerceData(raster, isAlphaPremultiplied);
+ }
+ }
+
+ /**
+ * Gets an array of colors in the TYPE_INT_ARGB color model and
+ * default sRGB colorspace of the specified area of this
+ * BufferedImage. The result array is composed by the following
+ * algirithm:
+ * <p>
+ * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]
+ *
+ * @param startX the start X area coordinate.
+ * @param startY the start Y area coordinate.
+ * @param w the width of the area.
+ * @param h the height of the area.
+ * @param rgbArray the result array will be stored to this array.
+ * @param offset the offset of the rgbArray array.
+ * @param scansize the scanline stride for the rgbArray.
+ *
+ * @return an array of colors for the specified area.
+ */
+ public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray,
+ int offset, int scansize) {
+ if (rgbArray == null) {
+ rgbArray = new int[offset + h * scansize];
+ }
+
+ int off = offset;
+ for (int y = startY; y < startY + h; y++, off += scansize) {
+ int i = off;
+ for (int x = startX; x < startX + w; x++, i++) {
+ rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null));
+ }
+ }
+ return rgbArray;
+ }
+
+ /**
+ * Sets RGB values from the specified array to the specified
+ * BufferedImage area. The pixels are in the default RGB color model
+ * (TYPE_INT_ARGB) and default sRGB color space.
+ *
+ * @param startX the start X coordinate.
+ * @param startY the start Y coordinate.
+ * @param w the width of the BufferedImage area.
+ * @param h the height of the BufferedImage area.
+ * @param rgbArray the array of RGB values.
+ * @param offset the offset of the rgbArray array.
+ * @param scansize the scanline stride for the rgbArray.
+ */
+ public void setRGB(int startX, int startY, int w, int h, int[] rgbArray,
+ int offset, int scansize) {
+ int off = offset;
+ for (int y = startY; y < startY + h; y++, off += scansize) {
+ int i = off;
+ for (int x = startX; x < startX + w; x++, i++) {
+ raster.setDataElements(x, y,
+ cm.getDataElements(rgbArray[i], null));
+ }
+ }
+ }
+
+ /**
+ * Sets a the specified RGB value to the specified pixel of
+ * this BufferedImage. The pixel should be in the default
+ * RGB color model (TYPE_INT_ARGB) and default sRGB color space.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param rgb the RGB value to be set.
+ */
+ public synchronized void setRGB(int x, int y, int rgb) {
+ raster.setDataElements(x, y, cm.getDataElements(rgb, null));
+ }
+
+ public boolean isTileWritable(int tileX, int tileY) {
+ if (tileX == 0 && tileY == 0) {
+ return true;
+ }
+ // awt.226=Both tileX and tileY are not equal to 0
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
+ }
+
+ public void releaseWritableTile(int tileX, int tileY) {
+ }
+
+ /**
+ * Gets a color in the TYPE_INT_ARGB color model and default
+ * sRGB colorspace of the specified pixel.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ *
+ * @return the color of the specified pixel in the TYPE_INT_ARGB
+ * color model and default sRGB colorspace.
+ */
+ public int getRGB(int x, int y) {
+ return cm.getRGB(raster.getDataElements(x, y, null));
+ }
+
+ /**
+ * Returnes true if alpha is premultiplied,
+ * false if alpha is not premultiplied or there is no alpha.
+ *
+ * @return true if alpha is premultiplied,
+ * false if alpha is not premultiplied or there is no alpha.
+ */
+ public boolean isAlphaPremultiplied() {
+ return cm.isAlphaPremultiplied();
+ }
+
+ public boolean hasTileWriters() {
+ return true;
+ }
+
+ @Override
+ public void flush() {
+ imageSurf.dispose();
+ }
+
+ public int getWidth() {
+ return raster.getWidth();
+ }
+
+ /**
+ * Gets the image type.
+ *
+ * @return the image type.
+ */
+ public int getType() {
+ return imageType;
+ }
+
+ public int getTileWidth() {
+ return raster.getWidth();
+ }
+
+ public int getTileHeight() {
+ return raster.getHeight();
+ }
+
+ public int getTileGridYOffset() {
+ return raster.getSampleModelTranslateY();
+ }
+
+ public int getTileGridXOffset() {
+ return raster.getSampleModelTranslateX();
+ }
+
+ public int getNumYTiles() {
+ return 1;
+ }
+
+ public int getNumXTiles() {
+ return 1;
+ }
+
+ public int getMinY() {
+ return raster.getMinY();
+ }
+
+ public int getMinX() {
+ return raster.getMinX();
+ }
+
+ public int getMinTileY() {
+ return 0;
+ }
+
+ public int getMinTileX() {
+ return 0;
+ }
+
+ public int getHeight() {
+ return raster.getHeight();
+ }
+
+ /**
+ * Creates the image surface.
+ *
+ * @param type the type
+ *
+ * @return the image surface
+ */
+ private ImageSurface createImageSurface(int type) {
+ return new ImageSurface(getColorModel(), getRaster(), type);
+ }
+
+ /**
+ * Gets the image surface.
+ *
+ * @return the image surface
+ */
+ ImageSurface getImageSurface() {
+ return imageSurf;
+ }
+
+ public int getTransparency() {
+ return cm.getTransparency();
+ }
+}
+
diff --git a/awt/java/awt/image/BufferedImageFilter.java b/awt/java/awt/image/BufferedImageFilter.java
new file mode 100644
index 0000000..44b3c2e
--- /dev/null
+++ b/awt/java/awt/image/BufferedImageFilter.java
@@ -0,0 +1,375 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BufferedImageFilter class provides filtering operations to
+ * the BufferedImage objects using operators which implement
+ * BufferedImageOp interface.
+ */
+public class BufferedImageFilter extends ImageFilter implements Cloneable {
+
+ /** The Constant accessor. */
+ private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance();
+
+ /** The op. */
+ private BufferedImageOp op;
+
+ /** The raster. */
+ private WritableRaster raster;
+
+ /** The i data. */
+ private int iData[];
+
+ /** The b data. */
+ private byte bData[];
+
+ /** The width. */
+ private int width;
+
+ /** The height. */
+ private int height;
+
+ /** The cm. */
+ private ColorModel cm;
+
+ /** The forced rgb. */
+ private boolean forcedRGB = false;
+
+ /** The transfer type. */
+ private int transferType = DataBuffer.TYPE_UNDEFINED;
+
+ /**
+ * Instantiates a new BufferedImageFilter with the specified
+ * BufferedImageOp operator.
+ *
+ * @param op the specified BufferedImageOp operator.
+ *
+ * @throws NullPointerException if BufferedImageOp is null.
+ */
+ public BufferedImageFilter(BufferedImageOp op) {
+ if (op == null) {
+ throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$
+ }
+ this.op = op;
+ }
+
+ /**
+ * Gets the BufferedImageOp operator associated with this
+ * BufferedImageFilter object.
+ *
+ * @return the BufferedImageOp associated with this
+ * BufferedImageFilter object.
+ */
+ public BufferedImageOp getBufferedImageOp() {
+ return op;
+ }
+
+ @Override
+ public void setDimensions(int width, int height) {
+ this.width = width;
+ this.height = height;
+ // Stop image consuming if no pixels expected.
+ if (width <= 0 || height <= 0) {
+ consumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ reset();
+ }
+ }
+
+ @Override
+ public void setColorModel(ColorModel model) {
+ if (this.cm != null && this.cm != model && raster != null) {
+ forceRGB();
+ } else {
+ this.cm = model;
+ }
+ }
+
+ @Override
+ public void setPixels(
+ int x, int y, int
+ w, int h,
+ ColorModel model, byte[] pixels,
+ int off, int scansize
+ ) {
+ setPixels(x, y, w, h, model, pixels, off, scansize, true);
+ }
+
+ @Override
+ public void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model, int[] pixels,
+ int off, int scansize
+ ) {
+ setPixels(x, y, w, h, model, pixels, off, scansize, false);
+ }
+
+ @Override
+ public void imageComplete(int status) {
+ if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) {
+ BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null);
+ bim = op.filter(bim, null);
+ DataBuffer dstDb = bim.getRaster().getDataBuffer();
+ ColorModel dstCm = bim.getColorModel();
+ int dstW = bim.getWidth();
+ int dstH = bim.getHeight();
+
+ consumer.setDimensions(dstW, dstH);
+
+ if (dstDb.getDataType() == DataBuffer.TYPE_INT) {
+ consumer.setColorModel(dstCm);
+ consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW);
+ } else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) {
+ consumer.setColorModel(dstCm);
+ consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW);
+ } else {
+ int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW);
+ dstCm = ColorModel.getRGBdefault();
+ consumer.setColorModel(dstCm);
+ consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW);
+ }
+ } else if (status == IMAGEERROR || status == IMAGEABORTED) {
+ reset();
+ }
+
+ consumer.imageComplete(status);
+ }
+
+ /**
+ * Sets the pixels.
+ *
+ * @param x the x
+ * @param y the y
+ * @param w the w
+ * @param h the h
+ * @param model the model
+ * @param pixels the pixels
+ * @param off the off
+ * @param scansize the scansize
+ * @param isByteData the is byte data
+ */
+ private void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model, Object pixels,
+ int off, int scansize, boolean isByteData
+ ) {
+ // Check bounds
+ // Need to copy only the pixels that will fit into the destination area
+ if (x < 0) {
+ w -= x;
+ off += x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h -= y;
+ off += y * scansize;
+ y = 0;
+ }
+
+ if (x + w > width) {
+ w = width - x;
+ }
+
+ if (y + h > height) {
+ h = height - y;
+ }
+
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ // Check model
+ if (this.cm == null) {
+ setColorModel(model);
+ } else if (model == null) {
+ model = this.cm;
+ } else if (!model.equals(this.cm)) {
+ forceRGB();
+ }
+
+ boolean canArraycopy;
+ // Process pixels
+ switch(transferType) {
+ case DataBuffer.TYPE_UNDEFINED: {
+ if (isByteData) {
+ transferType = DataBuffer.TYPE_BYTE;
+ createRaster(transferType);
+ //bData = new byte[width*height];
+ canArraycopy = !forcedRGB;
+ break;
+ }
+ transferType = DataBuffer.TYPE_INT;
+ createRaster(transferType);
+ //iData = new int[width*height];
+ canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault());
+ break;
+ } // And proceed to copy the pixels
+ case DataBuffer.TYPE_INT: {
+ if (isByteData) { // There are int data already but the new data are bytes
+ forceRGB();
+ canArraycopy = false;
+ break;
+ } else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) {
+ canArraycopy = true;
+ break;
+ } // Else fallback to the RGB conversion
+ }
+ case DataBuffer.TYPE_BYTE: {
+ if (isByteData && !forcedRGB) {
+ canArraycopy = true;
+ break;
+ }
+
+ // RGB conversion
+ canArraycopy = false;
+ break;
+ } default: {
+ throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$
+ }
+ }
+
+ off += x;
+ int maxOffset = off + h * scansize;
+ int dstOffset = x + y * width;
+
+ if (canArraycopy) {
+ Object dstArray = isByteData ? (Object) bData : (Object) iData;
+ for (; off < maxOffset; off += scansize, dstOffset += width) {
+ System.arraycopy(pixels, off, dstArray, dstOffset, w);
+ }
+ } else {
+ // RGB conversion
+ for (; off < maxOffset; off += scansize, dstOffset += width) {
+ int srcPos = off;
+ int dstPos = dstOffset;
+ int maxDstPos = dstOffset + w;
+ for (; dstPos < maxDstPos; dstPos++, srcPos++) {
+ iData[dstPos] = model.getRGB(
+ isByteData ?
+ ((byte[])pixels)[srcPos] :
+ ((int[])pixels)[srcPos]
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Force rgb.
+ */
+ private void forceRGB() {
+ if (!forcedRGB) {
+ forcedRGB = true;
+ int size = width*height;
+ int rgbData[] = new int[size];
+
+ if (bData != null) {
+ for (int i=0; i<size; i++) {
+ rgbData[i] = cm.getRGB(bData[i]);
+ }
+ } else if (iData != null) {
+ for (int i=0; i<size; i++) {
+ rgbData[i] = cm.getRGB(iData[i]);
+ }
+ }
+
+ cm = ColorModel.getRGBdefault();
+ DataBufferInt db = new DataBufferInt(rgbData, size);
+ int masks[] = new int[] {0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000};
+ raster = Raster.createPackedRaster(db, width, height, width, masks, null);
+ iData = accessor.getDataInt(db);
+ bData = null;
+ transferType = DataBuffer.TYPE_INT;
+ }
+ }
+
+ /**
+ * Reset.
+ */
+ private void reset() {
+ width = 0;
+ height = 0;
+ forcedRGB = false;
+ cm = null;
+ iData = null;
+ bData = null;
+ transferType = DataBuffer.TYPE_UNDEFINED;
+ raster = null;
+ }
+
+ /**
+ * Creates the raster.
+ *
+ * @param dataType the data type
+ */
+ private void createRaster(int dataType) {
+ boolean createdValidBuffer = false;
+ try{
+ raster = cm.createCompatibleWritableRaster(width, height);
+ int rasterType = raster.getDataBuffer().getDataType();
+ if (rasterType == dataType) {
+ switch (rasterType) {
+ case DataBuffer.TYPE_INT: {
+ iData = accessor.getDataInt(raster.getDataBuffer());
+ if (iData != null) {
+ createdValidBuffer = true;
+ }
+ break;
+ }
+ case DataBuffer.TYPE_BYTE: {
+ bData = accessor.getDataByte(raster.getDataBuffer());
+ if (bData != null) {
+ createdValidBuffer = true;
+ }
+ break;
+ }
+ default:
+ createdValidBuffer = false;
+ }
+
+ if(cm == ColorModel.getRGBdefault()){
+ forcedRGB = true;
+ }
+ } else {
+ createdValidBuffer = false;
+ }
+ } catch(Exception e) {
+ createdValidBuffer = false;
+ }
+
+ if (createdValidBuffer == false) {
+ cm = ColorModel.getRGBdefault();
+ raster = cm.createCompatibleWritableRaster(width, height);
+ iData = accessor.getDataInt(raster.getDataBuffer());
+ bData = null;
+ forcedRGB = true;
+ }
+ }
+}
diff --git a/awt/java/awt/image/BufferedImageOp.java b/awt/java/awt/image/BufferedImageOp.java
new file mode 100644
index 0000000..85b9f4e
--- /dev/null
+++ b/awt/java/awt/image/BufferedImageOp.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The BufferedImageOp interface provides methods for performing transformations
+ * from source data to destination data for BufferedImage objects. An object
+ * implementing this interface can be passed into a BufferedImageFilter
+ * to operate on a BufferedImage.
+ */
+public interface BufferedImageOp {
+
+ /**
+ * Creates a destination image with the specified BufferedImage and
+ * ColorModel; this destination image is empty and has the correct size
+ * and number of bands.
+ *
+ * @param src the source BufferedImage.
+ * @param destCM the destination ColorModel.
+ *
+ * @return the BufferedImage.
+ */
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM);
+
+ /**
+ * Performs a filter operation on the source BufferedImage and stores
+ * the resulting BufferedImage to the destination BufferedImage. If
+ * the destination BufferedImage is null, a BufferedImage with an
+ * appropriate ColorModel is created.
+ *
+ * @param src the source BufferedImage.
+ * @param dest the destination BufferedImage, where the result is stored.
+ *
+ * @return the filtered BufferedImage.
+ */
+ public BufferedImage filter(BufferedImage src, BufferedImage dest);
+
+ /**
+ * Gets the bounds of filtered image.
+ *
+ * @param src the source BufferedImage to be filtered.
+ *
+ * @return the rectangle bounds of filtered image.
+ */
+ public Rectangle2D getBounds2D(BufferedImage src);
+
+ /**
+ * Gets the point of the destination image which corresponds
+ * to the specified point in the source image.
+ *
+ * @param srcPt the point of the source image.
+ * @param dstPt the point where the result will be stored.
+ *
+ * @return the destination point.
+ */
+ public Point2D getPoint2D(Point2D srcPt, Point2D dstPt);
+
+ /**
+ * Gets the RenderingHints of the BufferedImageOp.
+ *
+ * @return the RenderingHints of the BufferedImageOp.
+ */
+ public RenderingHints getRenderingHints();
+}
diff --git a/awt/java/awt/image/ByteLookupTable.java b/awt/java/awt/image/ByteLookupTable.java
new file mode 100644
index 0000000..043b533
--- /dev/null
+++ b/awt/java/awt/image/ByteLookupTable.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ByteLookupTable class provides functionality for lookup operations,
+ * and is defined by an input byte array for bands or components of
+ * image and an offset value.
+ * The offset value will be subtracted from the input values before
+ * indexing the input arrays. The output of a lookup operation is
+ * represented as an array of unsigned bytes.
+ */
+public class ByteLookupTable extends LookupTable {
+
+ /** The data. */
+ private byte data[][];
+
+ /**
+ * Instantiates a new ByteLookupTable with the specified offset value
+ * and the specified byte array which represents the lookup table for
+ * all bands.
+ *
+ * @param offset the offset value.
+ * @param data the data array of bytes.
+ */
+ public ByteLookupTable(int offset, byte[] data) {
+ super(offset, 1);
+ if (data.length < 1)
+ throw new IllegalArgumentException("Length of data should not be less then one");
+ this.data = new byte[1][data.length];
+ // The data array stored as a reference
+ this.data[0] = data;
+ }
+
+ /**
+ * Instantiates a new ByteLookupTable with the specified offset value
+ * and the specified byte array of arrays which represents the lookup table
+ * for each band.
+ *
+ * @param offset the offset value.
+ * @param data the data array of bytes array for each band.
+ */
+ public ByteLookupTable(int offset, byte[][] data) {
+ super(offset, data.length);
+ this.data = new byte[data.length][data[0].length];
+ for (int i = 0; i < data.length; i++) {
+ // The data array for each band stored as a reference
+ this.data[i] = data[i];
+ }
+ }
+
+ /**
+ * Gets the lookup table of this ByteLookupTable object. If
+ * this ByteLookupTable object has one byte array for all bands,
+ * the returned array length is one.
+ *
+ * @return the lookup table of this ByteLookupTable object.
+ */
+ public final byte[][] getTable() {
+ // Returns data by reference
+ return data;
+ }
+
+ @Override
+ public int[] lookupPixel(int[] src, int[] dst) {
+ if (dst == null) {
+ dst = new int[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+
+ /**
+ * Returns a byte array which contains samples of the specified
+ * pixel which is translated with the lookup table of this
+ * ByteLookupTable object. The resulted array is stored to
+ * the dst array.
+ *
+ * @param src the source array.
+ * @param dst the destination array where the result can be stored.
+ *
+ * @return the byte array of translated samples of a pixel.
+ */
+ public byte[] lookupPixel(byte[] src, byte[] dst) {
+ if (dst == null) {
+ dst = new byte[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+}
diff --git a/awt/java/awt/image/ColorConvertOp.java b/awt/java/awt/image/ColorConvertOp.java
new file mode 100644
index 0000000..6d503d7
--- /dev/null
+++ b/awt/java/awt/image/ColorConvertOp.java
@@ -0,0 +1,711 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.color.ColorConverter;
+import org.apache.harmony.awt.gl.color.ColorScaler;
+import org.apache.harmony.awt.gl.color.ICC_Transform;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ColorConvertOp class converts the pixels of the data in the
+ * source image with the specified ColorSpace objects or an array
+ * of ICC_Profile objects. The result pixels are scaled to the precision
+ * of the destination image.
+ */
+public class ColorConvertOp implements BufferedImageOp, RasterOp {
+ // Unused but required by interfaces
+ /** The rendering hints. */
+ RenderingHints renderingHints;
+
+ // Sequence consisting of ColorSpace and ICC_Profile elements
+ /** The conversion sequence. */
+ Object conversionSequence[] = new ICC_Profile[0]; // To eliminate checks for null
+
+ // Not null if ColorConvertOp is constructed from the array of ICC profiles
+ /** The mid profiles. */
+ private ICC_Profile midProfiles[];
+
+ /** The cc. */
+ private final ColorConverter cc = new ColorConverter();
+
+ /** The t creator. */
+ private final ICC_TransfomCreator tCreator = new ICC_TransfomCreator();
+
+ /** The is icc. */
+ private boolean isICC = true;
+
+
+ // Cached ICC_Transform
+ /**
+ * The Class ICC_TransfomCreator.
+ */
+ private class ICC_TransfomCreator {
+
+ /** The transform. */
+ private ICC_Transform transform;
+
+ /** The max components. */
+ private int maxComponents;
+
+ /**
+ * For the full ICC case.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param convSeq the conv seq
+ *
+ * @return the transform
+ */
+ public ICC_Transform getTransform(ICC_Profile src, ICC_Profile dst, ICC_Profile convSeq[]) {
+ if (transform != null &&
+ src == transform.getSrc() &&
+ dst == transform.getDst()) {
+ return transform;
+ }
+
+ int length = convSeq.length;
+ int srcFlg = 0, dstFlg = 0;
+
+ if (length == 0 || src != convSeq[0]) {
+ if (src != null) {
+ srcFlg = 1; // need src profile
+ }
+ }
+ if (length == 0 || dst != convSeq[length-1]) {
+ if (dst != null) {
+ dstFlg = 1; // need dst profile
+ }
+ }
+
+ ICC_Profile profiles[];
+ int nProfiles = length + srcFlg + dstFlg;
+ if (nProfiles == length) {
+ profiles = convSeq;
+ } else {
+ profiles = new ICC_Profile[nProfiles];
+ int pos = 0;
+ if (srcFlg != 0) {
+ profiles[pos++] = src;
+ }
+ for (int i=0; i<length; i++) {
+ profiles[pos++] = convSeq[i];
+ }
+ if (dstFlg != 0) {
+ profiles[pos++] = dst;
+ }
+ }
+
+ return transform = new ICC_Transform(profiles);
+ }
+
+ /**
+ * Used only when there are non-ICC color spaces.
+ * Returns sequence of non-ICC color spaces and ICC transforms
+ * made from src, dst and conversionSequence.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the sequence
+ */
+ public Object[] getSequence(Object src, Object dst) {
+ ArrayList<Object> profiles = new ArrayList<Object>(10);
+ ArrayList<Object> sequence = new ArrayList<Object>(10);
+
+ // We need this profile anyway
+ ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
+
+ Object conversionFirst = null, conversionLast = null;
+ int conversionLength = conversionSequence.length;
+ if (conversionLength > 0) {
+ conversionFirst = conversionSequence[0];
+ conversionLast = conversionSequence[conversionLength-1];
+ }
+
+ boolean iccSequenceStarted = false;
+
+ if (src != conversionFirst && src != null) {
+ if (src instanceof ICC_Profile) {
+ profiles.add(src);
+ iccSequenceStarted = true;
+ } else {
+ profiles.add(xyzProfile);
+ sequence.add(src); // Add non-ICC color space to the sequence
+ }
+ } else {
+ profiles.add(xyzProfile);
+ }
+
+ for (int i=0; i<conversionLength; i++) {
+ if (conversionSequence[i] instanceof ICC_Profile) {
+ profiles.add(conversionSequence[i]);
+ iccSequenceStarted = true;
+ } else if (iccSequenceStarted) {
+ profiles.add(xyzProfile);
+
+ // Eliminate same profiles if there are any
+ // (e.g. xyzProfile may occur several times)
+ Object prev = profiles.get(0);
+ for (int k=1; k<profiles.size(); k++) {
+ if (prev == profiles.get(k)) {
+ k--;
+ profiles.remove(k);
+ }
+ prev = profiles.get(k);
+ }
+
+ // If only one profile left we skip the transform -
+ // it can be only CIEXYZ
+ if (profiles.size() > 1) {
+ sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0])));
+
+ // Add non-ICC color space to the sequence
+ sequence.add(conversionSequence[i]);
+ }
+
+ profiles.clear();
+ profiles.add(xyzProfile);
+ iccSequenceStarted = false; // Sequence of ICC profiles is processed
+ } else { // Add non-ICC color space to the sequence
+ sequence.add(conversionSequence[i]);
+ }
+ }
+
+ if (dst != conversionLast && dst != null) { // Add last profile if needed
+ if (dst instanceof ICC_Profile) {
+ profiles.add(dst);
+ iccSequenceStarted = true;
+ } else if (iccSequenceStarted) {
+ profiles.add(xyzProfile);
+ } else {
+ sequence.add(dst); // Add last non-ICC color space to the sequence
+ }
+ }
+
+ if (iccSequenceStarted) { // Make last transform if needed
+ sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0])));
+ if (dst != null && !(dst instanceof ICC_Profile)) {
+ sequence.add(dst); // Add last non-ICC color space to the
+ // sequence
+ }
+ }
+
+ // Calculate max number of components
+ // This number will be used for memory allocation
+ maxComponents = 0;
+ Object o;
+ for (int i=0, size = sequence.size(); i<size; i++) {
+ o = sequence.get(i);
+ if (o instanceof ICC_Transform) {
+ ICC_Transform t = (ICC_Transform) o;
+ maxComponents =
+ (maxComponents > t.getNumInputChannels() + 1) ?
+ maxComponents :
+ t.getNumInputChannels() + 1;
+ maxComponents =
+ (maxComponents > t.getNumOutputChannels() + 1) ?
+ maxComponents :
+ t.getNumOutputChannels() + 1;
+ } else {
+ ColorSpace cs = (ColorSpace) o;
+ maxComponents =
+ (maxComponents > cs.getNumComponents() + 1) ?
+ maxComponents :
+ cs.getNumComponents() + 1;
+ }
+ }
+
+ return sequence.toArray();
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object using two specified
+ * ColorSpace objects.
+ *
+ * @param srcCS the source ColorSpace.
+ * @param dstCS the destination ColorSpace.
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) {
+ if (srcCS == null || dstCS == null) {
+ throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$
+ }
+
+ renderingHints = hints;
+
+ boolean srcICC = srcCS instanceof ICC_ColorSpace;
+ boolean dstICC = dstCS instanceof ICC_ColorSpace;
+
+ if (srcICC && dstICC) {
+ conversionSequence = new ICC_Profile[2];
+ } else {
+ conversionSequence = new Object[2];
+ isICC = false;
+ }
+
+ if (srcICC) {
+ conversionSequence[0] = ((ICC_ColorSpace) srcCS).getProfile();
+ } else {
+ conversionSequence[0] = srcCS;
+ }
+
+ if (dstICC) {
+ conversionSequence[1] = ((ICC_ColorSpace) dstCS).getProfile();
+ } else {
+ conversionSequence[1] = dstCS;
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object from the specified
+ * ICC_Profile objects.
+ *
+ * @param profiles the array of ICC_Profile objects.
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) {
+ if (profiles == null) {
+ throw new NullPointerException(Messages.getString("awt.25C")); //$NON-NLS-1$
+ }
+
+ renderingHints = hints;
+
+ // This array is not used in the program logic, so don't need to copy it
+ // Store it only to return back
+ midProfiles = profiles;
+
+ conversionSequence = new ICC_Profile[midProfiles.length];
+
+ // Add profiles to the conversion sequence
+ for (int i=0, length=midProfiles.length; i<length; i++) {
+ conversionSequence[i] = midProfiles[i];
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object using the specified
+ * ColorSpace object.
+ *
+ * @param cs the destination ColorSpace or an intermediate ColorSpace.
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(ColorSpace cs, RenderingHints hints) {
+ if (cs == null) {
+ throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$
+ }
+
+ renderingHints = hints;
+
+ if (cs instanceof ICC_ColorSpace) {
+ conversionSequence = new ICC_Profile[1];
+ conversionSequence[0] = ((ICC_ColorSpace) cs).getProfile();
+ } else {
+ conversionSequence = new Object[1];
+ conversionSequence[0] = cs;
+ isICC = false;
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object which converts from
+ * a source color space to a destination color space.
+ *
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(RenderingHints hints) {
+ renderingHints = hints;
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (conversionSequence.length < 2) {
+ throw new IllegalArgumentException(Messages.getString("awt.25D")); //$NON-NLS-1$
+ }
+
+ ICC_Profile srcPf = null, dstPf = null; // unused if isICC is false
+ int nSrcColorComps, nDstColorComps;
+ Object first = conversionSequence[0];
+ Object last = conversionSequence[conversionSequence.length - 1];
+
+ // Get the number of input/output color components
+ if (isICC) {
+ srcPf = (ICC_Profile) first;
+ dstPf = (ICC_Profile) last;
+ nSrcColorComps = srcPf.getNumComponents();
+ nDstColorComps = dstPf.getNumComponents();
+ } else {
+ if (first instanceof ICC_Profile) {
+ srcPf = (ICC_Profile) first;
+ nSrcColorComps = srcPf.getNumComponents();
+ } else {
+ nSrcColorComps = ((ColorSpace) first).getNumComponents();
+ }
+
+ if (last instanceof ICC_Profile) {
+ dstPf = (ICC_Profile) last;
+ nDstColorComps = dstPf.getNumComponents();
+ } else {
+ nDstColorComps = ((ColorSpace) last).getNumComponents();
+ }
+ }
+
+ // Check that source and destination rasters are compatible with
+ // transforms and with each other
+ if (src.getNumBands() != nSrcColorComps) {
+ // awt.25E=Incorrect number of source raster bands. Should be equal
+ // to the number of color components of source colorspace.
+ throw new IllegalArgumentException(Messages.getString("awt.25E")); //$NON-NLS-1$
+ }
+
+ if (dst != null) { // Check destination raster
+ if (dst.getNumBands() !=
+ nDstColorComps) {
+ // awt.25F=Incorrect number of destination raster bands. Should
+ // be equal to the number of color components of destination
+ // colorspace.
+ throw new IllegalArgumentException(Messages.getString("awt.25F")); //$NON-NLS-1$
+ }
+
+ if (src.getWidth() != dst.getWidth() ||
+ src.getHeight() != dst.getHeight()) {
+ throw new IllegalArgumentException(Messages.getString("awt.260")); //$NON-NLS-1$
+ }
+
+ } else {
+ dst = createCompatibleDestRaster(src);
+ }
+
+ if (isICC) {
+ // Create transform
+ ICC_Transform t = tCreator.getTransform(srcPf, dstPf,
+ (ICC_Profile[])conversionSequence);
+ cc.translateColor(t, src, dst);
+ } else {
+ Object[] sequence = tCreator.getSequence(null, null);
+
+ // Get data from the source raster
+ ColorScaler scaler = new ColorScaler();
+ scaler.loadScalingData(src, null);
+ float tmpData[][] = scaler.scaleNormalize(src);
+
+ // Get source and destination color spaces
+ ColorSpace srcCS = (srcPf == null) ?
+ (ColorSpace) first:
+ new ICC_ColorSpace(srcPf);
+ ColorSpace dstCS = (dstPf == null) ?
+ (ColorSpace) last:
+ new ICC_ColorSpace(dstPf);
+
+ applySequence(sequence, tmpData, srcCS, dstCS);
+
+ scaler.loadScalingData(dst, null);
+ scaler.unscaleNormalized(dst, tmpData);
+ }
+
+ return dst;
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+ // If destination color model is passed only one line needed
+ if (destCM != null) {
+ return new BufferedImage(destCM,
+ destCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()),
+ destCM.isAlphaPremultiplied(),
+ null);
+ }
+
+ int nSpaces = conversionSequence.length;
+
+ if (nSpaces < 1) {
+ throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$
+ }
+
+ // Get destination color space
+ Object destination = conversionSequence[nSpaces-1];
+ ColorSpace dstCS =
+ (destination instanceof ColorSpace) ?
+ (ColorSpace) destination :
+ new ICC_ColorSpace((ICC_Profile) destination);
+
+ ColorModel srcCM = src.getColorModel();
+ ColorModel dstCM = new ComponentColorModel(dstCS,
+ srcCM.hasAlpha(),
+ srcCM.isAlphaPremultiplied(),
+ srcCM.getTransparency(),
+ srcCM.getTransferType());
+
+ return new BufferedImage(dstCM,
+ destCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()),
+ destCM.isAlphaPremultiplied(),
+ null);
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ if (dst == null && conversionSequence.length < 1) {
+ throw new IllegalArgumentException(Messages.getString("awt.262")); //$NON-NLS-1$
+ }
+
+ ColorModel srcCM = src.getColorModel();
+ // First handle index color model
+ if (srcCM instanceof IndexColorModel) {
+ src = ((IndexColorModel) srcCM).convertToIntDiscrete(src.getRaster(), false);
+ }
+ ColorSpace srcCS = srcCM.getColorSpace();
+
+ BufferedImage res;
+ boolean isDstIndex = false;
+ if (dst != null) {
+
+ if (src.getWidth() != dst.getWidth() ||
+ src.getHeight() != dst.getHeight()) {
+ throw new IllegalArgumentException(Messages.getString("awt.263")); //$NON-NLS-1$
+ }
+
+ if (dst.getColorModel() instanceof IndexColorModel) {
+ isDstIndex = true;
+ res = createCompatibleDestImage(src, null);
+ } else {
+ res = dst;
+ }
+ } else {
+ res = createCompatibleDestImage(src, null);
+ }
+ ColorModel dstCM = res.getColorModel();
+ ColorSpace dstCS = dstCM.getColorSpace();
+
+ ICC_Profile srcPf = null, dstPf = null;
+ if (srcCS instanceof ICC_ColorSpace) {
+ srcPf = ((ICC_ColorSpace)srcCS).getProfile();
+ }
+ if (dstCS instanceof ICC_ColorSpace) {
+ dstPf = ((ICC_ColorSpace)dstCS).getProfile();
+ }
+
+ boolean isFullICC = isICC && srcPf != null && dstPf != null;
+
+ if (isFullICC) {
+ ICC_Transform t =
+ tCreator.getTransform(srcPf, dstPf, (ICC_Profile[]) conversionSequence);
+ cc.translateColor(t, src, res);
+ } else { // Perform non-ICC transform
+ Object sequence[] = tCreator.getSequence(
+ srcPf == null ? (Object) srcCS : srcPf,
+ dstPf == null ? (Object) dstCS : dstPf);
+
+ int srcW = src.getWidth();
+ int srcH = src.getHeight();
+ int numPixels = srcW*srcH;
+
+ // Load all pixel data into array tmpData
+ float tmpData[][] =
+ new float[numPixels][tCreator.maxComponents];
+ for (int row=0, dataPos=0; row<srcW; row++) {
+ for (int col=0; col<srcH; col++) {
+ tmpData[dataPos] =
+ srcCM.getNormalizedComponents(
+ src.getRaster().getDataElements(row, col, null),
+ tmpData[dataPos], 0);
+ dataPos++;
+ }
+ }
+
+ // Copy alpha channel if needed
+ float alpha[] = null;
+ int alphaIdx = srcCM.numComponents - 1;
+ if (srcCM.hasAlpha() && dstCM.hasAlpha()) {
+ alpha = new float[numPixels];
+ for (int i=0; i<numPixels; i++) {
+ alpha[i] = tmpData[i][alphaIdx];
+ }
+ }
+
+ // Translate colors
+ applySequence(sequence, tmpData, srcCS, dstCS);
+
+ // Copy alpha if needed
+ if (dstCM.hasAlpha()) {
+ alphaIdx = dstCM.numComponents - 1;
+ if (alpha != null) {
+ for (int i=0; i<numPixels; i++) {
+ tmpData[i][alphaIdx] = alpha[i];
+ }
+ } else {
+ for (int i=0; i<numPixels; i++) {
+ tmpData[i][alphaIdx] = 1f;
+ }
+ }
+ }
+
+ // Store data back to the image
+ for (int row=0, dataPos=0; row<srcW; row++) {
+ for (int col=0; col<srcH; col++) {
+ res.getRaster().setDataElements(row, col,
+ dstCM.getDataElements(tmpData[dataPos++], 0 , null));
+ }
+ }
+ }
+
+ if (isDstIndex) { // Convert image into indexed color
+ Graphics2D g2d = dst.createGraphics();
+ g2d.drawImage(res, 0, 0, null);
+ g2d.dispose();
+ return dst;
+ }
+
+ return res;
+ }
+
+ /**
+ * Apply sequence.
+ *
+ * @param sequence the sequence
+ * @param tmpData the tmp data
+ * @param srcCS the src cs
+ * @param dstCS the dst cs
+ */
+ private void applySequence(
+ Object sequence[],
+ float tmpData[][],
+ ColorSpace srcCS,
+ ColorSpace dstCS
+ ) {
+ ColorSpace xyzCS = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
+
+ int numPixels = tmpData.length;
+
+ // First transform...
+ if (sequence[0] instanceof ICC_Transform) { // ICC
+ ICC_Transform t = (ICC_Transform)sequence[0];
+ cc.translateColor(t, tmpData, srcCS, xyzCS, numPixels);
+ } else { // non ICC
+ for (int k=0; k<numPixels; k++) {
+ tmpData[k] = srcCS.toCIEXYZ(tmpData[k]);
+ }
+ cc.loadScalingData(xyzCS); // prepare for scaling XYZ
+ }
+
+ for (Object element : sequence) {
+ if (element instanceof ICC_Transform) {
+ ICC_Transform t = (ICC_Transform)element;
+ cc.translateColor(t, tmpData, null, null, numPixels);
+ } else {
+ ColorSpace cs = (ColorSpace) element;
+ for (int k=0; k<numPixels; k++) {
+ tmpData[k] = cs.fromCIEXYZ(tmpData[k]);
+ tmpData[k] = cs.toCIEXYZ(tmpData[k]);
+ }
+ }
+ }
+
+ // Last transform...
+ if (sequence[sequence.length-1] instanceof ICC_Transform) { // ICC
+ ICC_Transform t = (ICC_Transform)sequence[sequence.length-1];
+ cc.translateColor(t, tmpData, xyzCS, dstCS, numPixels);
+ } else { // non ICC
+ for (int k=0; k<numPixels; k++) {
+ tmpData[k] = dstCS.fromCIEXYZ(tmpData[k]);
+ }
+ }
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt != null) {
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+ return new Point2D.Float((float) srcPt.getX(), (float) srcPt.getY());
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ int nComps = 0;
+ int nSpaces = conversionSequence.length;
+
+ if (nSpaces < 2) {
+ throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$
+ }
+
+ Object lastCS = conversionSequence[nSpaces-1];
+ if (lastCS instanceof ColorSpace) {
+ nComps = ((ColorSpace) lastCS).getNumComponents();
+ } else {
+ nComps = ((ICC_Profile) lastCS).getNumComponents();
+ }
+
+ // Calculate correct data type
+ int dstDataType = src.getDataBuffer().getDataType();
+ if (dstDataType != DataBuffer.TYPE_BYTE &&
+ dstDataType != DataBuffer.TYPE_SHORT) {
+ dstDataType = DataBuffer.TYPE_SHORT;
+ }
+
+ return Raster.createInterleavedRaster(
+ dstDataType,
+ src.getWidth(),
+ src.getHeight(),
+ nComps,
+ new Point(src.getMinX(), src.getMinY())
+ );
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return src.getRaster().getBounds();
+ }
+
+ /**
+ * Gets an array of ICC_Profiles objects which constructs
+ * this ColorConvertOp object or returns null if this ColorConvertOp
+ * is not constructed from array of ICC_Profiles.
+ *
+ * @return an array of ICC_Profiles objects which constructs
+ * this ColorConvertOp object or returns null if this ColorConvertOp
+ * is not constructed from array of ICC_Profiles.
+ */
+ public final ICC_Profile[] getICC_Profiles() {
+ if (midProfiles != null) {
+ return midProfiles;
+ }
+ return null;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return renderingHints;
+ }
+}
diff --git a/awt/java/awt/image/ColorModel.java b/awt/java/awt/image/ColorModel.java
new file mode 100644
index 0000000..945c087
--- /dev/null
+++ b/awt/java/awt/image/ColorModel.java
@@ -0,0 +1,911 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class ColorModel.
+ */
+public abstract class ColorModel implements Transparency {
+
+ /** The pixel_bits. */
+ protected int pixel_bits; // Pixel length in bits
+
+ /** The transfer type. */
+ protected int transferType;
+
+ /** The cs. */
+ ColorSpace cs;
+
+ /** The has alpha. */
+ boolean hasAlpha;
+
+ /** The is alpha premultiplied. */
+ boolean isAlphaPremultiplied;
+
+ /** The transparency. */
+ int transparency;
+
+ /** The num color components. */
+ int numColorComponents;
+
+ /** The num components. */
+ int numComponents;
+
+ /** The bits. */
+ int[] bits; // Array of components masks
+
+ /** The max values. */
+ int[] maxValues = null; // Max values that may be represent by color
+ // components
+
+ /** The max bit length. */
+ int maxBitLength; // Max length color components in bits
+
+ /** The RG bdefault. */
+ private static ColorModel RGBdefault;
+
+ /**
+ * Instantiates a new color model with the specified values.
+ *
+ * @param pixel_bits the pixel length in bits
+ * @param bits the array of component masks
+ * @param cspace the colorspace
+ * @param hasAlpha whether the color model has alpha
+ * @param isAlphaPremultiplied whether the alpha is premultiplied
+ * @param transparency the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ */
+ protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
+ boolean hasAlpha, boolean isAlphaPremultiplied, int transparency,
+ int transferType) {
+
+ if (pixel_bits < 1) {
+ // awt.26B=The number of bits in the pixel values is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.26B")); //$NON-NLS-1$
+ }
+
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ int sum = 0;
+ for (int element : bits) {
+ if (element < 0) {
+ // awt.26D=The elements in bits is less than 0
+ throw new IllegalArgumentException(Messages.getString("awt.26D")); //$NON-NLS-1$
+ }
+ sum += element;
+ }
+
+ if (sum < 1) {
+ // awt.26E=The sum of the number of bits in bits is less than 1
+ throw new NullPointerException(Messages.getString("awt.26E")); //$NON-NLS-1$
+ }
+
+ if (cspace == null) {
+ // awt.26F=The cspace is null
+ throw new IllegalArgumentException(Messages.getString("awt.26F")); //$NON-NLS-1$
+ }
+
+ if (transparency < Transparency.OPAQUE ||
+ transparency > Transparency.TRANSLUCENT) {
+ // awt.270=The transparency is not a valid value
+ throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$
+ }
+
+ this.pixel_bits = pixel_bits;
+ this.bits = bits.clone();
+
+ maxValues = new int[bits.length];
+ maxBitLength = 0;
+ for (int i = 0; i < maxValues.length; i++) {
+ maxValues[i] = (1 << bits[i]) - 1;
+ if (bits[i] > maxBitLength) {
+ maxBitLength = bits[i];
+ }
+ }
+
+ cs = cspace;
+ this.hasAlpha = hasAlpha;
+ this.isAlphaPremultiplied = isAlphaPremultiplied;
+ numColorComponents = cs.getNumComponents();
+
+ if (hasAlpha) {
+ numComponents = numColorComponents + 1;
+ } else {
+ numComponents = numColorComponents;
+ }
+
+ this.transparency = transparency;
+ this.transferType = transferType;
+
+ }
+
+ /**
+ * Instantiates a new color model with the specified pixel bit depth.
+ * The transferType is chosen based on the pixel bits, and the other
+ * data fields are given default values.
+ *
+ * @param bits the array of component masks
+ */
+ public ColorModel(int bits) {
+
+ if (bits < 1) {
+ // awt.271=The number of bits in bits is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.271")); //$NON-NLS-1$
+ }
+
+ pixel_bits = bits;
+ transferType = getTransferType(bits);
+ cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ hasAlpha = true;
+ isAlphaPremultiplied = false;
+ transparency = Transparency.TRANSLUCENT;
+
+ numColorComponents = 3;
+ numComponents = 4;
+
+ this.bits = null;
+ }
+
+ /**
+ * Gets the data elements from the specified component array, transforming
+ * them according to rules of the color model.
+ *
+ * @param components the components
+ * @param offset the offset in the normComponents array
+ * @param obj the array that the result is written to: an array of values
+ * whose length must be the number of components used by the color model and
+ * whose type depends on the transfer type (based on the pixel bit depth),
+ * or null to have the appropriate array created
+ *
+ * @return the array of data elements
+ */
+ public Object getDataElements(int[] components, int offset, Object obj) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the data elements from the specified array of normalized components.
+ *
+ * @param normComponents the array normalized components
+ * @param normOffset the offset in the normComponents array
+ * @param obj the array that the result is written to: an array of values
+ * whose length must be the number of components used by the color model and
+ * whose type depends on the transfer type (based on the pixel bit depth),
+ * or null to have the appropriate array created
+ *
+ * @return the array of data elements
+ */
+ public Object getDataElements(float[] normComponents, int normOffset,
+ Object obj) {
+ int unnormComponents[] = getUnnormalizedComponents(normComponents,
+ normOffset, null, 0);
+ return getDataElements(unnormComponents, 0, obj);
+ }
+
+ /**
+ * Gets the data elements corresponding to the pixel determined by the
+ * RGB data.
+ *
+ * @param rgb the rgb int that defines the pixel
+ * @param pixel the array that the result is written to: an array of values
+ * whose length must be the number of components used by the color model and
+ * whose type depends on the transfer type (based on the pixel bit depth),
+ * or null to have the appropriate array created
+ *
+ * @return the array of data elements
+ */
+ public Object getDataElements(int rgb, Object pixel) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the child raster corresponding to the alpha channel of the
+ * specified writable raster, or null if alpha is not supported.
+ *
+ * @param raster the raster
+ *
+ * @return the alpha raster
+ */
+ public WritableRaster getAlphaRaster(WritableRaster raster) {
+ return null;
+ }
+
+ /**
+ * Creates a new color model by coercing the data in the writable raster
+ * in accordance with the alpha strategy of this color model.
+ *
+ * @param raster the raster
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this
+ * color model
+ *
+ * @return the new color model
+ */
+ public ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour.
+ // It could be reveled such way:
+ // ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB,
+ // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+ // System.out.println(cm.toString());
+ return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$
+ + hasAlpha + "; is alpha premultipied = " //$NON-NLS-1$
+ + isAlphaPremultiplied + "; transparency = " + transparency //$NON-NLS-1$
+ + "; number color components = " + numColorComponents //$NON-NLS-1$
+ + "; pixel bits = " + pixel_bits + "; transfer type = " //$NON-NLS-1$ //$NON-NLS-2$
+ + transferType;
+ }
+
+ /**
+ * Gets the components of the pixel determined by the data array.
+ *
+ * @param pixel the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ * @param components the the array where the resulting components
+ * are written (or null to prompt the method to create the return array)
+ * @param offset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the array of components
+ */
+ public int[] getComponents(Object pixel, int[] components, int offset) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the normalized components of the pixel determined by the data array.
+ *
+ * @param pixel the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ * @param normComponents the array where the resulting normalised components
+ * are written (or null to prompt the method to create the return array)
+ * @param normOffset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the array of normalized components
+ */
+ public float[] getNormalizedComponents(Object pixel,
+ float[] normComponents, int normOffset) {
+
+ if (pixel == null) {
+ // awt.294=pixel is null
+ throw new NullPointerException(Messages.getString("awt.294")); //$NON-NLS-1$
+ }
+
+ int unnormComponents[] = getComponents(pixel, null, 0);
+ return getNormalizedComponents(unnormComponents, 0, normComponents,
+ normOffset);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ColorModel)) {
+ return false;
+ }
+ ColorModel cm = (ColorModel) obj;
+
+ return (pixel_bits == cm.getPixelSize() &&
+ transferType == cm.getTransferType() &&
+ cs.getType() == cm.getColorSpace().getType() &&
+ hasAlpha == cm.hasAlpha() &&
+ isAlphaPremultiplied == cm.isAlphaPremultiplied() &&
+ transparency == cm.getTransparency() &&
+ numColorComponents == cm.getNumColorComponents() &&
+ numComponents == cm.getNumComponents() &&
+ Arrays.equals(bits, cm.getComponentSize()));
+ }
+
+ /**
+ * Gets the red component of the pixel determined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the red
+ */
+ public int getRed(Object inData) {
+ return getRed(constructPixel(inData));
+ }
+
+ /**
+ * Gets the RGB int corresponding to the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the int that gives the pixel's colors in RGB format
+ */
+ public int getRGB(Object inData) {
+ return (getAlpha(inData) << 24 | getRed(inData) << 16 |
+ getGreen(inData) << 8 | getBlue(inData));
+ }
+
+ /**
+ * Gets the green component of the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the green
+ */
+ public int getGreen(Object inData) {
+ return getGreen(constructPixel(inData));
+ }
+
+ /**
+ * Gets the blue component of the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the blue
+ */
+ public int getBlue(Object inData) {
+ return getBlue(constructPixel(inData));
+ }
+
+ /**
+ * Gets the alpha component of the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the alpha
+ */
+ public int getAlpha(Object inData) {
+ return getAlpha(constructPixel(inData));
+ }
+
+ /**
+ * Creates a compatible writable raster.
+ *
+ * @param w the width of the desired writable raster
+ * @param h the height of the desired writable raster
+ *
+ * @return the writable raster
+ */
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if the sample model is compatible with this color model.
+ *
+ * @param sm the sample model
+ *
+ * @return true, if the sample model is compatible with this color model
+ */
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates the compatible sample model.
+ *
+ * @param w the width of the desired sample model
+ * @param h the height of the desired sample model
+ *
+ * @return the sample model
+ */
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if the specified raster is compatible with this color model.
+ *
+ * @param raster the raster to inspect
+ *
+ * @return true, if the raster is compatible with this color model
+ */
+ public boolean isCompatibleRaster(Raster raster) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the color space of this color model.
+ *
+ * @return the color space
+ */
+ public final ColorSpace getColorSpace() {
+ return cs;
+ }
+
+ /**
+ * Gets the normalized components corresponding to the specified
+ * unnormalized components.
+ *
+ * @param components the array of unnormalized components
+ * @param offset the offset where the components should be read
+ * from the array of unnormalized components
+ * @param normComponents the array where the resulting normalised components
+ * are written (or null to prompt the method to create the return array)
+ * @param normOffset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the normalized components
+ */
+ public float[] getNormalizedComponents(int[] components, int offset,
+ float normComponents[], int normOffset) {
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ if (normComponents == null) {
+ normComponents = new float[numComponents + normOffset];
+ }
+
+ if (hasAlpha && isAlphaPremultiplied) {
+ float normAlpha =
+ (float) components[offset + numColorComponents] /
+ maxValues[numColorComponents];
+ if (normAlpha != 0.0f) {
+ for (int i = 0; i < numColorComponents; i++) {
+ normComponents[normOffset + i] =
+ components[offset + i] /
+ (normAlpha * maxValues[i]);
+ }
+ normComponents[normOffset + numColorComponents] = normAlpha;
+ } else {
+ for (int i = 0; i < numComponents; i++) {
+ normComponents[normOffset + i] = 0.0f;
+ }
+ }
+ } else {
+ for (int i = 0; i < numComponents; i++) {
+ normComponents[normOffset + i] =
+ (float) components[offset + i] /
+ maxValues[i];
+ }
+ }
+
+ return normComponents;
+ }
+
+ /**
+ * Gets the data element corresponding to the unnormalized components.
+ *
+ * @param components the components
+ * @param offset the offset to start reading the components from the
+ * array of components
+ *
+ * @return the data element
+ */
+ public int getDataElement(int[] components, int offset) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the unnormalized components corresponding to the specified
+ * normalized components.
+ *
+ * @param normComponents the array of normalized components
+ * @param normOffset the offset where the components should be read
+ * from the array of normalized components
+ * @param components the array where the resulting unnormalised components
+ * are written (or null to prompt the method to create the return array)
+ * @param offset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the unnormalized components
+ */
+ public int[] getUnnormalizedComponents(float normComponents[],
+ int normOffset, int components[], int offset) {
+
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ if (normComponents.length - normOffset < numComponents) {
+ // awt.273=The length of normComponents minus normOffset is less than numComponents
+ throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$
+ }
+
+ if (components == null) {
+ components = new int[numComponents + offset];
+ } else {
+ if (components.length - offset < numComponents) {
+ // awt.272=The length of components minus offset is less than numComponents
+ throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$
+ }
+ }
+
+ if (hasAlpha && isAlphaPremultiplied) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ components[offset + i] = (int) (normComponents[normOffset + i]
+ * maxValues[i] * alpha + 0.5f);
+ }
+ components[offset + numColorComponents] =
+ (int) (normComponents[normOffset + numColorComponents] *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0; i < numComponents; i++) {
+ components[offset + i] =
+ (int) (normComponents[normOffset + i] *
+ maxValues[i] + 0.5f);
+ }
+ }
+
+ return components;
+ }
+
+ /**
+ * Gets the data element corresponding to the normalized components.
+ *
+ * @param normComponents the normalized components
+ * @param normOffset the offset where the normalized components should
+ * be read from the normalized component array
+ *
+ * @return the data element
+ */
+ public int getDataElement(float normComponents[], int normOffset) {
+ int unnormComponents[] = getUnnormalizedComponents(normComponents,
+ normOffset, null, 0);
+ return getDataElement(unnormComponents, 0);
+ }
+
+ /**
+ * Takes a pixel whose data is defined by an int, and writes the
+ * corresponding components into the components array, starting
+ * from the index offset.
+ *
+ * @param pixel the pixel data
+ * @param components the data array to write the components to (or
+ * null to have the method create the return array)
+ * @param offset the offset that determines where the results are
+ * written in the components array
+ *
+ * @return the array of components corresponding to the pixel
+ */
+ public int[] getComponents(int pixel, int components[], int offset) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the red component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel data
+ *
+ * @return the red component of the pixel
+ */
+ public abstract int getRed(int pixel);
+
+ /**
+ * Takes the pixel data and returns the int corresponding
+ * to the pixel's color in RGB format.
+ *
+ * @param pixel the pixel data
+ *
+ * @return the corresponding RGB int
+ */
+ public int getRGB(int pixel) {
+ return (getAlpha(pixel) << 24 | getRed(pixel) << 16
+ | getGreen(pixel) << 8 | getBlue(pixel));
+ }
+
+ /**
+ * Gets the green component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel data
+ *
+ * @return the green component of the pixel
+ */
+ public abstract int getGreen(int pixel);
+
+ /**
+ * Gets the size of the desired component of this color model.
+ *
+ * @param componentIdx the index that determines which component size to get
+ *
+ * @return the component size corresponding to the index
+ *
+ * @throws NullPointerException if this color model doesn't support
+ * an array of separate components.
+ * @throws ArrayIndexOutOfBoundsException if the index is negative or
+ * greater than or equal to the number of components
+ */
+ public int getComponentSize(int componentIdx) {
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ if (componentIdx < 0 || componentIdx >= bits.length) {
+ // awt.274=componentIdx is greater than the number of components or less than zero
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$
+ }
+
+ return bits[componentIdx];
+ }
+
+ /**
+ * Gets the blue component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel
+ *
+ * @return the blue component of the pixel
+ */
+ public abstract int getBlue(int pixel);
+
+ /**
+ * Gets the alpha component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel
+ *
+ * @return the alpha component of the pixel
+ */
+ public abstract int getAlpha(int pixel);
+
+ /**
+ * Gets the array of sizes of the different components.
+ *
+ * @return the array of sizes of the different components
+ */
+ public int[] getComponentSize() {
+ if (bits != null) {
+ return bits.clone();
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the alpha component is premultiplied.
+ *
+ * @return true, if the alpha component is premultiplied
+ */
+ public final boolean isAlphaPremultiplied() {
+ return isAlphaPremultiplied;
+ }
+
+ /**
+ * Checks whether this color model supports alpha.
+ *
+ * @return true, if this color model has alpha
+ */
+ public final boolean hasAlpha() {
+ return hasAlpha;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp;
+
+ if (hasAlpha) {
+ hash ^= 1;
+ hash <<= 8;
+ }
+ if (isAlphaPremultiplied) {
+ hash ^= 1;
+ hash <<= 8;
+ }
+
+ tmp = hash >>> 24;
+ hash ^= numColorComponents;
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= transparency;
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= cs.getType();
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= pixel_bits;
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= transferType;
+ hash <<= 8;
+ hash |= tmp;
+
+ if (bits != null) {
+
+ for (int element : bits) {
+ tmp = hash >>> 24;
+ hash ^= element;
+ hash <<= 8;
+ hash |= tmp;
+ }
+
+ }
+
+ return hash;
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Gets the transfer type, which is the type of Java primitive
+ * value that corresponds to the bit length per pixel: either
+ * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT},
+ * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}.
+ *
+ * @return the transfer type
+ */
+ public final int getTransferType() {
+ return transferType;
+ }
+
+ /**
+ * Gets the pixel size in bits.
+ *
+ * @return the pixel size
+ */
+ public int getPixelSize() {
+ return pixel_bits;
+ }
+
+ /**
+ * Gets the number of components of this color model.
+ *
+ * @return the number of components
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+ /**
+ * Gets the number of color components of this color model.
+ *
+ * @return the number color components
+ */
+ public int getNumColorComponents() {
+ return numColorComponents;
+ }
+
+ /**
+ * Gets the default RGB color model.
+ *
+ * @return the default RGB color model
+ */
+ public static ColorModel getRGBdefault() {
+ if (RGBdefault == null) {
+ RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00,
+ 0x000000ff, 0xff000000);
+ }
+ return RGBdefault;
+ }
+
+ /*
+ * Construct INT pixel representation from Object
+ * @param obj
+ *
+ * @return
+ */
+ /**
+ * Construct pixel.
+ *
+ * @param obj the obj
+ *
+ * @return the int
+ */
+ private int constructPixel(Object obj) {
+ int pixel = 0;
+
+ switch (getTransferType()) {
+
+ case DataBuffer.TYPE_BYTE:
+ byte[] bPixel = (byte[]) obj;
+ if(bPixel.length > 1) {
+ // awt.275=This pixel representation is not suuported by tis Color Model
+ throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+ }
+ pixel = bPixel[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short[] sPixel = (short[]) obj;
+ if(sPixel.length > 1) {
+ // awt.275=This pixel representation is not suuported by tis Color Model
+ throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+ }
+ pixel = sPixel[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int[] iPixel = (int[]) obj;
+ if(iPixel.length > 1) {
+ // awt.275=This pixel representation is not suuported by tis Color Model
+ throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+ }
+ pixel = iPixel[0];
+ break;
+
+ default:
+ // awt.22D=This transferType ( {0} ) is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$
+ transferType));
+
+ }
+ return pixel;
+ }
+
+ /**
+ * Gets the transfer type, which is the type of Java primitive
+ * value that corresponds to the bit length per pixel: either
+ * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT},
+ * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}.
+ *
+ * @param bits the array of component masks
+ *
+ * @return the transfer type
+ */
+ static int getTransferType(int bits) {
+ if (bits <= 8) {
+ return DataBuffer.TYPE_BYTE;
+ } else if (bits <= 16) {
+ return DataBuffer.TYPE_USHORT;
+ } else if (bits <= 32) {
+ return DataBuffer.TYPE_INT;
+ } else {
+ return DataBuffer.TYPE_UNDEFINED;
+ }
+ }
+
+ @Override
+ public void finalize() {
+ // This method is added for the API compatibility
+ // Don't need to call super since Object's finalize is always empty
+ }
+}
diff --git a/awt/java/awt/image/ComponentColorModel.java b/awt/java/awt/image/ComponentColorModel.java
new file mode 100644
index 0000000..a152f55
--- /dev/null
+++ b/awt/java/awt/image/ComponentColorModel.java
@@ -0,0 +1,1471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.color.ColorSpace;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class ComponentColorModel represents a color model that is defined
+ * in terms of its components.
+ */
+public class ComponentColorModel extends ColorModel {
+
+ /** The signed. */
+ private boolean signed; // Pixel samples are signed.
+ // Samples with TransferType DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT -
+ // unsigned. Samples with others TransferType -
+ // signed.
+
+ /** The integral. */
+ private boolean integral; // Pixel samples are integral.
+ // Samples with TransferType DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, DataBuffer.Short and
+ // DataBuffer.TYPE_INT - integral.
+
+ /** The scale factors. */
+ private float scaleFactors[]; // Array of factors for reduction components
+ // values into the form scaled from 0 to 255
+
+ /** The donot support unnormalized. */
+ private boolean donotSupportUnnormalized; // This Color Model don't support
+ // unnormolized form
+
+ /** The need alpha divide. */
+ private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied
+
+ /** The calc value. */
+ private boolean calcValue; // Value was culculated
+
+ /** The need scale. */
+ private boolean needScale; // Normalized value need to scale
+
+ /** The min vals. */
+ private float minVals[]; // Array of Min normalized values
+
+ /** The ranges. */
+ private float ranges[]; // Array of range normalized values
+
+ /** The alpha lut. */
+ private byte alphaLUT[]; // Lookup table for scale alpha value
+
+ /** The color lu ts. */
+ private byte colorLUTs[][]; // Lookup tables for scale color values
+
+ /** The from_ linea r_ rg b_ lut. */
+ private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from
+ // Linear RGB Color Space into sRGB
+
+ /** The to_ linea r_8 rg b_ lut. */
+ private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 8 bit
+
+ /** The to_ linea r_16 rg b_ lut. */
+ private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 16 bit
+
+ /** The LINEA r_ rg b_ length. */
+ private int LINEAR_RGB_Length; // Linear RGB bit length
+
+ /** The factor. */
+ private float fFactor; // Scale factor
+
+ /** The is_s rgb. */
+ private boolean is_sRGB; // ColorModel has sRGB ColorSpace
+
+ /** The is_ linea r_ rgb. */
+ private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color
+ // Space
+
+ /**
+ * Instantiates a new component color model.
+ *
+ * @param colorSpace the color space
+ * @param bits the array of component masks
+ * @param hasAlpha whether the color model has alpha
+ * @param isAlphaPremultiplied whether the alpha is premultiplied
+ * @param transparency the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ */
+ public ComponentColorModel(ColorSpace colorSpace, int bits[],
+ boolean hasAlpha, boolean isAlphaPremultiplied, int transparency,
+ int transferType) {
+ super(createPixelBits(colorSpace, hasAlpha, transferType),
+ validateBits(bits, colorSpace, hasAlpha, transferType),
+ colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
+ transferType);
+
+ needScale = false;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ signed = false;
+ integral = true;
+ donotSupportUnnormalized = false;
+ scaleFactors = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ scaleFactors[i] = 1.0f / maxValues[i];
+ if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+ donotSupportUnnormalized = true;
+ }
+ }
+ if (hasAlpha) {
+ maxValues[numColorComponents] =
+ (1 << bits[numColorComponents]) - 1;
+ scaleFactors[numColorComponents] =
+ 1.0f / maxValues[numColorComponents];
+ }
+ break;
+ case DataBuffer.TYPE_SHORT:
+ signed = true;
+ integral = true;
+ donotSupportUnnormalized = true;
+ scaleFactors = new float[numComponents];
+ for (int i = 0; i < numComponents; i++) {
+ maxValues[i] = Short.MAX_VALUE;
+ scaleFactors[i] = 1.0f / maxValues[i];
+ if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+ needScale = true;
+ }
+ }
+ if (needScale) {
+ minVals = new float[numColorComponents];
+ ranges = new float[numColorComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ minVals[i] = cs.getMinValue(i);
+ ranges[i] = cs.getMaxValue(i) - minVals[i];
+ }
+ }
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ case DataBuffer.TYPE_DOUBLE:
+ signed = true;
+ integral = false;
+ donotSupportUnnormalized = true;
+ break;
+ default:
+ // awt.215=transferType is not one of DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT,
+ // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or
+ // DataBuffer.TYPE_DOUBLE
+ throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$
+ }
+
+ needAlphaDivide = hasAlpha && isAlphaPremultiplied;
+ initLUTs();
+ }
+
+ /**
+ * Instantiates a new component color model.
+ *
+ * @param colorSpace the color space
+ * @param hasAlpha whether the color model has alpha
+ * @param isAlphaPremultiplied whether the alpha is premultiplied
+ * @param transparency the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ */
+ public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha,
+ boolean isAlphaPremultiplied, int transparency, int transferType) {
+
+ this(colorSpace,
+ createPixelBitsArray(colorSpace, hasAlpha, transferType),
+ hasAlpha,
+ isAlphaPremultiplied,
+ transparency,
+ transferType);
+ }
+
+ /**
+ * Validate bits.
+ *
+ * @param bits the bits
+ * @param colorSpace the color space
+ * @param hasAlpha the has alpha
+ * @param transferType the transfer type
+ *
+ * @return the int[]
+ */
+ private static int[] validateBits(int bits[], ColorSpace colorSpace,
+ boolean hasAlpha, int transferType) {
+ if (bits != null) {
+ return bits;
+ }
+
+ int numComponents = colorSpace.getNumComponents();
+ if (hasAlpha) {
+ numComponents++;
+ }
+ bits = new int[numComponents];
+
+ int componentLength = DataBuffer.getDataTypeSize(transferType);
+
+ for (int i = 0; i < numComponents; i++) {
+ bits[i] = componentLength;
+ }
+
+ return bits;
+ }
+
+ /**
+ * Creates the pixel bits.
+ *
+ * @param colorSpace the color space
+ * @param hasAlpha the has alpha
+ * @param transferType the transfer type
+ *
+ * @return the int
+ */
+ private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha,
+ int transferType) {
+ int numComponents = colorSpace.getNumComponents();
+ if (hasAlpha) {
+ numComponents++;
+ }
+ int componentLength = DataBuffer.getDataTypeSize(transferType);
+ return numComponents * componentLength;
+ }
+
+ /**
+ * Creates the pixel bits array.
+ *
+ * @param colorSpace the color space
+ * @param hasAlpha the has alpha
+ * @param transferType the transfer type
+ *
+ * @return the int[]
+ */
+ private static int[] createPixelBitsArray(ColorSpace colorSpace,
+ boolean hasAlpha, int transferType) {
+
+ int numComponents = colorSpace.getNumComponents();
+ if (hasAlpha) {
+ numComponents++;
+ }
+
+ int bits[] = new int[numComponents];
+ for(int i = 0; i < numComponents; i++){
+ bits[i] = DataBuffer.getDataTypeSize(transferType);
+ }
+ return bits;
+ }
+
+ @Override
+ public Object getDataElements(int components[], int offset, Object obj) {
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (offset + numComponents > components.length) {
+ // awt.216=The components array is not large enough to hold all the color and alpha components
+ throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (obj == null) {
+ ba = new byte[numComponents];
+ } else {
+ ba = (byte[]) obj;
+ }
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ ba[i] = (byte) components[idx];
+ }
+ return ba;
+ case DataBuffer.TYPE_USHORT:
+ short sa[];
+ if (obj == null) {
+ sa = new short[numComponents];
+ } else {
+ sa = (short[]) obj;
+ }
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ sa[i] = (short) components[idx];
+ }
+ return sa;
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (obj == null) {
+ ia = new int[numComponents];
+ } else {
+ ia = (int[]) obj;
+ }
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ ia[i] = components[idx];
+ }
+ return ia;
+ default:
+ // awt.217=The transfer type of this ComponentColorModel is not one
+ // of the following transfer types: DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+ throw new UnsupportedOperationException(Messages
+ .getString("awt.217")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object getDataElements(float normComponents[], int normOffset,
+ Object obj) {
+ if (needScale) {
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ normComponents[idx] =
+ (normComponents[idx] - minVals[i]) / ranges[i];
+ }
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (obj == null) {
+ ba = new byte[numComponents];
+ } else {
+ ba = (byte[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = normOffset; i < numColorComponents;
+ i++, idx++) {
+ ba[i] = (byte) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ ba[numColorComponents] =
+ (byte) (normComponents[normOffset + numColorComponents] *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ ba[idx] =
+ (byte) (normComponents[idx] * maxValues[i] + 0.5f);
+ }
+ }
+ return ba;
+
+ case DataBuffer.TYPE_USHORT:
+ short usa[];
+ if (obj == null) {
+ usa = new short[numComponents];
+ } else {
+ usa = (short[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ usa[i] = (short) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ usa[numColorComponents] = (short) (alpha *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ usa[i] = (short) (normComponents[idx] *
+ maxValues[i] + 0.5f);
+ }
+ }
+ return usa;
+
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (obj == null) {
+ ia = new int[numComponents];
+ } else {
+ ia = (int[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ ia[i] = (int) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ ia[numColorComponents] = (int) (alpha *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ ia[i] = (int) (normComponents[idx] * maxValues[i] + 0.5f);
+ }
+ }
+ return ia;
+
+ case DataBuffer.TYPE_SHORT:
+ short sa[];
+ if (obj == null) {
+ sa = new short[numComponents];
+ } else {
+ sa = (short[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ sa[i] = (short) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ sa[numColorComponents] = (short) (alpha *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ sa[i] = (short) (normComponents[idx] *
+ maxValues[i] + 0.5f);
+ }
+ }
+ return sa;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fa[];
+ if (obj == null) {
+ fa = new float[numComponents];
+ } else {
+ fa = (float[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ fa[i] = normComponents[idx] * alpha;
+ }
+ fa[numColorComponents] = alpha;
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ fa[i] = normComponents[idx];
+ }
+ }
+ return fa;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double da[];
+ if (obj == null) {
+ da = new double[numComponents];
+ } else {
+ da = (double[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ double alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ da[i] = normComponents[idx] * alpha;
+ }
+ da[numColorComponents] = alpha;
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ da[i] = normComponents[idx];
+ }
+ }
+ return da;
+
+ default:
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object getDataElements(int rgb, Object pixel) {
+ float normComp[];
+ float comp[];
+
+ int red = (rgb >> 16) & 0xff;
+ int green = (rgb >> 8) & 0xff;
+ int blue = rgb & 0xff;
+ int alpha = (rgb >> 24) & 0xff;
+
+ comp = new float[3];
+ if (is_sRGB || is_LINEAR_RGB) {
+ if (is_LINEAR_RGB) {
+ if (LINEAR_RGB_Length == 8) {
+ red = to_LINEAR_8RGB_LUT[red] & 0xff;
+ green = to_LINEAR_8RGB_LUT[green] & 0xff;
+ blue = to_LINEAR_8RGB_LUT[blue] & 0xff;
+ } else {
+ red = to_LINEAR_16RGB_LUT[red] & 0xffff;
+ green = to_LINEAR_16RGB_LUT[green] & 0xffff;
+ blue = to_LINEAR_16RGB_LUT[blue] & 0xffff;
+ }
+ }
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ if (!hasAlpha) {
+ normComp = comp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = comp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ } else {
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ float[] defComp = cs.fromRGB(comp);
+ if (!hasAlpha) {
+ normComp = defComp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = defComp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ }
+ if(hasAlpha && isAlphaPremultiplied){
+ normComp[0] *= normComp[numColorComponents];
+ normComp[1] *= normComp[numColorComponents];
+ normComp[2] *= normComp[numColorComponents];
+ }
+
+ return getDataElements(normComp, 0, pixel);
+ }
+
+ @Override
+ public WritableRaster getAlphaRaster(WritableRaster raster) {
+ if(!hasAlpha) {
+ return null;
+ }
+
+ int x = raster.getMinX();
+ int y = raster.getMinY();
+ int bandList[] = new int[1];
+ bandList[0] = raster.getNumBands() - 1;
+
+ return raster.createWritableChild(x, y, raster.getWidth(),
+ raster.getHeight(), x, y, bandList);
+ }
+
+ @Override
+ public ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied) {
+ if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) {
+ return this;
+ }
+
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ if (isAlphaPremultiplied) {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ float alphaFactor = maxValues[numColorComponents];
+ int iComponents[] = null;
+ int iTransparentComponents[] = new int[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ iComponents = raster.getPixel(x, minY,
+ iComponents);
+ if (iComponents[numColorComponents] == 0) {
+ raster.setPixel(x, minY, iTransparentComponents);
+ } else {
+ float alpha =
+ iComponents[numColorComponents] /
+ alphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ iComponents[n] =
+ (int) (alpha * iComponents[n] + 0.5f);
+ }
+ raster.setPixel(x, minY, iComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ float sAlphaFactor = maxValues[numColorComponents];
+ short sComponents[] = null;
+ short sTransparentComponents[] = new short[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ sComponents = (short[]) raster.getDataElements(x, minY,
+ sComponents);
+ if (sComponents[numColorComponents] == 0) {
+ raster.setDataElements(x, minY,
+ sTransparentComponents);
+ } else {
+ float alpha =
+ sComponents[numColorComponents] /
+ sAlphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ sComponents[n] =
+ (byte) (alpha * sComponents[n] + 0.5f);
+ }
+ raster.setDataElements(x, minY, sComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fComponents[] = null;
+ float fTransparentComponents[] = new float[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ fComponents = raster.getPixel(x, minY, fComponents);
+ if (fComponents[numColorComponents] == 0.0f) {
+ raster.setDataElements(x, minY,
+ fTransparentComponents);
+ } else {
+ float alpha = fComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ fComponents[n] = fComponents[n] * alpha;
+ }
+ raster.setPixel(x, minY, fComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dComponents[] = null;
+ double dTransparentComponents[] = new double[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ dComponents = raster.getPixel(x, minY, dComponents);
+ if (dComponents[numColorComponents] == 0.0) {
+ raster.setPixel(x, minY, dTransparentComponents);
+ } else {
+ double alpha = dComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ dComponents[n] = dComponents[n] * alpha;
+ }
+ raster.setPixel(x, minY, dComponents);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ // awt.219=This transferType is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+ }
+ } else {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ float alphaFactor = maxValues[numColorComponents];
+ int iComponents[] = null;
+ int iTransparentComponents[] = new int[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ iComponents = raster.getPixel(x, minY,
+ iComponents);
+ if (iComponents[numColorComponents] == 0) {
+ raster.setPixel(x, minY, iTransparentComponents);
+ } else {
+ float alpha =
+ iComponents[numColorComponents] /
+ alphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ iComponents[n] =
+ (int) (iComponents[n] /
+ alpha + 0.5f);
+ }
+ raster.setPixel(x, minY, iComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ float sAlphaFactor = maxValues[numColorComponents];
+ short sComponents[] = null;
+ short sTransparentComponents[] = new short[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ sComponents = (short[]) raster.getDataElements(x, minY,
+ sComponents);
+ if (sComponents[numColorComponents] == 0) {
+ raster.setDataElements(x, minY,
+ sTransparentComponents);
+ } else {
+ float alpha =
+ sComponents[numColorComponents] /
+ sAlphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ sComponents[n] =
+ (byte) (sComponents[n] /
+ alpha + 0.5f);
+ }
+ raster.setDataElements(x, minY, sComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fComponents[] = null;
+ float fTransparentComponents[] = new float[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ fComponents = raster.getPixel(x, minY, fComponents);
+ if (fComponents[numColorComponents] == 0.0f) {
+ raster.setDataElements(x, minY,
+ fTransparentComponents);
+ } else {
+ float alpha = fComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ fComponents[n] = fComponents[n] / alpha;
+ }
+ raster.setPixel(x, minY, fComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dComponents[] = null;
+ double dTransparentComponents[] = new double[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ dComponents = raster.getPixel(x, minY, dComponents);
+ if (dComponents[numColorComponents] == 0.0) {
+ raster.setPixel(x, minY, dTransparentComponents);
+ } else {
+ double alpha = dComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ dComponents[n] = dComponents[n] / alpha;
+ }
+ raster.setPixel(x, minY, dComponents);
+ }
+ }
+
+ }
+ break;
+ default:
+ // awt.219=This transferType is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+ }
+ }
+
+ if (!signed) {
+ return new ComponentColorModel(cs, bits, hasAlpha,
+ isAlphaPremultiplied, transparency, transferType);
+ }
+
+ return new ComponentColorModel(cs, null, hasAlpha,
+ isAlphaPremultiplied, transparency, transferType);
+ }
+
+ @Override
+ public int[] getComponents(Object pixel, int[] components, int offset) {
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (components == null) {
+ components = new int[offset + numComponents];
+ } else if (offset + numComponents > components.length) {
+ // awt.218=The components array is not large enough to hold all the color and alpha components
+ throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ components[idx] = ba[i] & 0xff;
+ }
+ return components;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) pixel;
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ components[idx] = sa[i] & 0xffff;
+ }
+ return components;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ components[idx] = ia[i];
+ }
+ return components;
+
+ default:
+ // awt.217=The transfer type of this ComponentColorModel is not one
+ // of the following transfer types: DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+ throw new UnsupportedOperationException(Messages
+ .getString("awt.217")); //$NON-NLS-1$
+ }
+
+ }
+
+ @Override
+ public float[] getNormalizedComponents(Object pixel,
+ float normComponents[], int normOffset) {
+
+ if (normComponents == null) {
+ normComponents = new float[numComponents + normOffset];
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short usa[] = (short[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = (usa[i] & 0xffff)
+ * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = ia[i] * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ short sa[] = (short[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = sa[i] * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fa[] = (float[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = fa[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double da[] = (double[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = (float) da[i];
+ }
+ break;
+
+ default:
+ // awt.21A=This ComponentColorModel does not support this transferType
+ throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = normOffset; i < numColorComponents;
+ i++, idx++) {
+ normComponents[idx] /= alpha;
+ }
+ }
+
+ if (needScale) {
+ for (int i = 0, idx = normOffset; i < numColorComponents;
+ i++, idx++) {
+ normComponents[idx] = minVals[i] +
+ ranges[i] * normComponents[idx];
+ }
+ }
+ return normComponents;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ComponentColorModel)) {
+ return false;
+ }
+ return super.equals(obj);
+ }
+
+ @Override
+ public int getRed(Object inData) {
+ return getRGBComponent(inData, 0);
+ }
+
+ @Override
+ public int getRGB(Object inData) {
+ int alpha = getAlpha(inData);
+ if (cs.getType() == ColorSpace.TYPE_GRAY) {
+ int gray = getRed(inData);
+ return (alpha << 24 | gray << 16 | gray << 8 | gray);
+ }
+ return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 |
+ getBlue(inData));
+ }
+
+ @Override
+ public int getGreen(Object inData) {
+ return getRGBComponent(inData, 1);
+ }
+
+ @Override
+ public int getBlue(Object inData) {
+ return getRGBComponent(inData, 2);
+ }
+
+ @Override
+ public int getAlpha(Object inData) {
+ if (!hasAlpha) {
+ return 255;
+ }
+ int alpha = 0;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE: {
+ byte ba[] = (byte[]) inData;
+ alpha = ba[numColorComponents] & 0xff;
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_USHORT: {
+ short usa[] = (short[]) inData;
+ alpha = usa[numColorComponents] & 0xffff;
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_INT: {
+ int ia[] = (int[]) inData;
+ alpha = ia[numColorComponents];
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_SHORT: {
+ short sa[] = (short[]) inData;
+ alpha = sa[numColorComponents];
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_FLOAT: {
+ float fa[] = (float[]) inData;
+ return (int) (fa[numColorComponents] * 255.0f + 0.5f);
+ }
+ case DataBuffer.TYPE_DOUBLE: {
+ double da[] = (double[]) inData;
+ return (int) (da[numColorComponents] * 255.0 + 0.5);
+ }
+ default: {
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ @Override
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ SampleModel sm = createCompatibleSampleModel(w, h);
+ DataBuffer db = sm.createDataBuffer();
+ return Raster.createWritableRaster(sm, db, null);
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ if (!(sm instanceof ComponentSampleModel)) {
+ return false;
+ }
+ if (numComponents != sm.getNumBands()) {
+ return false;
+ }
+ if (transferType != sm.getTransferType()) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ int bandOffsets[] = new int[numComponents];
+ for (int i = 0; i < numComponents; i++) {
+ bandOffsets[i] = i;
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ return new PixelInterleavedSampleModel(transferType, w, h,
+ numComponents, w * numComponents, bandOffsets);
+
+ default:
+ return new ComponentSampleModel(transferType, w, h, numComponents,
+ w * numComponents, bandOffsets);
+ }
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ SampleModel sm = raster.getSampleModel();
+ if (!(sm instanceof ComponentSampleModel)) {
+ return false;
+ }
+
+ if (sm.getNumBands() != numComponents) {
+ return false;
+ }
+ if (raster.getTransferType() != transferType) {
+ return false;
+ }
+
+ int sampleSizes[] = sm.getSampleSize();
+ for (int i = 0; i < numComponents; i++) {
+ if (bits[i] != sampleSizes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public float[] getNormalizedComponents(int components[], int offset,
+ float normComponents[], int normOffset) {
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ return super.getNormalizedComponents(components, offset,
+ normComponents, normOffset);
+ }
+
+ @Override
+ public int getDataElement(int[] components, int offset) {
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+ return components[offset];
+ }
+
+ @Override
+ public int[] getUnnormalizedComponents(float[] normComponents,
+ int normOffset, int[] components, int offset) {
+
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (normComponents.length - normOffset < numComponents) {
+ // awt.21B=The length of normComponents minus normOffset is less than numComponents
+ throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$
+ }
+
+ return super.getUnnormalizedComponents(normComponents, normOffset,
+ components, offset);
+ }
+
+ @Override
+ public int getDataElement(float normComponents[], int normOffset) {
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+ if (signed) {
+ // awt.210=The component value for this ColorModel is signed
+ throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+ }
+
+ Object pixel = getDataElements(normComponents, normOffset, null);
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ return ba[0] & 0xff;
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) pixel;
+ return sa[0] & 0xffff;
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ return ia[0];
+ default:
+ // awt.211=Pixel values for this ColorModel are not conveniently
+ // representable as a single int
+ throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public int[] getComponents(int pixel, int components[], int offset) {
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (components == null) {
+ components = new int[offset + 1];
+ }
+
+ components[offset] = pixel & maxValues[0];
+ return components;
+ }
+
+ @Override
+ public int getRed(int pixel) {
+ float rgb[] = toRGB(pixel);
+ return (int) (rgb[0] * 255.0f + 0.5f);
+ }
+
+ @Override
+ public int getRGB(int pixel) {
+ return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) |
+ (getGreen(pixel) << 8) | getBlue(pixel);
+ }
+
+ @Override
+ public int getGreen(int pixel) {
+ float rgb[] = toRGB(pixel);
+ return (int) (rgb[1] * 255.0f + 0.5f);
+ }
+
+ @Override
+ public int getBlue(int pixel) {
+ float rgb[] = toRGB(pixel);
+ return (int) (rgb[2] * 255.0f + 0.5f);
+ }
+
+ @Override
+ public int getAlpha(int pixel) {
+
+ // This method throw IllegalArgumentException according to
+ // Java API Spacification
+ if (signed) {
+ // awt.210=The component value for this ColorModel is signed
+ throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+ }
+
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+
+ return 255;
+ }
+
+ /**
+ * Initialization of Lookup tables.
+ */
+ private void initLUTs() {
+ is_sRGB = cs.isCS_sRGB();
+ is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS);
+
+ if (hasAlpha && bits[numColorComponents] != 8 && integral) {
+ alphaLUT = new byte[maxValues[numColorComponents] + 1];
+ for (int i = 0; i <= maxValues[numColorComponents]; i++) {
+ alphaLUT[i] = (byte) (scaleFactors[numColorComponents] * i +
+ 0.5f);
+ }
+ }
+
+ if (is_LINEAR_RGB) {
+ if (maxBitLength > 8) {
+ LINEAR_RGB_Length = 16;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom16lRGBtosRGB_LUT();
+ to_LINEAR_16RGB_LUT =
+ LUTColorConverter.getFromsRGBto16lRGB_LUT();
+ } else {
+ LINEAR_RGB_Length = 8;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom8lRGBtosRGB_LUT();
+ to_LINEAR_8RGB_LUT =
+ LUTColorConverter.getFromsRGBto8lRGB_LUT();
+ }
+ fFactor = ((1 << LINEAR_RGB_Length) - 1);
+ } else {
+ fFactor = 255.0f;
+ }
+
+ if (!isAlphaPremultiplied && integral) {
+ colorLUTs = new byte[3][];
+
+ if (is_sRGB) {
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != 8) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[0]; j++) {
+ colorLUTs[i][j] =
+ (byte) (scaleFactors[i] * j + 0.5f);
+ }
+ }
+ }
+ }
+
+ if (is_LINEAR_RGB) {
+
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != LINEAR_RGB_Length) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[0]; j++) {
+ int idx;
+ if (LINEAR_RGB_Length == 8) {
+ idx = (int) (scaleFactors[i] * j + 0.5f);
+ } else {
+ idx = (int) (scaleFactors[i] * j * 257.0f +
+ 0.5f);
+ }
+ colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx];
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * To rgb.
+ *
+ * @param pixel - int representation of pixel
+ *
+ * @return - array of normalized sRGB components
+ */
+ private float[] toRGB(int pixel) {
+
+ // This method throw IllegalArgumentException according to
+ // Java API Spacification
+ if (signed) {
+ // awt.210=The component value for this ColorModel is signed
+ throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+ }
+
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+
+ Object obj = null;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = new byte[1];
+ ba[0] = (byte) pixel;
+ obj = ba;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = new short[1];
+ sa[0] = (short) pixel;
+ obj = sa;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = new int[1];
+ ia[0] = pixel;
+ obj = ia;
+ break;
+
+ }
+
+ return cs.toRGB(getNormalizedComponents(obj, null, 0));
+ }
+
+ /**
+ * Gets the rgb component.
+ *
+ * @param pixel - pixel
+ * @param idx - index of component
+ *
+ * @return - RGB value from 0 to 255 pixel's component
+ */
+ private int getRGBComponent(Object pixel, int idx) {
+ if (is_sRGB) {
+ int comp = getDefComponent(pixel, idx);
+ if (calcValue || bits[idx] == 8) {
+ return comp;
+ }
+ return colorLUTs[idx][comp] & 0xff;
+ } else if (is_LINEAR_RGB) {
+ int comp = getDefComponent(pixel, idx);
+ if (calcValue || bits[idx] == LINEAR_RGB_Length) {
+ return from_LINEAR_RGB_LUT[comp] & 0xff;
+ }
+ return colorLUTs[idx][comp] & 0xff;
+ }
+
+ float normComp[] = getNormalizedComponents(pixel, null, 0);
+ float rgbComp[] = cs.toRGB(normComp);
+ return (int) (rgbComp[idx] * 255.0f + 0.5f);
+ }
+
+ /**
+ * Gets the def component.
+ *
+ * @param pixel - pixel
+ * @param idx - index of component
+ *
+ * @return - tentative value of the pixel component
+ */
+ private int getDefComponent(Object pixel, int idx) {
+ int comp = 0;
+ calcValue = false;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ comp = ba[idx] & 0xff;
+ if (needAlphaDivide) {
+ int alpha = ba[numColorComponents] & 0xff;
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_USHORT:
+ short usa[] = (short[]) pixel;
+ comp = usa[idx] & 0xffff;
+ if (needAlphaDivide) {
+ int alpha = usa[numColorComponents] & 0xffff;
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ comp = ia[idx];
+ if (needAlphaDivide) {
+ int alpha = ia[numColorComponents];
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_SHORT:
+ short sa[] = (short[]) pixel;
+ comp = sa[idx];
+ if (needAlphaDivide) {
+ int alpha = sa[numColorComponents];
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fa[] = (float[]) pixel;
+ if (needAlphaDivide) {
+ float alpha = fa[numColorComponents];
+ if (fa[numColorComponents] == 0.0f) {
+ comp = 0;
+ } else {
+ comp = (int) (fa[idx] * fFactor / alpha + 0.5f);
+ }
+ } else {
+ comp = (int) (fa[idx] * fFactor + 0.5f);
+ }
+ calcValue = true;
+ return comp;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double da[] = (double[]) pixel;
+ if (needAlphaDivide) {
+ if (da[numColorComponents] == 0.0) {
+ comp = 0;
+ } else {
+ comp = (int) (da[idx] * fFactor / da[numColorComponents] +
+ 0.5);
+ }
+ } else {
+ comp = (int) (da[idx] * fFactor + 0.5);
+ }
+ calcValue = true;
+ return comp;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/image/ComponentSampleModel.java b/awt/java/awt/image/ComponentSampleModel.java
new file mode 100644
index 0000000..2ff4f1a
--- /dev/null
+++ b/awt/java/awt/image/ComponentSampleModel.java
@@ -0,0 +1,690 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ComponentSampleModel class represents a set of image data whose
+ * each element - the sample of a pixel - takes one data element of
+ * the DataBuffer.
+ * <p>
+ * The Bank indices denote the correspondence between the bank of data
+ * buffers and a band of image data. The Pixel stride is the number of data
+ * array elements between two samples for the same band on the same
+ * scanline. The pixel stride for a BandedSampleModel is one. The Scanline
+ * stride represents the number of data array elements between a
+ * specified sample and the corresponding sample in the same column in
+ * the next scanline. The array of band offsets gives the starting
+ * offsets within each data banks of the in the DataBuffer. The bank
+ * indices represents the indices within each bank of the DataBuffer
+ * corresponding to a band of image data.
+ */
+public class ComponentSampleModel extends SampleModel {
+
+ /** The band offsets array of this ComponentSampleModel. */
+ protected int bandOffsets[];
+
+ /** The bank indices array of this ComponentSampleModel. */
+ protected int bankIndices[];
+
+ /** The number of bands in this ComponentSampleModel. */
+ protected int numBands;
+
+ /** The number banks of this ComponentSampleModel. */
+ protected int numBanks;
+
+ /** The scanline stride of this ComponentSampleModel. */
+ protected int scanlineStride;
+
+ /** The pixel stride of this ComponentSampleModel. */
+ protected int pixelStride;
+
+ /**
+ * Instantiates a new ComponentSampleModel with the specified
+ * properties.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param pixelStride the pixel stride of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bankIndices the array of the bank indices.
+ * @param bandOffsets the array of the band offsets.
+ */
+ public ComponentSampleModel(int dataType, int w, int h, int pixelStride,
+ int scanlineStride, int bankIndices[], int bandOffsets[]) {
+
+ super(dataType, w, h, bandOffsets.length);
+
+ if (pixelStride < 0) {
+ // awt.24B=Pixel stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
+ }
+
+ if (scanlineStride < 0) {
+ // awt.24C=Scanline stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
+ }
+
+ if (bankIndices.length != bandOffsets.length) {
+ // awt.24D=Bank Indices length must be equal Bank Offsets length
+ throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$
+ }
+
+ this.pixelStride = pixelStride;
+ this.scanlineStride = scanlineStride;
+ this.bandOffsets = bandOffsets.clone();
+ this.bankIndices = bankIndices.clone();
+ this.numBands = bandOffsets.length;
+
+ int maxBank = 0;
+ for (int i = 0; i < bankIndices.length; i++) {
+ if (bankIndices[i] < 0) {
+ // awt.24E=Index of {0} bank must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$
+ }
+ if (bankIndices[i] > maxBank) {
+ maxBank = bankIndices[i];
+ }
+ }
+ this.numBanks = maxBank + 1;
+
+ }
+
+ /**
+ * Instantiates a new ComponentSampleModel with the specified
+ * properties.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param pixelStride the pixel stride of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bandOffsets the band offsets.
+ */
+ public ComponentSampleModel(int dataType, int w, int h, int pixelStride,
+ int scanlineStride, int bandOffsets[]) {
+
+ super(dataType, w, h, bandOffsets.length);
+ if (pixelStride < 0) {
+ // awt.24B=Pixel stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
+ }
+
+ if (scanlineStride < 0) {
+ // awt.24C=Scanline stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
+ }
+
+ this.pixelStride = pixelStride;
+ this.scanlineStride = scanlineStride;
+ this.bandOffsets = bandOffsets.clone();
+ this.numBands = bandOffsets.length;
+ this.numBanks = 1;
+
+ this.bankIndices = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ bankIndices[i] = 0;
+ }
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ if (obj == null) {
+ bdata = new byte[numBands];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ bdata[i] = (byte) getSample(x, y, i, data);
+ }
+
+ obj = bdata;
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ if (obj == null) {
+ sdata = new short[numBands];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ sdata[i] = (short) getSample(x, y, i, data);
+ }
+
+ obj = sdata;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ if (obj == null) {
+ idata = new int[numBands];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ idata[i] = getSample(x, y, i, data);
+ }
+
+ obj = idata;
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fdata[];
+ if (obj == null) {
+ fdata = new float[numBands];
+ } else {
+ fdata = (float[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ fdata[i] = getSampleFloat(x, y, i, data);
+ }
+
+ obj = fdata;
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double ddata[];
+ if (obj == null) {
+ ddata = new double[numBands];
+ } else {
+ ddata = (double[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ ddata[i] = getSampleDouble(x, y, i, data);
+ }
+
+ obj = ddata;
+ break;
+ }
+
+ return obj;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ byte barr[] = (byte[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, barr[i] & 0xff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sarr[] = (short[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, sarr[i] & 0xffff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int iarr[] = (int[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iarr[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float farr[] = (float[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, farr[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double darr[] = (double[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, darr[i], data);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Compares this ComponentSampleModel with the specified Object.
+ *
+ * @param o the Object.
+ *
+ * @return true, if the object is a ComponentSampleModel with
+ * identical data values to this ComponentSampleModel, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof ComponentSampleModel)) {
+ return false;
+ }
+ ComponentSampleModel model = (ComponentSampleModel) o;
+ return this.width == model.width && this.height == model.height &&
+ this.numBands == model.numBands &&
+ this.dataType == model.dataType &&
+ Arrays.equals(this.bandOffsets, model.bandOffsets) &&
+ Arrays.equals(this.bankIndices, model.bankIndices) &&
+ this.numBands == model.numBands &&
+ this.numBanks == model.numBanks &&
+ this.scanlineStride == model.scanlineStride &&
+ this.pixelStride == model.pixelStride;
+ }
+
+ /**
+ * @see java.awt.image.SampleModel#createSubsetSampleModel(int[])
+ */
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands.length > this.numBands) {
+ // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+ throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+ }
+
+ int indices[] = new int[bands.length];
+ int offsets[] = new int[bands.length];
+
+ for (int i = 0; i < bands.length; i++) {
+ indices[i] = bankIndices[bands[i]];
+ offsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new ComponentSampleModel(dataType, width, height, pixelStride,
+ scanlineStride, indices, offsets);
+
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new ComponentSampleModel(dataType, w, h, pixelStride,
+ pixelStride * w, bankIndices, bandOffsets);
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ int pixel[];
+
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElem(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b]);
+ }
+
+ @Override
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemFloat(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b]);
+ }
+
+ @Override
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemDouble(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b]);
+ }
+
+ @Override
+ public int[] getPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x > this.width || x + w > this.width
+ || y > this.height || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixels[] = null;
+ int idx = 0;
+
+ if (iArray == null) {
+ pixels = new int[w * h * numBands];
+ } else {
+ pixels = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSample(j, i, n, data);
+ }
+ }
+ }
+
+ return pixels;
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride
+ + bandOffsets[b], s);
+ }
+
+ @Override
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ if (data == null) {
+ // awt.295=data is null
+ throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, iArray[idx++], data);
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemFloat(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemDouble(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b], s);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer data = null;
+
+ int maxOffset = bandOffsets[0];
+ for (int i = 1; i < bandOffsets.length; i++) {
+ if (bandOffsets[i] > maxOffset) {
+ maxOffset = bandOffsets[i];
+ }
+ }
+ int size = (height - 1) * scanlineStride +
+ (width - 1) * pixelStride + maxOffset + 1;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size, numBanks);
+ break;
+ case DataBuffer.TYPE_SHORT:
+ data = new DataBufferShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size, numBanks);
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ data = new DataBufferFloat(size, numBanks);
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ data = new DataBufferDouble(size, numBanks);
+ break;
+ }
+
+ return data;
+
+ }
+
+ /**
+ * Gets the offset of the specified band of the specified pixel.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the offset of the specified band of the specified pixel.
+ */
+ public int getOffset(int x, int y, int b) {
+ return y * scanlineStride + x * pixelStride + bandOffsets[b];
+ }
+
+ /**
+ * Gets the offset of the first band of the specified pixel.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ *
+ * @return the offset of the first band of the specified pixel.
+ */
+ public int getOffset(int x, int y) {
+ return y * scanlineStride + x * pixelStride + bandOffsets[0];
+ }
+
+ @Override
+ public final int getSampleSize(int band) {
+ return DataBuffer.getDataTypeSize(dataType);
+ }
+
+ @Override
+ public final int[] getSampleSize() {
+ int sampleSizes[] = new int[numBands];
+ int size = DataBuffer.getDataTypeSize(dataType);
+
+ for (int i = 0; i < numBands; i++) {
+ sampleSizes[i] = size;
+ }
+ return sampleSizes;
+ }
+
+ /**
+ * Gets an array of bank indices corresponding to this
+ * ComponentSampleModel.
+ *
+ * @return the array of bank indices.
+ */
+ public final int[] getBankIndices() {
+ return bankIndices.clone();
+ }
+
+ /**
+ * Gets an array of the band offsets corresponding to this
+ * ComponentSampleModel.
+ *
+ * @return the array of band offsets.
+ */
+ public final int[] getBandOffsets() {
+ return bandOffsets.clone();
+ }
+
+ /**
+ * Gets a hash code of this ComponentSampleModel object.
+ *
+ * @return a hash code of this ComponentSampleModel object.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp = 0;
+
+ hash = width;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= height;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= numBands;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataType;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ for (int element : bandOffsets) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ for (int element : bankIndices) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ hash ^= pixelStride;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+
+ hash ^= scanlineStride;
+ return hash;
+ }
+
+ /**
+ * Gets the scanline stride of this ComponentSampleModel.
+ *
+ * @return the scanline stride of this ComponentSampleModel.
+ */
+ public final int getScanlineStride() {
+ return scanlineStride;
+ }
+
+ /**
+ * Gets the pixel stride.
+ *
+ * @return the pixel stride
+ */
+ public final int getPixelStride() {
+ return pixelStride;
+ }
+
+ @Override
+ public final int getNumDataElements() {
+ return numBands;
+ }
+
+}
+
+
+
diff --git a/awt/java/awt/image/ConvolveOp.java b/awt/java/awt/image/ConvolveOp.java
new file mode 100644
index 0000000..bb588bc
--- /dev/null
+++ b/awt/java/awt/image/ConvolveOp.java
@@ -0,0 +1,545 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 29, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ConvolveOp class convolves from the source data
+ * to the destination using a convolution kernel.
+ * Each output pixel is represented as the result of multiplying
+ * the kernel and the surround of the input pixel.
+ */
+public class ConvolveOp implements BufferedImageOp, RasterOp {
+
+ /**
+ * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of
+ * the destination image are set to zero.
+ */
+ public static final int EDGE_ZERO_FILL = 0;
+
+ /**
+ * The Constant EDGE_NO_OP indicates that pixels at the edge of
+ * the source image are converted to the edge pixels in the
+ * destination without modification.
+ */
+ public static final int EDGE_NO_OP = 1;
+
+ /** The kernel. */
+ private Kernel kernel;
+
+ /** The edge cond. */
+ private int edgeCond;
+
+ /** The rhs. */
+ private RenderingHints rhs = null;
+
+ static {
+ // TODO
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new ConvolveOp object with the specified Kernel
+ * and specified edges condition.
+ *
+ * @param kernel the specified Kernel.
+ * @param edgeCondition the specified edge condition.
+ * @param hints the RenderingHints object, or null.
+ */
+ public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) {
+ this.kernel = kernel;
+ this.edgeCond = edgeCondition;
+ this.rhs = hints;
+ }
+
+ /**
+ * Instantiates a new ConvolveOp object with the specified Kernel
+ * and EDGE_ZERO_FILL edge condition.
+ *
+ * @param kernel the specified Kernel.
+ */
+ public ConvolveOp(Kernel kernel) {
+ this.kernel = kernel;
+ this.edgeCond = EDGE_ZERO_FILL;
+ }
+
+ /**
+ * Gets the Kernel object of this ConvolveOp.
+ *
+ * @return the Kernel object of this ConvolveOp.
+ */
+ public final Kernel getKernel() {
+ return (Kernel) kernel.clone();
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return rhs;
+ }
+
+ /**
+ * Gets the edge condition of this ConvolveOp.
+ *
+ * @return the edge condition: EDGE_NO_OP or EDGE_ZERO_FILL.
+ */
+ public int getEdgeCondition() {
+ return edgeCond;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ return src.createCompatibleWritableRaster();
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+ if (dstCM == null) {
+ dstCM = src.getColorModel();
+ }
+
+ if (dstCM instanceof IndexColorModel) {
+ dstCM = ColorModel.getRGBdefault();
+ }
+
+ WritableRaster r =
+ dstCM.isCompatibleSampleModel(src.getSampleModel()) ?
+ src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) :
+ dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+ return new BufferedImage(
+ dstCM,
+ r,
+ dstCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (src == null) { // Should throw according to spec
+ // awt.256=Source raster is null
+ throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$
+ }
+
+ if (src == dst){
+ // awt.257=Source raster is equal to destination
+ throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else if (src.getNumBands() != dst.getNumBands()) {
+ // awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1})
+ throw new IllegalArgumentException(
+ Messages.getString("awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$
+ }
+
+ // TODO
+ //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0)
+ if (slowFilter(src, dst) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private int slowFilter(Raster src, WritableRaster dst) {
+ try {
+ SampleModel sm = src.getSampleModel();
+
+ int numBands = src.getNumBands();
+ int srcHeight = src.getHeight();
+ int srcWidth = src.getWidth();
+
+ int xOrigin = kernel.getXOrigin();
+ int yOrigin = kernel.getYOrigin();
+ int kWidth = kernel.getWidth();
+ int kHeight = kernel.getHeight();
+ float[] data = kernel.getKernelData(null);
+
+ int srcMinX = src.getMinX();
+ int srcMinY = src.getMinY();
+ int dstMinX = dst.getMinX();
+ int dstMinY = dst.getMinY();
+
+ int srcConvMaxX = srcWidth - (kWidth - xOrigin - 1);
+ int srcConvMaxY = srcHeight - (kHeight - yOrigin - 1);
+
+ int[] maxValues = new int[numBands];
+ int[] masks = new int[numBands];
+ int[] sampleSizes = sm.getSampleSize();
+
+ for (int i=0; i < numBands; i++){
+ maxValues[i] = (1 << sampleSizes[i]) - 1;
+ masks[i] = ~(maxValues[i]);
+ }
+
+ // Processing bounds
+ float[] pixels = null;
+ pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels);
+ float[] newPixels = new float[pixels.length];
+ int rowLength = srcWidth*numBands;
+ if (this.edgeCond == ConvolveOp.EDGE_NO_OP){
+ // top
+ int start = 0;
+ int length = yOrigin*rowLength;
+ System.arraycopy(pixels, start, newPixels, start, length);
+ // bottom
+ start = (srcHeight - (kHeight - yOrigin - 1))*rowLength;
+ length = (kHeight - yOrigin - 1)*rowLength;
+ System.arraycopy(pixels, start, newPixels, start, length);
+ // middle
+ length = xOrigin*numBands;
+ int length1 = (kWidth - xOrigin - 1)*numBands;
+ start = yOrigin*rowLength;
+ int start1 = (yOrigin+1)*rowLength - length1;
+ for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i ++) {
+ System.arraycopy(pixels, start, newPixels, start, length);
+ System.arraycopy(pixels, start1, newPixels, start1, length1);
+ start +=rowLength;
+ start1 +=rowLength;
+ }
+
+ }
+
+ // Cycle over pixels to be calculated
+ for (int i = yOrigin; i < srcConvMaxY; i++){
+ for (int j = xOrigin; j < srcConvMaxX; j++){
+
+ // Take kernel data in backward direction, convolution
+ int kernelIdx = data.length - 1;
+
+ int pixelIndex = i * rowLength + j * numBands;
+ for (int hIdx = 0, rasterHIdx = i - yOrigin;
+ hIdx < kHeight;
+ hIdx++, rasterHIdx++
+ ){
+ for (int wIdx = 0, rasterWIdx = j - xOrigin;
+ wIdx < kWidth;
+ wIdx++, rasterWIdx++
+ ){
+ int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands;
+ for (int idx=0; idx < numBands; idx++){
+ newPixels[pixelIndex+idx] += data[kernelIdx] * pixels[curIndex+idx];
+ }
+ kernelIdx--;
+ }
+ }
+
+ // Check for overflow now
+ for (int idx=0; idx < numBands; idx++){
+ if (((int)newPixels[pixelIndex+idx] & masks[idx]) != 0) {
+ if (newPixels[pixelIndex+idx] < 0) {
+ newPixels[pixelIndex+idx] = 0;
+ } else {
+ newPixels[pixelIndex+idx] = maxValues[idx];
+ }
+ }
+ }
+ }
+ }
+
+ dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, newPixels);
+ } catch (Exception e) { // Something goes wrong, signal error
+ return 1;
+ }
+ return 0;
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ if (src == null) {
+ // awt.259=Source image is null
+ throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$
+ }
+
+ if (src == dst){
+ // awt.25A=Source equals to destination
+ throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$
+ }
+
+ ColorModel srcCM = src.getColorModel();
+ BufferedImage finalDst = null;
+
+ if (srcCM instanceof IndexColorModel) {
+ src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true);
+ srcCM = src.getColorModel();
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestImage(src, srcCM);
+ } else {
+ if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same
+ if (
+ !((src.getType() == BufferedImage.TYPE_INT_RGB ||
+ src.getType() == BufferedImage.TYPE_INT_ARGB) &&
+ (dst.getType() == BufferedImage.TYPE_INT_RGB ||
+ dst.getType() == BufferedImage.TYPE_INT_ARGB))
+ ) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ }
+ }
+ }
+
+ // Skip alpha channel for TYPE_INT_RGB images
+ // TODO
+ //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0)
+ if (slowFilter(src.getRaster(), dst.getRaster()) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return finalDst;
+ }
+
+ // TODO remove when this method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private int ippFilter(Raster src, WritableRaster dst, int imageType) {
+ int srcStride, dstStride;
+ boolean skipChannel = false;
+ int channels;
+ int offsets[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_RGB:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ skipChannel = true;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code?
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels
+ if (!(channels == 1 || channels == 3 || channels == 4)) {
+ return slowFilter(src, dst);
+ }
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride();
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride();
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ channels = sppsm1.getNumBands();
+
+ // TYPE_INT_RGB, TYPE_INT_ARGB...
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT ||
+ !(channels == 3 || channels == 4)
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ // Check compatibility of sample models
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst);
+ }
+ }
+
+ if (channels == 3) { // Cannot skip channel, don't know which is alpha...
+ channels = 4;
+ }
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else {
+ return slowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ return ippFilter32f(
+ kernel.data, kernel.getWidth(), kernel.getHeight(),
+ kernel.getXOrigin(), kernel.getYOrigin(), edgeCond,
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ channels, skipChannel, offsets
+ );
+ }
+
+ /**
+ * Ipp filter32f.
+ *
+ * @param kernel the kernel
+ * @param kWidth the k width
+ * @param kHeight the k height
+ * @param anchorX the anchor x
+ * @param anchorY the anchor y
+ * @param borderType the border type
+ * @param src the src
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dst the dst
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param channels the channels
+ * @param skipChannel the skip channel
+ * @param offsets the offsets
+ *
+ * @return the int
+ */
+ private native int ippFilter32f(
+ float kernel[], int kWidth, int kHeight,
+ int anchorX, int anchorY, int borderType,
+ Object src, int srcWidth, int srcHeight, int srcStride,
+ Object dst, int dstWidth, int dstHeight, int dstStride,
+ int channels, boolean skipChannel, int offsets[]
+ );
+}
+
diff --git a/awt/java/awt/image/CropImageFilter.java b/awt/java/awt/image/CropImageFilter.java
new file mode 100644
index 0000000..e90c44a
--- /dev/null
+++ b/awt/java/awt/image/CropImageFilter.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The CropImageFilter class crops a rectangular region of an source
+ * Image and provides a source for a new image containing the extracted
+ * region.
+ */
+public class CropImageFilter extends ImageFilter {
+
+ /** The HEIGHT. */
+ private final int X, Y, WIDTH, HEIGHT;
+
+ /**
+ * Instantiates a new CropImageFilter object with the specified
+ * rectangular area.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ */
+ public CropImageFilter(int x, int y, int w, int h) {
+ X = x;
+ Y = y;
+ WIDTH = w;
+ HEIGHT = h;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setProperties(Hashtable<?, ?> props) {
+ Hashtable<Object, Object> fprops;
+ if(props == null) {
+ fprops = new Hashtable<Object, Object>();
+ } else {
+ fprops = (Hashtable<Object, Object>) props.clone();
+ }
+ String propName = "Crop Filters"; //$NON-NLS-1$
+ String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$
+ Object o = fprops.get(propName);
+ if(o != null){
+ if(o instanceof String){
+ prop = (String)o + "; " + prop; //$NON-NLS-1$
+ }else{
+ prop = o.toString() + "; " + prop; //$NON-NLS-1$
+ }
+ }
+ fprops.put(propName, prop);
+ consumer.setProperties(fprops);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) {
+
+ if(x + w < X || X + WIDTH < x ||
+ y + h < Y || Y + HEIGHT < y) {
+ return;
+ }
+
+ int destX, destY, destWidth, destHeight, endX, endY,
+ srcEndX, srcEndY;
+
+ int newOffset = off;
+
+ endX = X + WIDTH;
+ endY = Y + HEIGHT;
+
+ srcEndX = x + w;
+ srcEndY = y + h;
+
+ if(x <= X){
+ destX = 0;
+ newOffset += X;
+ if(endX >= srcEndX){
+ destWidth = srcEndX - X;
+ }else{
+ destWidth = WIDTH;
+ }
+ }else{
+ destX = x - X;
+ if(endX >= srcEndX){
+ destWidth = w;
+ }else{
+ destWidth = endX - x;
+ }
+ }
+
+
+ if(y <= Y){
+ newOffset += scansize * (Y - y);
+ destY = 0;
+ if(endY >= srcEndY){
+ destHeight = srcEndY - Y;
+ }else{
+ destHeight = HEIGHT;
+ }
+ }else{
+ destY = y - Y;
+ if(endY >= srcEndY){
+ destHeight = h;
+ }else{
+ destHeight = endY - y;
+ }
+ }
+ consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) {
+
+ if(x + w < X || X + WIDTH < x ||
+ y + h < Y || Y + HEIGHT < y) {
+ return;
+ }
+
+ int destX, destY, destWidth, destHeight, endX, endY,
+ srcEndX, srcEndY;
+
+ int newOffset = off;
+
+ endX = X + WIDTH;
+ endY = Y + HEIGHT;
+
+ srcEndX = x + w;
+ srcEndY = y + h;
+
+ if(x <= X){
+ destX = 0;
+ newOffset += X;
+ if(endX >= srcEndX){
+ destWidth = srcEndX - X;
+ }else{
+ destWidth = WIDTH;
+ }
+ }else{
+ destX = x - X;
+ if(endX >= srcEndX){
+ destWidth = w;
+ }else{
+ destWidth = endX - x;
+ }
+ }
+
+
+ if(y <= Y){
+ newOffset += scansize * (Y - y);
+ destY = 0;
+ if(endY >= srcEndY){
+ destHeight = srcEndY - Y;
+ }else{
+ destHeight = HEIGHT;
+ }
+ }else{
+ destY = y - Y;
+ if(endY >= srcEndY){
+ destHeight = h;
+ }else{
+ destHeight = endY - y;
+ }
+ }
+ consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize);
+ }
+
+ @Override
+ public void setDimensions(int w, int h) {
+ consumer.setDimensions(WIDTH, HEIGHT);
+ }
+
+}
+
diff --git a/awt/java/awt/image/DataBuffer.java b/awt/java/awt/image/DataBuffer.java
new file mode 100644
index 0000000..6856aee
--- /dev/null
+++ b/awt/java/awt/image/DataBuffer.java
@@ -0,0 +1,442 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DataBuffer is a wrapper class for a data array
+ * to be used for the situation where a suite of functionality
+ * acts on a set of data in a consistent way even though the
+ * primitive type of the data may vary from one use to the next.
+ */
+public abstract class DataBuffer {
+
+ /** The Constant TYPE_BYTE. */
+ public static final int TYPE_BYTE = 0;
+
+ /** The Constant TYPE_USHORT. */
+ public static final int TYPE_USHORT = 1;
+
+ /** The Constant TYPE_SHORT. */
+ public static final int TYPE_SHORT = 2;
+
+ /** The Constant TYPE_INT. */
+ public static final int TYPE_INT = 3;
+
+ /** The Constant TYPE_FLOAT. */
+ public static final int TYPE_FLOAT = 4;
+
+ /** The Constant TYPE_DOUBLE. */
+ public static final int TYPE_DOUBLE = 5;
+
+ /** The Constant TYPE_UNDEFINED. */
+ public static final int TYPE_UNDEFINED = 32;
+
+ /** The data type indicates the primitive type of the
+ * data in this DataBuffer. */
+ protected int dataType;
+
+ /** The number of data arrays in this DataBuffer. */
+ protected int banks;
+
+ /** The starting index for reading the
+ * data from the first (or only) internal data array. */
+ protected int offset;
+
+ /** The length (number of elements) of the data arrays. */
+ protected int size;
+
+ /** The starting indices for reading the
+ * data from the internal data arrays. */
+ protected int offsets[];
+
+ /** The data changed. */
+ boolean dataChanged = true;
+
+ /** The data taken. */
+ boolean dataTaken = false;
+
+ /** The listener. */
+ DataBufferListener listener;
+
+ static {
+ AwtImageBackdoorAccessorImpl.init();
+ }
+
+ /**
+ * Instantiates a new data buffer.
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ * @param numBanks the number of data arrays to create
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = numBanks;
+ this.offsets = offsets.clone();
+ this.offset = offsets[0];
+ }
+
+ /**
+ * Instantiates a new data buffer with all of the
+ * data arrays starting at the same index.
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ * @param numBanks the number of data arrays to create
+ * @param offset the offset to use for all of the data arrays
+ */
+ protected DataBuffer(int dataType, int size, int numBanks, int offset) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = numBanks;
+ this.offset = offset;
+ this.offsets = new int[numBanks];
+ int i = 0;
+ while (i < numBanks) {
+ offsets[i++] = offset;
+ }
+ }
+
+ /**
+ * Instantiates a new data buffer with all of the
+ * data arrays read from the beginning (at offset zero).
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ protected DataBuffer(int dataType, int size, int numBanks) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = numBanks;
+ this.offset = 0;
+ this.offsets = new int[numBanks];
+ }
+
+ /**
+ * Instantiates a new data buffer with one internal data array
+ * read from the beginning (at offset zero).
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ */
+ protected DataBuffer(int dataType, int size) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = 1;
+ this.offset = 0;
+ this.offsets = new int[1];
+ }
+
+ /**
+ * Sets the data value in the specified array at the
+ * specified index.
+ *
+ * @param bank the internal array to the data to
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public abstract void setElem(int bank, int i, int val);
+
+ /**
+ * Sets the float data value in the specified array at the
+ * specified index.
+ *
+ * @param bank the internal array to the data to
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemFloat(int bank, int i, float val) {
+ setElem(bank, i, (int) val);
+ }
+
+ /**
+ * Sets the double data value in the specified array at the
+ * specified index.
+ *
+ * @param bank the internal array to the data to
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemDouble(int bank, int i, double val) {
+ setElem(bank, i, (int) val);
+ }
+
+ /**
+ * Sets the data value in the first array at the
+ * specified index.
+ *
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElem(int i, int val) {
+ setElem(0, i, val);
+ }
+
+ /**
+ * Gets the data value from the specified data array at the
+ * specified index.
+ *
+ * @param bank the data array to read from
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public abstract int getElem(int bank, int i);
+
+ /**
+ * Gets the float-type data value from the specified
+ * data array at the specified index.
+ *
+ * @param bank the data array to read from
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public float getElemFloat(int bank, int i) {
+ return getElem(bank, i);
+ }
+
+ /**
+ * Gets the double-type data value from the specified
+ * data array at the specified index.
+ *
+ * @param bank the data array to read from
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public double getElemDouble(int bank, int i) {
+ return getElem(bank, i);
+ }
+
+ /**
+ * Sets the float data value in the first array at the
+ * specified index.
+ *
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemFloat(int i, float val) {
+ setElemFloat(0, i, val);
+ }
+
+ /**
+ * Sets the double data value in the first array at the
+ * specified index.
+ *
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemDouble(int i, double val) {
+ setElemDouble(0, i, val);
+ }
+
+ /**
+ * Gets the data value from the first
+ * data array at the specified index and returns it
+ * as an int.
+ *
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public int getElem(int i) {
+ return getElem(0, i);
+ }
+
+ /**
+ * Gets the data value from the first
+ * data array at the specified index and returns it
+ * as a float.
+ *
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public float getElemFloat(int i) {
+ return getElem(0, i);
+ }
+
+ /**
+ * Gets the data value from the first
+ * data array at the specified index and returns it
+ * as a double.
+ *
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public double getElemDouble(int i) {
+ return getElem(i);
+ }
+
+ /**
+ * Gets the array giving the offsets corresponding
+ * to the internal data arrays.
+ *
+ * @return the array of offsets
+ */
+ public int[] getOffsets() {
+ return offsets;
+ }
+
+ /**
+ * Gets the size in bits of the primitive data type.
+ *
+ * @return the size in bits of the primitive data type
+
+ */
+ public int getSize() {
+ return size;
+ }
+
+ /**
+ * Gets the offset corresponding to the first internal
+ * data array.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Gets the number of data arrays in this DataBuffer.
+ *
+ * @return the number of data arrays
+ */
+ public int getNumBanks() {
+ return banks;
+ }
+
+ /**
+ * Gets the primitive type of this buffer's data.
+ *
+ * @return the data type
+ */
+ public int getDataType() {
+ return this.dataType;
+ }
+
+ /**
+ * Gets the size in bits of the primitive data type.
+ *
+ * @param type the primitive type
+ *
+ * @return the size in bits of the primitive data type
+ */
+ public static int getDataTypeSize(int type) {
+ switch (type) {
+
+ case TYPE_BYTE:
+ return 8;
+
+ case TYPE_USHORT:
+ case TYPE_SHORT:
+ return 16;
+
+ case TYPE_INT:
+ case TYPE_FLOAT:
+ return 32;
+
+ case TYPE_DOUBLE:
+ return 64;
+
+ default:
+ // awt.22C=Unknown data type {0}
+ throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Notifies the listener that the data has changed.
+ */
+ void notifyChanged(){
+ if(listener != null && !dataChanged){
+ dataChanged = true;
+ listener.dataChanged();
+ }
+ }
+
+ /**
+ * Notifies the listener that the data has been released.
+ */
+ void notifyTaken(){
+ if(listener != null && !dataTaken){
+ dataTaken = true;
+ listener.dataTaken();
+ }
+ }
+
+ /**
+ * Release the data.
+ */
+ void releaseData(){
+ if(listener != null && dataTaken){
+ dataTaken = false;
+ listener.dataReleased();
+ }
+ }
+
+ /**
+ * Adds the data buffer listener.
+ *
+ * @param listener the listener
+ */
+ void addDataBufferListener(DataBufferListener listener){
+ this.listener = listener;
+ }
+
+ /**
+ * Removes the data buffer listener.
+ */
+ void removeDataBufferListener(){
+ listener = null;
+ }
+
+ /**
+ * Validate.
+ */
+ void validate(){
+ dataChanged = false;
+ }
+
+}
+
diff --git a/awt/java/awt/image/DataBufferByte.java b/awt/java/awt/image/DataBufferByte.java
new file mode 100644
index 0000000..4d29c9c
--- /dev/null
+++ b/awt/java/awt/image/DataBufferByte.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferByte is the subclass of DataBuffer
+ * for the case where the underlying data is of type byte.
+ */
+public final class DataBufferByte extends DataBuffer {
+
+ /** The data. */
+ byte data[][];
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferByte(byte dataArrays[][], int size, int offsets[]) {
+ super(TYPE_BYTE, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferByte(byte dataArrays[][], int size) {
+ super(TYPE_BYTE, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferByte(byte dataArray[], int size, int offset) {
+ super(TYPE_BYTE, size, 1, offset);
+ data = new byte[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferByte(byte dataArray[], int size) {
+ super(TYPE_BYTE, size);
+ data = new byte[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferByte(int size, int numBanks) {
+ super(TYPE_BYTE, size, numBanks);
+ data = new byte[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new byte[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferByte(int size) {
+ super(TYPE_BYTE, size);
+ data = new byte[1][];
+ data[0] = new byte[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = (byte) val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = (byte) val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (data[bank][offsets[bank] + i]) & 0xff;
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public byte[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (data[0][offset + i]) & 0xff;
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public byte[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+
+}
+
diff --git a/awt/java/awt/image/DataBufferDouble.java b/awt/java/awt/image/DataBufferDouble.java
new file mode 100644
index 0000000..fa3d324
--- /dev/null
+++ b/awt/java/awt/image/DataBufferDouble.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferDouble is the subclass of DataBuffer
+ * for the case where the underlying data is of type double.
+ */
+public final class DataBufferDouble extends DataBuffer {
+
+ /** The data. */
+ double data[][];
+
+ /**
+ * Instantiates a new data buffer of type double.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferDouble(double dataArrays[][], int size, int offsets[]) {
+ super(TYPE_DOUBLE, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type double.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferDouble(double dataArrays[][], int size) {
+ super(TYPE_DOUBLE, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type double
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferDouble(double dataArray[], int size, int offset) {
+ super(TYPE_DOUBLE, size, 1, offset);
+ data = new double[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type double
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferDouble(double dataArray[], int size) {
+ super(TYPE_DOUBLE, size);
+ data = new double[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type double
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferDouble(int size, int numBanks) {
+ super(TYPE_DOUBLE, size, numBanks);
+ data = new double[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new double[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type double
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferDouble(int size) {
+ super(TYPE_DOUBLE, size);
+ data = new double[1][];
+ data[0] = new double[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemFloat(int bank, int i, float val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int bank, int i, double val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (int) (data[bank][offsets[bank] + i]);
+ }
+
+ @Override
+ public float getElemFloat(int bank, int i) {
+ return (float) (data[bank][offsets[bank] + i]);
+ }
+
+ @Override
+ public double getElemDouble(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ @Override
+ public void setElemFloat(int i, float val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int i, double val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public double[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (int) (data[0][offset + i]);
+ }
+
+ @Override
+ public float getElemFloat(int i) {
+ return (float) (data[0][offset + i]);
+ }
+
+ @Override
+ public double getElemDouble(int i) {
+ return data[0][offset + i];
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public double[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public double[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferFloat.java b/awt/java/awt/image/DataBufferFloat.java
new file mode 100644
index 0000000..e34245c
--- /dev/null
+++ b/awt/java/awt/image/DataBufferFloat.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferFloat is the subclass of DataBuffer
+ * for the case where the underlying data is float.
+ */
+public final class DataBufferFloat extends DataBuffer {
+
+ /** The data. */
+ float data[][];
+
+ /**
+ * Instantiates a new data buffer of type float.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferFloat(float dataArrays[][], int size, int offsets[]) {
+ super(TYPE_FLOAT, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type float.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferFloat(float dataArrays[][], int size) {
+ super(TYPE_FLOAT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type float
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferFloat(float dataArray[], int size, int offset) {
+ super(TYPE_FLOAT, size, 1, offset);
+ data = new float[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type float
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferFloat(float dataArray[], int size) {
+ super(TYPE_FLOAT, size);
+ data = new float[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type float
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferFloat(int size, int numBanks) {
+ super(TYPE_FLOAT, size, numBanks);
+ data = new float[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new float[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type float
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferFloat(int size) {
+ super(TYPE_FLOAT, size);
+ data = new float[1][];
+ data[0] = new float[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemFloat(int bank, int i, float val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int bank, int i, double val) {
+ data[bank][offsets[bank] + i] = (float) val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (int) (data[bank][offsets[bank] + i]);
+ }
+
+ @Override
+ public float getElemFloat(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ @Override
+ public double getElemDouble(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ @Override
+ public void setElemFloat(int i, float val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int i, double val) {
+ data[0][offset + i] = (float) val;
+ notifyChanged();
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired array
+ *
+ * @return the data
+ */
+ public float[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (int) (data[0][offset + i]);
+ }
+
+ @Override
+ public float getElemFloat(int i) {
+ return data[0][offset + i];
+ }
+
+ @Override
+ public double getElemDouble(int i) {
+ return data[0][offset + i];
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public float[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public float[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferInt.java b/awt/java/awt/image/DataBufferInt.java
new file mode 100644
index 0000000..43dc188
--- /dev/null
+++ b/awt/java/awt/image/DataBufferInt.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferInt is the subclass of DataBuffer
+ * for the case where the underlying data is of type int.
+ */
+public final class DataBufferInt extends DataBuffer {
+
+ /** The data. */
+ int data[][];
+
+ /**
+ * Instantiates a new data buffer of type int.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferInt(int dataArrays[][], int size, int offsets[]) {
+ super(TYPE_INT, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type int.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferInt(int dataArrays[][], int size) {
+ super(TYPE_INT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type int
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferInt(int dataArray[], int size, int offset) {
+ super(TYPE_INT, size, 1, offset);
+ data = new int[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type int
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferInt(int dataArray[], int size) {
+ super(TYPE_INT, size);
+ data = new int[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type int
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferInt(int size, int numBanks) {
+ super(TYPE_INT, size, numBanks);
+ data = new int[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new int[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type int
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferInt(int size) {
+ super(TYPE_INT, size);
+ data = new int[1][];
+ data[0] = new int[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public int[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return data[0][offset + i];
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public int[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public int[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferShort.java b/awt/java/awt/image/DataBufferShort.java
new file mode 100644
index 0000000..819ba4a
--- /dev/null
+++ b/awt/java/awt/image/DataBufferShort.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferShort is the subclass of DataBuffer
+ * for the case where the underlying data is short.
+ */
+public final class DataBufferShort extends DataBuffer {
+
+ /** The data. */
+ short data[][];
+
+ /**
+ * Instantiates a new data buffer of type short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferShort(short dataArrays[][], int size, int offsets[]) {
+ super(TYPE_SHORT, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferShort(short dataArrays[][], int size) {
+ super(TYPE_SHORT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type short
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+
+ */
+ public DataBufferShort(short dataArray[], int size, int offset) {
+ super(TYPE_SHORT, size, 1, offset);
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+
+ */
+ public DataBufferShort(short dataArray[], int size) {
+ super(TYPE_SHORT, size);
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type short
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferShort(int size, int numBanks) {
+ super(TYPE_SHORT, size, numBanks);
+ data = new short[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new short[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferShort(int size) {
+ super(TYPE_SHORT, size);
+ data = new short[1][];
+ data[0] = new short[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = (short) val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = (short) val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (data[bank][offsets[bank] + i]);
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public short[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (data[0][offset + i]);
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public short[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public short[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferUShort.java b/awt/java/awt/image/DataBufferUShort.java
new file mode 100644
index 0000000..7982678
--- /dev/null
+++ b/awt/java/awt/image/DataBufferUShort.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DataBufferUShort is the subclass of DataBuffer
+ * for the case where the underlying data is unsigned short.
+ */
+public final class DataBufferUShort extends DataBuffer {
+
+ /** The data. */
+ short data[][];
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferUShort(short dataArrays[][], int size, int offsets[]) {
+ super(TYPE_USHORT, size, dataArrays.length, offsets);
+ for(int i = 0; i < dataArrays.length; i++){
+ if(dataArrays[i].length < offsets[i] + size){
+ // awt.28d=Length of dataArray[{0}] is less than size + offset[{1}]
+ throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$
+ }
+ }
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferUShort(short dataArrays[][], int size) {
+ super(TYPE_USHORT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferUShort(short dataArray[], int size, int offset) {
+ super(TYPE_USHORT, size, 1, offset);
+ if(dataArray.length < size + offset){
+ // awt.28E=Length of dataArray is less than size + offset
+ throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$
+ }
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferUShort(short dataArray[], int size) {
+ super(TYPE_USHORT, size);
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferUShort(int size, int numBanks) {
+ super(TYPE_USHORT, size, numBanks);
+ data = new short[numBanks][];
+ int i= 0;
+ while( i < numBanks) {
+ data[i++] = new short[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferUShort(int size) {
+ super(TYPE_USHORT, size);
+ data = new short[1][];
+ data[0] = new short[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = (short)val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = (short)val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (data[bank][offsets[bank] + i]) & 0xffff;
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public short[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (data[0][offset + i]) & 0xffff;
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public short[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public short[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DirectColorModel.java b/awt/java/awt/image/DirectColorModel.java
new file mode 100644
index 0000000..7a287c0
--- /dev/null
+++ b/awt/java/awt/image/DirectColorModel.java
@@ -0,0 +1,862 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.color.ColorSpace;
+import java.awt.Transparency;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DirectColorModel represents a standard (packed) RGB
+ * color model with additional support for converting between sRGB
+ * color space and 8 or 16 bit linear RGB color space using lookup tables.
+ */
+public class DirectColorModel extends PackedColorModel {
+
+ /** The from_ linea r_ rg b_ lut. */
+ private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from
+ // Linear RGB Color Space into sRGB
+
+ /** The to_ linea r_8 rg b_ lut. */
+ private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 8 bit
+
+ /** The to_ linea r_16 rg b_ lut. */
+ private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 16 bit
+
+ /** The alpha lut. */
+ private byte alphaLUT[]; // Lookup table for scale alpha value
+
+ /** The color lu ts. */
+ private byte colorLUTs[][]; // Lookup tables for scale color values
+
+ /** The is_s rgb. */
+ private boolean is_sRGB; // ColorModel has sRGB ColorSpace
+
+ /** The is_ linea r_ rgb. */
+ private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color
+ // Space
+
+ /** The LINEA r_ rg b_ length. */
+ private int LINEAR_RGB_Length; // Linear RGB bit length
+
+ /** The factor. */
+ private float fFactor; // Scale factor
+
+ /**
+ * Instantiates a new direct color model.
+ *
+ * @param space the color space
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ * @param amask the bitmask corresponding to the alpha band
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the number of bits in the combined
+ * bitmasks for the color bands is less than one or greater than 32
+ */
+ public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask,
+ int bmask, int amask, boolean isAlphaPremultiplied,
+ int transferType) {
+
+ super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied,
+ (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT),
+ transferType);
+
+ initLUTs();
+ }
+
+ /**
+ * Instantiates a new direct color model, determining the transfer
+ * type from the bits array, the transparency from the alpha mask,
+ * and the default color space {@link ColorSpace#CS_sRGB}.
+ *
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ * @param amask the bitmask corresponding to the alpha band
+ */
+ public DirectColorModel(int bits, int rmask, int gmask, int bmask,
+ int amask) {
+
+ super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask,
+ bmask, amask, false,
+ (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT),
+ ColorModel.getTransferType(bits));
+
+ initLUTs();
+ }
+
+ /**
+ * Instantiates a new direct color model with no alpha channel,
+ * determining the transfer type from the bits array,
+ * the default color space {@link ColorSpace#CS_sRGB},
+ * and with the transparency set to {@link Transparency#OPAQUE}.
+ *
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ */
+ public DirectColorModel(int bits, int rmask, int gmask, int bmask) {
+ this(bits, rmask, gmask, bmask, 0);
+ }
+
+ @Override
+ public Object getDataElements(int components[], int offset, Object obj) {
+ int pixel = 0;
+ for (int i = 0; i < numComponents; i++) {
+ pixel |= (components[offset + i] << offsets[i]) & componentMasks[i];
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (obj == null) {
+ ba = new byte[1];
+ } else {
+ ba = (byte[]) obj;
+ }
+ ba[0] = (byte) pixel;
+ obj = ba;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[];
+ if (obj == null) {
+ sa = new short[1];
+ } else {
+ sa = (short[]) obj;
+ }
+ sa[0] = (short) pixel;
+ obj = sa;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (obj == null) {
+ ia = new int[1];
+ } else {
+ ia = (int[]) obj;
+ }
+ ia[0] = pixel;
+ obj = ia;
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+
+ return obj;
+ }
+
+ @Override
+ public Object getDataElements(int rgb, Object pixel) {
+ if (equals(ColorModel.getRGBdefault())) {
+ int ia[];
+ if (pixel == null) {
+ ia = new int[1];
+ } else {
+ ia = (int[]) pixel;
+ }
+ ia[0] = rgb;
+ return ia;
+ }
+
+ int alpha = (rgb >> 24) & 0xff;
+ int red = (rgb >> 16) & 0xff;
+ int green = (rgb >> 8) & 0xff;
+ int blue = rgb & 0xff;
+
+ float comp[] = new float[numColorComponents];
+ float normComp[] = null;
+
+ if (is_sRGB || is_LINEAR_RGB) {
+ if (is_LINEAR_RGB) {
+ if (LINEAR_RGB_Length == 8) {
+ red = to_LINEAR_8RGB_LUT[red] & 0xff;
+ green = to_LINEAR_8RGB_LUT[green] & 0xff;
+ blue = to_LINEAR_8RGB_LUT[blue] & 0xff;
+ } else {
+ red = to_LINEAR_16RGB_LUT[red] & 0xffff;
+ green = to_LINEAR_16RGB_LUT[green] & 0xffff;
+ blue = to_LINEAR_16RGB_LUT[blue] & 0xffff;
+ }
+ }
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ if (!hasAlpha) {
+ normComp = comp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = comp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ } else {
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ float rgbComp[] = cs.fromRGB(comp);
+ if (!hasAlpha) {
+ normComp = rgbComp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = rgbComp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ }
+
+ int pxl = 0;
+ if (hasAlpha) {
+ float normAlpha = normComp[numColorComponents];
+ alpha = (int) (normAlpha * maxValues[numColorComponents] + 0.5f);
+ if (isAlphaPremultiplied) {
+ red = (int) (normComp[0] * normAlpha * maxValues[0] + 0.5f);
+ green = (int) (normComp[1] * normAlpha * maxValues[1] + 0.5f);
+ blue = (int) (normComp[2] * normAlpha * maxValues[2] + 0.5f);
+ } else {
+ red = (int) (normComp[0] * maxValues[0] + 0.5f);
+ green = (int) (normComp[1] * maxValues[1] + 0.5f);
+ blue = (int) (normComp[2] * maxValues[2] + 0.5f);
+ }
+ pxl = (alpha << offsets[3]) & componentMasks[3];
+ } else {
+ red = (int) (normComp[0] * maxValues[0] + 0.5f);
+ green = (int) (normComp[1] * maxValues[1] + 0.5f);
+ blue = (int) (normComp[2] * maxValues[2] + 0.5f);
+ }
+
+ pxl |= ((red << offsets[0]) & componentMasks[0]) |
+ ((green << offsets[1]) & componentMasks[1]) |
+ ((blue << offsets[2]) & componentMasks[2]);
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (pixel == null) {
+ ba = new byte[1];
+ } else {
+ ba = (byte[]) pixel;
+ }
+ ba[0] = (byte) pxl;
+ return ba;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[];
+ if (pixel == null) {
+ sa = new short[1];
+ } else {
+ sa = (short[]) pixel;
+ }
+ sa[0] = (short) pxl;
+ return sa;
+
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (pixel == null) {
+ ia = new int[1];
+ } else {
+ ia = (int[]) pixel;
+ }
+ ia[0] = pxl;
+ return ia;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public final ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied) {
+
+ if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) {
+ return this;
+ }
+
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ int components[] = null;
+ int transparentComponents[] = new int[numComponents];
+
+ float alphaFactor = maxValues[numColorComponents];
+
+ if (isAlphaPremultiplied) {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ components = raster.getPixel(x, minY, components);
+ if (components[numColorComponents] == 0) {
+ raster.setPixel(x, minY, transparentComponents);
+ } else {
+ float alpha =
+ components[numColorComponents] /
+ alphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ components[n] =
+ (int) (alpha * components[n] + 0.5f);
+ }
+ raster.setPixel(x, minY, components);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ } else {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ components = raster.getPixel(x, minY, components);
+ if (components[numColorComponents] != 0) {
+ float alpha =
+ alphaFactor / components[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ components[n] =
+ (int) (alpha * components[n] + 0.5f);
+ }
+ raster.setPixel(x, minY, components);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+
+ }
+
+ return new DirectColorModel(cs, pixel_bits, componentMasks[0],
+ componentMasks[1], componentMasks[2], componentMasks[3],
+ isAlphaPremultiplied, transferType);
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour.
+ // It could be reveled such way:
+ // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ // ColorModel cm = bi.getColorModel();
+ // System.out.println(cm.toString());
+ String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$
+ Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$
+ Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$
+ Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$
+ (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$
+
+ return str;
+ }
+
+ @Override
+ public final int[] getComponents(Object pixel, int components[],
+ int offset) {
+
+ if (components == null) {
+ components = new int[numComponents + offset];
+ }
+
+ int intPixel = 0;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ intPixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) pixel;
+ intPixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ intPixel = ia[0];
+ break;
+
+ default:
+ // awt.22D=This transferType ( {0} ) is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$
+ transferType));
+ }
+
+ return getComponents(intPixel, components, offset);
+ }
+
+ @Override
+ public int getRed(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getRed(pixel);
+ }
+
+ @Override
+ public int getRGB(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getRGB(pixel);
+ }
+
+ @Override
+ public int getGreen(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getGreen(pixel);
+ }
+
+ @Override
+ public int getBlue(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getBlue(pixel);
+ }
+
+ @Override
+ public int getAlpha(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getAlpha(pixel);
+ }
+
+ @Override
+ public final WritableRaster createCompatibleWritableRaster(int w, int h) {
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ int bandMasks[] = componentMasks.clone();
+
+ if (pixel_bits > 16) {
+ return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h,
+ bandMasks, null);
+ } else if (pixel_bits > 8) {
+ return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h,
+ bandMasks, null);
+ } else {
+ return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h,
+ bandMasks, null);
+ }
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ SampleModel sm = raster.getSampleModel();
+ if (!(sm instanceof SinglePixelPackedSampleModel)) {
+ return false;
+ }
+
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+
+ if (sppsm.getNumBands() != numComponents) {
+ return false;
+ }
+ if (raster.getTransferType() != transferType) {
+ return false;
+ }
+
+ int maskBands[] = sppsm.getBitMasks();
+ return Arrays.equals(maskBands, componentMasks);
+ }
+
+ @Override
+ public int getDataElement(int components[], int offset) {
+ int pixel = 0;
+ for (int i = 0; i < numComponents; i++) {
+ pixel |= (components[offset + i] << offsets[i]) & componentMasks[i];
+ }
+ return pixel;
+ }
+
+ @Override
+ public final int[] getComponents(int pixel, int components[], int offset) {
+ if (components == null) {
+ components = new int[numComponents + offset];
+ }
+ for (int i = 0; i < numComponents; i++) {
+ components[offset + i] = (pixel & componentMasks[i]) >> offsets[i];
+ }
+ return components;
+ }
+
+ @Override
+ public final int getRed(int pixel) {
+ if (is_sRGB) {
+ return getComponentFrom_sRGB(pixel, 0);
+ }
+ if (is_LINEAR_RGB) {
+ return getComponentFrom_LINEAR_RGB(pixel, 0);
+ }
+ return getComponentFrom_RGB(pixel, 0);
+ }
+
+ @Override
+ public final int getRGB(int pixel) {
+ return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) |
+ (getGreen(pixel) << 8) | getBlue(pixel);
+ }
+
+ @Override
+ public final int getGreen(int pixel) {
+ if (is_sRGB) {
+ return getComponentFrom_sRGB(pixel, 1);
+ }
+ if (is_LINEAR_RGB) {
+ return getComponentFrom_LINEAR_RGB(pixel, 1);
+ }
+ return getComponentFrom_RGB(pixel, 1);
+ }
+
+ @Override
+ public final int getBlue(int pixel) {
+ if (is_sRGB) {
+ return getComponentFrom_sRGB(pixel, 2);
+ }
+ if (is_LINEAR_RGB) {
+ return getComponentFrom_LINEAR_RGB(pixel, 2);
+ }
+ return getComponentFrom_RGB(pixel, 2);
+ }
+
+ @Override
+ public final int getAlpha(int pixel) {
+ if (!hasAlpha) {
+ return 255;
+ }
+ int a = (pixel & componentMasks[3]) >>> offsets[3];
+ if (bits[3] == 8) {
+ return a;
+ }
+ return alphaLUT[a] & 0xff;
+ }
+
+ /**
+ * Gets the red mask.
+ *
+ * @return the red mask
+ */
+ public final int getRedMask() {
+ return componentMasks[0];
+ }
+
+ /**
+ * Gets the green mask.
+ *
+ * @return the green mask
+ */
+ public final int getGreenMask() {
+ return componentMasks[1];
+ }
+
+ /**
+ * Gets the blue mask.
+ *
+ * @return the blue mask
+ */
+ public final int getBlueMask() {
+ return componentMasks[2];
+ }
+
+ /**
+ * Gets the alpha mask.
+ *
+ * @return the alpha mask
+ */
+ public final int getAlphaMask() {
+ if (hasAlpha) {
+ return componentMasks[3];
+ }
+ return 0;
+ }
+
+ /**
+ * Initialization of Lookup tables.
+ */
+ private void initLUTs() {
+ is_sRGB = cs.isCS_sRGB();
+ is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS);
+
+ if (is_LINEAR_RGB) {
+ if (maxBitLength > 8) {
+ LINEAR_RGB_Length = 16;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom16lRGBtosRGB_LUT();
+ to_LINEAR_16RGB_LUT =
+ LUTColorConverter.getFromsRGBto16lRGB_LUT();
+ } else {
+ LINEAR_RGB_Length = 8;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom8lRGBtosRGB_LUT();
+ to_LINEAR_8RGB_LUT =
+ LUTColorConverter.getFromsRGBto8lRGB_LUT();
+ }
+ fFactor = ((1 << LINEAR_RGB_Length) - 1);
+ } else {
+ fFactor = 255.0f;
+ }
+
+ if (hasAlpha && bits[3] != 8) {
+ alphaLUT = new byte[maxValues[3] + 1];
+ for (int i = 0; i <= maxValues[3]; i++) {
+ alphaLUT[i] = (byte) (scales[3] * i + 0.5f);
+ }
+
+ }
+
+ if (!isAlphaPremultiplied) {
+ colorLUTs = new byte[3][];
+
+ if (is_sRGB) {
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != 8) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[i]; j++) {
+ colorLUTs[i][j] = (byte) (scales[i] * j + 0.5f);
+ }
+ }
+ }
+ }
+
+ if (is_LINEAR_RGB) {
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != LINEAR_RGB_Length) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[0]; j++) {
+ int idx;
+ if (LINEAR_RGB_Length == 8) {
+ idx = (int) (scales[i] * j + 0.5f);
+ } else {
+ idx = (int) (scales[i] * j * 257.0f + 0.5f);
+ }
+ colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx];
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * This method return RGB component value if Color Model has
+ * sRGB ColorSpace.
+ *
+ * @param pixel - INT representation of pixel
+ * @param idx - index of pixel component
+ *
+ * @return - value of the pixel component scaled fro 0 to 255
+ */
+ private int getComponentFrom_sRGB(int pixel, int idx) {
+ int comp = (pixel & componentMasks[idx]) >> offsets[idx];
+ if (isAlphaPremultiplied) {
+ int alpha = (pixel & componentMasks[3]) >>> offsets[3];
+ comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * 255.0f /
+ (scales[3] * alpha) + 0.5f);
+ } else if (bits[idx] != 8) {
+ comp = colorLUTs[idx][comp] & 0xff;
+ }
+ return comp;
+ }
+
+ /**
+ * This method return RGB component value if Color Model has
+ * Linear RGB ColorSpace.
+ *
+ * @param pixel - INT representation of pixel
+ * @param idx - index of pixel component
+ *
+ * @return - value of the pixel component scaled fro 0 to 255
+ */
+ private int getComponentFrom_LINEAR_RGB(int pixel, int idx) {
+ int comp = (pixel & componentMasks[idx]) >> offsets[idx];
+ if (isAlphaPremultiplied) {
+ float factor = ((1 << LINEAR_RGB_Length) - 1);
+ int alpha = (pixel & componentMasks[3]) >> offsets[3];
+ comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * factor /
+ (scales[3] * alpha) + 0.5f);
+ } else if (bits[idx] != LINEAR_RGB_Length) {
+ comp = colorLUTs[idx][comp] & 0xff;
+ } else {
+ comp = from_LINEAR_RGB_LUT[comp] & 0xff;
+ }
+ return comp;
+ }
+
+ /**
+ * This method return RGB component value if Color Model has
+ * arbitrary RGB ColorSapce.
+ *
+ * @param pixel - INT representation of pixel
+ * @param idx - index of pixel component
+ *
+ * @return - value of the pixel component scaled fro 0 to 255
+ */
+ private int getComponentFrom_RGB(int pixel, int idx) {
+ int components[] = getComponents(pixel, null, 0);
+ float[] normComponents = getNormalizedComponents(components, 0, null, 0);
+ float[] sRGBcomponents = cs.toRGB(normComponents);
+ return (int) (sRGBcomponents[idx] * 255.0f + 0.5f);
+ }
+
+}
+
diff --git a/awt/java/awt/image/FilteredImageSource.java b/awt/java/awt/image/FilteredImageSource.java
new file mode 100644
index 0000000..6a41fa7
--- /dev/null
+++ b/awt/java/awt/image/FilteredImageSource.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+
+/**
+ * The FilteredImageSource class is used for producing image data for a new
+ * filtered version of the original image using the specified filter object.
+ */
+public class FilteredImageSource implements ImageProducer {
+
+ /** The source. */
+ private final ImageProducer source;
+
+ /** The filter. */
+ private final ImageFilter filter;
+
+ /** The cons table. */
+ private final Hashtable<ImageConsumer, ImageConsumer> consTable = new Hashtable<ImageConsumer, ImageConsumer>();
+
+ /**
+ * Instantiates a new FilteredImageSource object with
+ * the specified ImageProducer and the ImageFilter objects.
+ *
+ * @param orig the specified ImageProducer.
+ * @param imgf the specified ImageFilter.
+ */
+ public FilteredImageSource(ImageProducer orig, ImageFilter imgf) {
+ source = orig;
+ filter = imgf;
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ if(ic != null) {
+ return consTable.containsKey(ic);
+ }
+ return false;
+ }
+
+ public void startProduction(ImageConsumer ic) {
+ addConsumer(ic);
+ ImageConsumer fic = consTable.get(ic);
+ source.startProduction(fic);
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {
+ if(ic != null && isConsumer(ic)){
+ ImageFilter fic = (ImageFilter) consTable.get(ic);
+ fic.resendTopDownLeftRight(source);
+ }
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ if(ic != null && isConsumer(ic)){
+ ImageConsumer fic = consTable.get(ic);
+ source.removeConsumer(fic);
+ consTable.remove(ic);
+ }
+ }
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if(ic != null && !isConsumer(ic)){
+ ImageConsumer fic = filter.getFilterInstance(ic);
+ source.addConsumer(fic);
+ consTable.put(ic, fic);
+ }
+ }
+}
diff --git a/awt/java/awt/image/ImageConsumer.java b/awt/java/awt/image/ImageConsumer.java
new file mode 100644
index 0000000..2eba290
--- /dev/null
+++ b/awt/java/awt/image/ImageConsumer.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The ImageConsumer interface provides the data about the image
+ * and about how its data is delivered. A ImageProducer provides
+ * all of the information about the image using
+ * the methods defined in this interface.
+ */
+public interface ImageConsumer {
+
+ /**
+ * The Constant RANDOMPIXELORDER indicates that the pixels are
+ * delivered in a random order.
+ */
+ public static final int RANDOMPIXELORDER = 1;
+
+ /**
+ * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are
+ * delivered in top-down, left-to-right order.
+ */
+ public static final int TOPDOWNLEFTRIGHT = 2;
+
+ /**
+ * The Constant COMPLETESCANLINES indicates that the pixels are
+ * delivered in complete scanline.
+ */
+ public static final int COMPLETESCANLINES = 4;
+
+ /**
+ * The Constant SINGLEPASS indicates that pixels are delivered
+ * in a single pass.
+ */
+ public static final int SINGLEPASS = 8;
+
+ /**
+ * The Constant SINGLEFRAME indicates that image consists of
+ * single frame.
+ */
+ public static final int SINGLEFRAME = 16;
+
+ /**
+ * The Constant IMAGEERROR indicates an image error during image producing.
+ */
+ public static final int IMAGEERROR = 1;
+
+ /**
+ * The Constant SINGLEFRAMEDONE indicates that only one of the
+ * image's frames is completed.
+ */
+ public static final int SINGLEFRAMEDONE = 2;
+
+ /**
+ * The Constant STATICIMAGEDONE indicates that the image is completed.
+ */
+ public static final int STATICIMAGEDONE = 3;
+
+ /**
+ * The Constant IMAGEABORTED indicates that the image producing
+ * process is aborted.
+ */
+ public static final int IMAGEABORTED = 4;
+
+ /**
+ * Sets the properties for the image associated with this ImageConsumer.
+ *
+ * @param props the properties for the image associated with
+ * this ImageConsumer.
+ */
+ public void setProperties(Hashtable<?, ?> props);
+
+ /**
+ * Sets the ColorModel object.
+ *
+ * @param model the new ColorModel.
+ */
+ public void setColorModel(ColorModel model);
+
+ /**
+ * Sets the pixels for the specified rectangular area of the image.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param model the specified ColorModel to be used for pixels
+ * converting.
+ * @param pixels the array of pixels.
+ * @param off the offset of pixels array.
+ * @param scansize the distance from the one row of pixels
+ * to the next row in the specified array.
+ */
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ int[] pixels, int off, int scansize);
+
+ /**
+ * Sets the pixels for the specified rectangular area of the image.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param model the specified ColorModel to be used for pixels
+ * converting.
+ * @param pixels the array of pixels.
+ * @param off the offset of pixels array.
+ * @param scansize the distance from the one row of pixels
+ * to the next row in the specified array.
+ */
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ byte[] pixels, int off, int scansize);
+
+ /**
+ * Sets the dimensions of a source image.
+ *
+ * @param width the width of the image.
+ * @param height the height of the image.
+ */
+ public void setDimensions(int width, int height);
+
+ /**
+ * Sets the hint flags of pixels order, which is used by
+ * the ImageConsumer for obtaining pixels from the ImageProducer
+ * for which this ImageConsumer is added.
+ *
+ * @param hintflags the mask of hint flags.
+ */
+ public void setHints(int hintflags);
+
+ /**
+ * THis method is called in the one of the following cases:
+ * <ul>
+ * <li>The ImageProducer (for which this ImageConsumer is added)
+ * has been delivered all pixels of the source image. </li>
+ * <li>A one frame of an animation has been completed. </li>
+ * <li> An error while loading or producing of the image has occured.
+ * </ul>
+ *
+ * @param status the status of image producing.
+ */
+ public void imageComplete(int status);
+
+}
+
diff --git a/awt/java/awt/image/ImageFilter.java b/awt/java/awt/image/ImageFilter.java
new file mode 100644
index 0000000..e386d65
--- /dev/null
+++ b/awt/java/awt/image/ImageFilter.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The ImageFilter class provides a filter for delivering image data
+ * from an ImageProducer to an ImageConsumer.
+ */
+public class ImageFilter implements ImageConsumer, Cloneable {
+
+ /** The consumer. */
+ protected ImageConsumer consumer;
+
+ /**
+ * Instantiates a new ImageFilter.
+ */
+ public ImageFilter() {
+ super();
+ }
+
+ /**
+ * Gets an instance of an ImageFilter object which performs
+ * the filtering for the specified ImageConsumer.
+ *
+ * @param ic the specified ImageConsumer.
+ *
+ * @return an ImageFilter used to perform the filtering for
+ * the specified ImageConsumer.
+ */
+ public ImageFilter getFilterInstance(ImageConsumer ic) {
+ ImageFilter filter = (ImageFilter) clone();
+ filter.consumer = ic;
+ return filter;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void setProperties(Hashtable<?, ?> props) {
+ Hashtable<Object, Object> fprops;
+ if (props == null) {
+ fprops = new Hashtable<Object, Object>();
+ } else {
+ fprops = (Hashtable<Object, Object>) props.clone();
+ }
+ String propName = "Filters"; //$NON-NLS-1$
+ String prop = "Null filter"; //$NON-NLS-1$
+ Object o = fprops.get(propName);
+ if (o != null) {
+ if (o instanceof String) {
+ prop = (String) o + "; " + prop; //$NON-NLS-1$
+ } else {
+ prop = o.toString() + "; " + prop; //$NON-NLS-1$
+ }
+ }
+ fprops.put(propName, prop);
+ consumer.setProperties(fprops);
+ }
+
+ /**
+ * Returns a copy of this ImageFilter.
+ *
+ * @return a copy of this ImageFilter.
+ */
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Responds to a request for a Top-Down-Left-Right ordered
+ * resend of the pixel data from an ImageConsumer.
+ *
+ * @param ip the ImageProducer that provides this instance of
+ * the filter.
+ */
+ public void resendTopDownLeftRight(ImageProducer ip) {
+ ip.requestTopDownLeftRightResend(this);
+ }
+
+ public void setColorModel(ColorModel model) {
+ consumer.setColorModel(model);
+ }
+
+ public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+ int scansize) {
+ consumer.setPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+
+ public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+ int scansize) {
+ consumer.setPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+
+ public void setDimensions(int width, int height) {
+ consumer.setDimensions(width, height);
+ }
+
+ public void setHints(int hints) {
+ consumer.setHints(hints);
+ }
+
+ public void imageComplete(int status) {
+ consumer.imageComplete(status);
+ }
+
+}
diff --git a/awt/java/awt/image/ImageObserver.java b/awt/java/awt/image/ImageObserver.java
new file mode 100644
index 0000000..418bd07
--- /dev/null
+++ b/awt/java/awt/image/ImageObserver.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Image;
+
+/**
+ * the ImageObserver interface is an asynchronous update interface
+ * for receiving notifications about Image construction status.
+ */
+public interface ImageObserver {
+
+ /**
+ * The Constant WIDTH indicates that the width of the image is
+ * available.
+ */
+ public static final int WIDTH = 1;
+
+ /**
+ * The Constant HEIGHT indicates that the width of the image is
+ * available.
+ */
+ public static final int HEIGHT = 2;
+
+ /**
+ * The Constant PROPERTIES indicates that the properties of the image
+ * are available.
+ */
+ public static final int PROPERTIES = 4;
+
+ /**
+ * The Constant SOMEBITS indicates that more bits needed for
+ * drawing a scaled variation of the image pixels are available.
+ */
+ public static final int SOMEBITS = 8;
+
+ /**
+ * The Constant FRAMEBITS indicates that complete frame of
+ * a image which was previously drawn is now available
+ * for drawing again.
+ */
+ public static final int FRAMEBITS = 16;
+
+ /**
+ * The Constant ALLBITS indicates that an image which
+ * was previously drawn is now complete and can be drawn again.
+ */
+ public static final int ALLBITS = 32;
+
+ /**
+ * The Constant ERROR indicates that error occured.
+ */
+ public static final int ERROR = 64;
+
+ /**
+ * The Constant ABORT indicates that the image producing is
+ * aborted.
+ */
+ public static final int ABORT = 128;
+
+ /**
+ * This method is called when information about an Image
+ * interface becomes available. This method returns true
+ * if further updates are needed, false if not.
+ *
+ * @param img the image to be observed.
+ * @param infoflags the bitwise OR combination of information flags:
+ * ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS,
+ * WIDTH.
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ * @param width the width.
+ * @param height the height.
+ *
+ * @return true if further updates are needed, false if not.
+ */
+ public boolean imageUpdate(Image img, int infoflags, int x, int y,
+ int width, int height);
+
+}
+
diff --git a/awt/java/awt/image/ImageProducer.java b/awt/java/awt/image/ImageProducer.java
new file mode 100644
index 0000000..557ae08
--- /dev/null
+++ b/awt/java/awt/image/ImageProducer.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * The ImageProducer provides an interface for objects which produce
+ * the image data. ImageProducer is used for reconstructing the
+ * image. Each image contains an ImageProducer.
+ */
+public interface ImageProducer {
+
+ /**
+ * Checks if the specified ImageConsumer is registered with this
+ * ImageProvider or not.
+ *
+ * @param ic the ImageConsumer to be checked.
+ *
+ * @return true, if the specified ImageConsumer is registered with this
+ * ImageProvider, false otherwise.
+ */
+ public boolean isConsumer(ImageConsumer ic);
+
+ /**
+ * Starts a reconstruction of the image data which will
+ * be delivered to this consumer. This method addes the
+ * specified ImageConsumer before reconstructing the image.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void startProduction(ImageConsumer ic);
+
+ /**
+ * Requests the ImageProducer to resend the image data
+ * in ImageConsumer.TOPDOWNLEFTRIGHT order.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void requestTopDownLeftRightResend(ImageConsumer ic);
+
+ /**
+ * Deregisters the specified ImageConsumer.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void removeConsumer(ImageConsumer ic);
+
+ /**
+ * Adds the specified ImageConsumer object to this ImageProducer.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void addConsumer(ImageConsumer ic);
+
+}
+
diff --git a/awt/java/awt/image/ImagingOpException.java b/awt/java/awt/image/ImagingOpException.java
new file mode 100644
index 0000000..ebcaba4
--- /dev/null
+++ b/awt/java/awt/image/ImagingOpException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 5, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ImagingOpException class provides error notification when
+ * the BufferedImageOp or RasterOp filter methods can not perform
+ * the desired filter operation.
+ */
+public class ImagingOpException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8026288481846276658L;
+
+ /**
+ * Instantiates a new ImagingOpException with a detail message.
+ *
+ * @param s the detail message.
+ */
+ public ImagingOpException(String s) {
+ super(s);
+ }
+}
diff --git a/awt/java/awt/image/IndexColorModel.java b/awt/java/awt/image/IndexColorModel.java
new file mode 100644
index 0000000..a7043f4
--- /dev/null
+++ b/awt/java/awt/image/IndexColorModel.java
@@ -0,0 +1,1020 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.math.BigInteger;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class IndexColorModel represents a color model in which the
+ * color values of the pixels are read from a palette.
+ */
+public class IndexColorModel extends ColorModel {
+
+ /** The color map. */
+ private int colorMap[]; // Color Map
+
+ /** The map size. */
+ private int mapSize; // Color Map size
+
+ /** The transparent index. */
+ private int transparentIndex; // Index of fully transparent pixel
+
+ /** The gray palette. */
+ private boolean grayPalette; // Color Model has Color Map with Gray Pallete
+
+ /** The valid bits. */
+ private BigInteger validBits; // Specify valid Color Map values
+
+ /** The Constant CACHESIZE. */
+ private static final int CACHESIZE = 20; // Cache size. Cache used for
+ // improving performace of selection
+ // nearest color in Color Map
+
+ /** The cachetable. */
+ private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - used for
+ // storing RGB values and that appropriate indices
+ // in the Color Map
+
+
+ /** The next insert idx. */
+ private int nextInsertIdx = 0; // Next index for insertion into Cache table
+
+ /** The total inserted. */
+ private int totalInserted = 0; // Number of inserted values into Cache table
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ * @param validBits a list of which bits represent valid colormap
+ * values, or null if all are valid
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, int cmap[], int start,
+ int transferType, BigInteger validBits) {
+
+ super(bits, IndexColorModel.createBits(true),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false,
+ Transparency.OPAQUE, validateTransferType(transferType));
+
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ transparentIndex = -1;
+
+ if (validBits != null) {
+ for (int i = 0; i < mapSize; i++) {
+ if (!validBits.testBit(i)) {
+ this.validBits = validBits;
+ }
+ break;
+ }
+ }
+
+ transparency = Transparency.OPAQUE;
+ int alphaMask = 0xff000000;
+ int alpha = 0;
+
+ for (int i = 0; i < mapSize; i++, start++) {
+ colorMap[i] = cmap[start];
+ alpha = cmap[start] & alphaMask;
+
+ if (alpha == alphaMask) {
+ continue;
+ }
+ if (alpha == 0) {
+ if (transparentIndex < 0) {
+ transparentIndex = i;
+ }
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ } else if (alpha != alphaMask &&
+ transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+
+ }
+ checkPalette();
+
+ }
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param hasalpha whether this color model uses alpha
+ * @param trans the transparency supported, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, int cmap[], int start,
+ boolean hasalpha, int trans, int transferType) {
+
+ super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ (hasalpha || (trans >= 0)), false, Transparency.OPAQUE,
+ validateTransferType(transferType));
+
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ if (trans >= 0 && trans < mapSize) {
+ transparentIndex = trans;
+ transparency = Transparency.BITMASK;
+ } else {
+ transparentIndex = -1;
+ transparency = Transparency.OPAQUE;
+ }
+
+ int alphaMask = 0xff000000;
+ int alpha = 0;
+
+ for (int i = 0; i < mapSize; i++, start++) {
+ if (transparentIndex == i) {
+ colorMap[i] = cmap[start] & 0x00ffffff;
+ continue;
+ }
+ if (hasalpha) {
+ alpha = cmap[start] & alphaMask;
+ colorMap[i] = cmap[start];
+
+ if (alpha == alphaMask) {
+ continue;
+ }
+ if (alpha == 0) {
+ if (trans < 0) {
+ trans = i;
+ }
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ } else if (alpha != 0
+ && transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+ } else {
+ colorMap[i] = alphaMask | cmap[start];
+ }
+ }
+ checkPalette();
+
+ }
+
+ /**
+ * Instantiates a new index color model by building the color map
+ * from arrays of red, green, blue, and alpha values.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param r the array giving the red components of the entries in the color map
+ * @param g the array giving the green components of the entries in the color map
+ * @param b the array giving the blue components of the entries in the color map
+ * @param a the array giving the alpha components of the entries in the color map
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ * @throws ArrayIndexOutOfBoundsException if the size of one of the
+ * component arrays is less than the size of the color map
+ */
+ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[],
+ byte a[]) {
+
+ super(bits, IndexColorModel.createBits(true),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false,
+ Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ createColorMap(size, r, g, b, a, -1);
+ checkPalette();
+ }
+
+ /**
+ * Instantiates a new index color model by building the color map
+ * from arrays of red, green, and blue values.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param r the array giving the red components of the entries in the color map
+ * @param g the array giving the green components of the entries in the color map
+ * @param b the array giving the blue components of the entries in the color map
+ * @param trans the transparency supported, @see java.awt.Transparency
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ * @throws ArrayIndexOutOfBoundsException if the size of one of the
+ * component arrays is less than the size of the color map
+ */
+ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[],
+ int trans) {
+
+ super(bits, IndexColorModel.createBits((trans >= 0)),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), (trans >= 0), false,
+ Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ createColorMap(size, r, g, b, null, trans);
+ checkPalette();
+ }
+
+ /**
+ * Instantiates a new index color model by building the color map
+ * from arrays of red, green, and blue values.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param r the array giving the red components of the entries in the color map
+ * @param g the array giving the green components of the entries in the color map
+ * @param b the array giving the blue components of the entries in the color map
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ * @throws ArrayIndexOutOfBoundsException if the size of one of the
+ * component arrays is less than the size of the color map
+ */
+ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) {
+ super(bits, IndexColorModel.createBits(false),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false,
+ Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ createColorMap(size, r, g, b, null, -1);
+ checkPalette();
+ }
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param hasalpha whether this color model uses alpha
+ * @param trans the transparency supported, @see java.awt.Transparency
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, byte cmap[], int start,
+ boolean hasalpha, int trans) {
+
+ super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ (hasalpha || (trans >= 0)), false, Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ transparentIndex = -1;
+
+ transparency = Transparency.OPAQUE;
+ int alpha = 0xff000000;
+
+ for (int i = 0; i < mapSize; i++) {
+ colorMap[i] = (cmap[start++] & 0xff) << 16 |
+ (cmap[start++] & 0xff) << 8 | (cmap[start++] & 0xff);
+ if (trans == i) {
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ if(hasalpha) {
+ start++;
+ }
+ continue;
+ }
+ if (hasalpha) {
+ alpha = cmap[start++] & 0xff;
+ if (alpha == 0) {
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ if (trans < 0) {
+ trans = i;
+ }
+ }
+ } else {
+ if (alpha != 0xff &&
+ transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+ }
+ alpha <<= 24;
+ }
+ colorMap[i] |= alpha;
+ }
+
+ if (trans >= 0 && trans < mapSize) {
+ transparentIndex = trans;
+ }
+ checkPalette();
+
+ }
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param hasalpha whether this color model uses alpha
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, byte cmap[], int start,
+ boolean hasalpha) {
+
+ this(bits, size, cmap, start, hasalpha, -1);
+ }
+
+ @Override
+ public Object getDataElements(int[] components, int offset, Object pixel) {
+ int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 |
+ components[offset + 2];
+ if (hasAlpha) {
+ rgb |= components[offset + 3] << 24;
+ } else {
+ rgb |= 0xff000000;
+ }
+ return getDataElements(rgb, pixel);
+ }
+
+ @Override
+ public synchronized Object getDataElements(int rgb, Object pixel) {
+ int red = (rgb >> 16) & 0xff;
+ int green = (rgb >> 8) & 0xff;
+ int blue = rgb & 0xff;
+ int alpha = rgb >>> 24;
+ int pixIdx = 0;
+
+ for (int i = 0; i < totalInserted; i++) {
+ int idx = i * 2;
+ if (rgb == cachetable[idx]) {
+ return createDataObject(cachetable[idx + 1], pixel);
+ }
+ }
+
+ if (!hasAlpha && grayPalette) {
+ int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8;
+ int minError = 255;
+ int error = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ error = Math.abs((colorMap[i] & 0xff) - grey);
+ if (error < minError) {
+ pixIdx = i;
+ if (error == 0) {
+ break;
+ }
+ minError = error;
+ }
+ }
+ } else if (alpha == 0 && transparentIndex > -1) {
+ pixIdx = transparentIndex;
+ } else {
+ int minAlphaError = 255;
+ int minError = 195075; // 255^2 + 255^2 + 255^2
+ int alphaError;
+ int error = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ int pix = colorMap[i];
+ if (rgb == pix) {
+ pixIdx = i;
+ break;
+ }
+ alphaError = Math.abs(alpha - (pix >>> 24));
+ if (alphaError <= minAlphaError) {
+ minAlphaError = alphaError;
+
+ int buf = ((pix >> 16) & 0xff) - red;
+ error = buf * buf;
+
+ if (error < minError) {
+ buf = ((pix >> 8) & 0xff) - green;
+ error += buf * buf;
+
+ if (error < minError) {
+ buf = (pix & 0xff) - blue;
+ error += buf * buf;
+
+ if (error < minError) {
+ pixIdx = i;
+ minError = error;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ cachetable[nextInsertIdx] = rgb;
+ cachetable[nextInsertIdx + 1] = pixIdx;
+
+ nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2);
+ if (totalInserted < CACHESIZE) {
+ totalInserted++;
+ }
+
+ return createDataObject(pixIdx, pixel);
+ }
+
+ /**
+ * Converts an image from indexed to RGB format.
+ *
+ * @param raster the raster containing the source image
+ * @param forceARGB whether to use the default RGB color model
+ *
+ * @return the buffered image
+ *
+ * @throws IllegalArgumentException if the raster is not compatible with
+ * this color model
+ */
+ public BufferedImage convertToIntDiscrete(Raster raster,
+ boolean forceARGB) {
+
+ if (!isCompatibleRaster(raster)) {
+ // awt.265=The raster argument is not compatible with this IndexColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$
+ }
+
+ ColorModel model;
+ if (forceARGB || transparency == Transparency.TRANSLUCENT) {
+ model = ColorModel.getRGBdefault();
+ } else if (transparency == Transparency.BITMASK) {
+ model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00,
+ 0x000000ff, 0x01000000);
+ } else {
+ model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
+ }
+
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ WritableRaster distRaster = model.createCompatibleWritableRaster(w, h);
+
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+
+ Object obj = null;
+ int pixels[] = null;
+
+ for (int i = 0; i < h; i++, minY++) {
+ obj = raster.getDataElements(minX, minY, w, 1, obj);
+ if (obj instanceof byte[]) {
+ byte ba[] = (byte[]) obj;
+ if (pixels == null) {
+ pixels = new int[ba.length];
+ }
+ for (int j = 0; j < ba.length; j++) {
+ pixels[j] = colorMap[ba[j] & 0xff];
+ }
+ } else if (obj instanceof short[]) {
+ short sa[] = (short[]) obj;
+ if (pixels == null) {
+ pixels = new int[sa.length];
+ }
+ for (int j = 0; j < sa.length; j++) {
+ pixels[j] = colorMap[sa[j] & 0xffff];
+ }
+ }
+ if (obj instanceof int[]) {
+ int ia[] = (int[]) obj;
+ if (pixels == null) {
+ pixels = new int[ia.length];
+ }
+ for (int j = 0; j < ia.length; j++) {
+ pixels[j] = colorMap[ia[j]];
+ }
+ }
+
+ distRaster.setDataElements(0, i, w, 1, pixels);
+ }
+
+ return new BufferedImage(model, distRaster, false, null);
+ }
+
+ /**
+ * Gets the valid pixels.
+ *
+ * @return the valid pixels
+ */
+ public BigInteger getValidPixels() {
+ return validBits;
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour.
+ // It could be reveled such way:
+ // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED);
+ // ColorModel cm = bi.getColorModel();
+ // System.out.println(cm.toString());
+ String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$
+ " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$
+ " transparency = "; //$NON-NLS-1$
+
+ if (transparency == Transparency.OPAQUE) {
+ str = str + "Transparency.OPAQUE"; //$NON-NLS-1$
+ } else if (transparency == Transparency.BITMASK) {
+ str = str + "Transparency.BITMASK"; //$NON-NLS-1$
+ } else {
+ str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$
+ }
+
+ str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$
+ hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$
+
+ return str;
+ }
+
+ @Override
+ public int[] getComponents(Object pixel, int components[], int offset) {
+ int pixIdx = -1;
+ if (pixel instanceof byte[]) {
+ byte ba[] = (byte[]) pixel;
+ pixIdx = ba[0] & 0xff;
+ } else if (pixel instanceof short[]) {
+ short sa[] = (short[]) pixel;
+ pixIdx = sa[0] & 0xffff;
+ } else if (pixel instanceof int[]) {
+ int ia[] = (int[]) pixel;
+ pixIdx = ia[0];
+ } else {
+ // awt.219=This transferType is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+ }
+
+ return getComponents(pixIdx, components, offset);
+ }
+
+ @Override
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ WritableRaster raster;
+ if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1,
+ pixel_bits, null);
+ } else if (pixel_bits <= 8) {
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h,
+ 1, null);
+ } else if (pixel_bits <= 16) {
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w,
+ h, 1, null);
+ } else {
+ // awt.266=The number of bits in a pixel is greater than 16
+ throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$
+ }
+
+ return raster;
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ if (sm == null) {
+ return false;
+ }
+
+ if (!(sm instanceof MultiPixelPackedSampleModel)
+ && !(sm instanceof ComponentSampleModel)) {
+ return false;
+ }
+
+ if (sm.getTransferType() != transferType) {
+ return false;
+ }
+ if (sm.getNumBands() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+ return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h,
+ pixel_bits);
+ }
+ int bandOffsets[] = new int[1];
+ bandOffsets[0] = 0;
+ return new ComponentSampleModel(transferType, w, h, 1, w,
+ bandOffsets);
+
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ int sampleSize = raster.getSampleModel().getSampleSize(0);
+ return (raster.getTransferType() == transferType &&
+ raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize);
+ }
+
+ @Override
+ public int getDataElement(int components[], int offset) {
+ int rgb = (components[offset] << 16) | (components[offset + 1]) << 8
+ | components[offset + 2];
+
+ if (hasAlpha) {
+ rgb |= components[offset + 3] << 24;
+ } else {
+ rgb |= 0xff000000;
+ }
+
+ int pixel;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) getDataElements(rgb, null);
+ pixel = ba[0] & 0xff;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) getDataElements(rgb, null);
+ pixel = sa[0] & 0xffff;
+ break;
+ default:
+ // awt.267=The transferType is invalid
+ throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Gets the color map.
+ *
+ * @param rgb the destination array where the color map is written
+ */
+ public final void getRGBs(int rgb[]) {
+ System.arraycopy(colorMap, 0, rgb, 0, mapSize);
+ }
+
+ /**
+ * Gets the red component of the color map.
+ *
+ * @param r the destination array
+ */
+ public final void getReds(byte r[]) {
+ for (int i = 0; i < mapSize; i++) {
+ r[i] = (byte) (colorMap[i] >> 16);
+ }
+ }
+
+ /**
+ * Gets the green component of the color map.
+ *
+ * @param g the destination array
+ */
+ public final void getGreens(byte g[]) {
+ for (int i = 0; i < mapSize; i++) {
+ g[i] = (byte) (colorMap[i] >> 8);
+ }
+ }
+
+ /**
+ * Gets the blue component of the color map.
+ *
+ * @param b the destination array
+ */
+ public final void getBlues(byte b[]) {
+ for (int i = 0; i < mapSize; i++) {
+ b[i] = (byte) colorMap[i];
+ }
+ }
+
+ /**
+ * Gets the alpha component of the color map.
+ *
+ * @param a the destination array
+ */
+ public final void getAlphas(byte a[]) {
+ for (int i = 0; i < mapSize; i++) {
+ a[i] = (byte) (colorMap[i] >> 24);
+ }
+ }
+
+ @Override
+ public int[] getComponents(int pixel, int components[], int offset) {
+ if (components == null) {
+ components = new int[offset + numComponents];
+ }
+
+ components[offset + 0] = getRed(pixel);
+ components[offset + 1] = getGreen(pixel);
+ components[offset + 2] = getBlue(pixel);
+ if (hasAlpha && (components.length - offset) > 3) {
+ components[offset + 3] = getAlpha(pixel);
+ }
+
+ return components;
+ }
+
+ /**
+ * Checks if the specified pixel is valid for this color model.
+ *
+ * @param pixel the pixel
+ *
+ * @return true, if the pixel is valid
+ */
+ public boolean isValid(int pixel) {
+ if (validBits == null) {
+ return (pixel >= 0 && pixel < mapSize);
+ }
+ return (pixel < mapSize && validBits.testBit(pixel));
+ }
+
+ @Override
+ public final int getRed(int pixel) {
+ return (colorMap[pixel] >> 16) & 0xff;
+ }
+
+ @Override
+ public final int getRGB(int pixel) {
+ return colorMap[pixel];
+ }
+
+ @Override
+ public final int getGreen(int pixel) {
+ return (colorMap[pixel] >> 8) & 0xff;
+ }
+
+ @Override
+ public final int getBlue(int pixel) {
+ return colorMap[pixel] & 0xff;
+ }
+
+ @Override
+ public final int getAlpha(int pixel) {
+ return (colorMap[pixel] >> 24) & 0xff;
+ }
+
+ @Override
+ public int[] getComponentSize() {
+ return bits.clone();
+ }
+
+ /**
+ * Checks if this color model validates pixels.
+ *
+ * @return true, if all pixels are valid, otherwise false
+ */
+ public boolean isValid() {
+ return (validBits == null);
+ }
+
+ @Override
+ public void finalize() {
+ // TODO: implement
+ return;
+ }
+
+ /**
+ * Gets the index that represents the transparent pixel.
+ *
+ * @return the index that represents the transparent pixel
+ */
+ public final int getTransparentPixel() {
+ return transparentIndex;
+ }
+
+ @Override
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Gets the size of the color map.
+ *
+ * @return the map size
+ */
+ public final int getMapSize() {
+ return mapSize;
+ }
+
+ /**
+ * Creates the color map.
+ *
+ * @param size the size
+ * @param r the r
+ * @param g the g
+ * @param b the b
+ * @param a the a
+ * @param trans the trans
+ */
+ private void createColorMap(int size, byte r[], byte g[], byte b[],
+ byte a[], int trans) {
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ if (trans >= 0 && trans < mapSize) {
+ transparency = Transparency.BITMASK;
+ transparentIndex = trans;
+ } else {
+ transparency = Transparency.OPAQUE;
+ transparentIndex = -1;
+ }
+ int alpha = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) |
+ (b[i] & 0xff);
+
+ if (trans == i) {
+ continue;
+ }
+
+ if (a == null) {
+ colorMap[i] |= 0xff000000;
+ } else {
+ alpha = a[i] & 0xff;
+ if (alpha == 0xff) {
+ colorMap[i] |= 0xff000000;
+ } else if (alpha == 0) {
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ if (transparentIndex < 0) {
+ transparentIndex = i;
+ }
+ } else {
+ colorMap[i] |= (a[i] & 0xff) << 24;
+ if (transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * This method checking, if Color Map has Gray Palette.
+ */
+ private void checkPalette() {
+ grayPalette = false;
+ if (transparency > Transparency.OPAQUE) {
+ return;
+ }
+ int rgb = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ rgb = colorMap[i];
+ if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) ||
+ ((rgb >> 8) & 0xff) != (rgb & 0xff)) {
+ return;
+ }
+ }
+ grayPalette = true;
+ }
+
+ /**
+ * Construction an array pixel representation.
+ *
+ * @param colorMapIdx - index into Color Map
+ * @param pixel - pixel
+ *
+ * @return - an array pixel representation
+ */
+ private Object createDataObject(int colorMapIdx, Object pixel) {
+ if (pixel == null) {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte[] ba = new byte[1];
+ ba[0] = (byte) colorMapIdx;
+ pixel = ba;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short[] sa = new short[1];
+ sa[0] = (short) colorMapIdx;
+ pixel = sa;
+ break;
+ default:
+ // awt.267=The transferType is invalid
+ throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
+ }
+ } else if (pixel instanceof byte[]
+ && transferType == DataBuffer.TYPE_BYTE) {
+ byte ba[] = (byte[]) pixel;
+ ba[0] = (byte) colorMapIdx;
+ pixel = ba;
+ } else if (pixel instanceof short[]&&
+ transferType == DataBuffer.TYPE_USHORT) {
+ short[] sa = (short[]) pixel;
+ sa[0] = (short) colorMapIdx;
+ pixel = sa;
+ } else if (pixel instanceof int[]) {
+ int ia[] = (int[]) pixel;
+ ia[0] = colorMapIdx;
+ pixel = ia;
+ } else {
+ // awt.268=The pixel is not a primitive array of type transferType
+ throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$
+ }
+ return pixel;
+ }
+
+ /**
+ * Creates the bits.
+ *
+ * @param hasAlpha the has alpha
+ *
+ * @return the int[]
+ */
+ private static int[] createBits(boolean hasAlpha) {
+
+ int numChannels;
+ if (hasAlpha) {
+ numChannels = 4;
+ } else {
+ numChannels = 3;
+ }
+
+ int bits[] = new int[numChannels];
+ for (int i = 0; i < numChannels; i++) {
+ bits[i] = 8;
+ }
+
+ return bits;
+
+ }
+
+ /**
+ * Validate transfer type.
+ *
+ * @param transferType the transfer type
+ *
+ * @return the int
+ */
+ private static int validateTransferType(int transferType) {
+ if (transferType != DataBuffer.TYPE_BYTE &&
+ transferType != DataBuffer.TYPE_USHORT) {
+ // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
+ throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$
+ }
+ return transferType;
+ }
+
+ /**
+ * Checks if is gray pallete.
+ *
+ * @return true, if is gray pallete
+ */
+ boolean isGrayPallete(){
+ return grayPalette;
+ }
+
+}
+
+
diff --git a/awt/java/awt/image/Kernel.java b/awt/java/awt/image/Kernel.java
new file mode 100644
index 0000000..c6f00e2
--- /dev/null
+++ b/awt/java/awt/image/Kernel.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 28, 2005
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Kernel class provides a matrix. This matrix is stored as a float array
+ * which describes how a specified pixel affects the value calculated for
+ * the pixel's position in the output image of a filtering operation.
+ * The X, Y origins indicate the kernel matrix element which corresponds to
+ * the pixel position for which an output value is being calculated.
+ */
+public class Kernel implements Cloneable {
+
+ /** The x origin. */
+ private final int xOrigin;
+
+ /** The y origin. */
+ private final int yOrigin;
+
+ /** The width. */
+ private int width;
+
+ /** The height. */
+ private int height;
+
+ /** The data. */
+ float data[];
+
+ /**
+ * Instantiates a new Kernel with the specified float array.
+ * The width*height elements of the data array are copied.
+ *
+ * @param width the width of the Kernel.
+ * @param height the height of the Kernel.
+ * @param data the data of Kernel.
+ */
+ public Kernel(int width, int height, float[] data) {
+ int dataLength = width*height;
+ if (data.length < dataLength) {
+ // awt.22B=Length of data should not be less than width*height
+ throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$
+ }
+
+ this.width = width;
+ this.height = height;
+
+ this.data = new float[dataLength];
+ System.arraycopy(data, 0, this.data, 0, dataLength);
+
+ xOrigin = (width-1)/2;
+ yOrigin = (height-1)/2;
+ }
+
+ /**
+ * Gets the width of this Kernel.
+ *
+ * @return the width of this Kernel.
+ */
+ public final int getWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the height of this Kernel.
+ *
+ * @return the height of this Kernel.
+ */
+ public final int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the float data array of this Kernel.
+ *
+ * @param data the float array where the resulted data will be stored.
+ *
+ * @return the float data array of this Kernel.
+ */
+ public final float[] getKernelData(float[] data) {
+ if (data == null) {
+ data = new float[this.data.length];
+ }
+ System.arraycopy(this.data, 0, data, 0, this.data.length);
+
+ return data;
+ }
+
+ /**
+ * Gets the X origin of this Kernel.
+ *
+ * @return the X origin of this Kernel.
+ */
+ public final int getXOrigin() {
+ return xOrigin;
+ }
+
+ /**
+ * Gets the Y origin of this Kernel.
+ *
+ * @return the Y origin of this Kernel.
+ */
+ public final int getYOrigin() {
+ return yOrigin;
+ }
+
+ /**
+ * Returns a copy of this Kernel object.
+ *
+ * @return the copy of this Kernel object.
+ */
+ @Override
+ public Object clone() {
+ return new Kernel(width, height, data);
+ }
+}
diff --git a/awt/java/awt/image/LookupOp.java b/awt/java/awt/image/LookupOp.java
new file mode 100644
index 0000000..f9bd2c7
--- /dev/null
+++ b/awt/java/awt/image/LookupOp.java
@@ -0,0 +1,647 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The LookupOp class perfoms a lookup operation which transforms a
+ * source image by filtering each band using a table of data.
+ * The table may contain a single array or it may contain a
+ * different data array for each band of the image.
+ */
+public class LookupOp implements BufferedImageOp, RasterOp {
+
+ /** The lut. */
+ private final LookupTable lut;
+
+ /** The hints. */
+ private RenderingHints hints;
+
+ // TODO remove when this field is used
+ /** The can use ipp. */
+ @SuppressWarnings("unused")
+ private final boolean canUseIpp;
+
+ // We don't create levels/values when it is possible to reuse old
+ /** The cached levels. */
+ private int cachedLevels[];
+
+ /** The cached values. */
+ private int cachedValues[];
+ // Number of channels for which cache is valid.
+ // If negative number of channels is same as positive but skipAlpha was specified
+ /** The valid for channels. */
+ private int validForChannels;
+
+ /** The level initializer. */
+ static int levelInitializer[] = new int[0x10000];
+
+ static {
+ // TODO
+ // System.loadLibrary("imageops");
+
+ for (int i=1; i<=0x10000; i++) {
+ levelInitializer[i-1] = i;
+ }
+ }
+
+ /**
+ * Instantiates a new LookupOp object from the specified
+ * LookupTable object and a RenderingHints object.
+ *
+ * @param lookup the specified LookupTable object.
+ * @param hints the RenderingHints object or null.
+ */
+ public LookupOp(LookupTable lookup, RenderingHints hints) {
+ if (lookup == null){
+ throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ lut = lookup;
+ this.hints = hints;
+ canUseIpp = lut instanceof ByteLookupTable || lut instanceof ShortLookupTable;
+ }
+
+ /**
+ * Gets the LookupTable of the specified Object.
+ *
+ * @return the LookupTable of the specified Object.
+ */
+ public final LookupTable getTable() {
+ return lut;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ return src.createCompatibleWritableRaster();
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+ if (dstCM == null) {
+ dstCM = src.getColorModel();
+
+ // Sync transfer type with LUT for component color model
+ if (dstCM instanceof ComponentColorModel) {
+ int transferType = dstCM.getTransferType();
+ if (lut instanceof ByteLookupTable) {
+ transferType = DataBuffer.TYPE_BYTE;
+ } else if (lut instanceof ShortLookupTable) {
+ transferType = DataBuffer.TYPE_SHORT;
+ }
+
+ dstCM = new ComponentColorModel(
+ dstCM.cs,
+ dstCM.hasAlpha(),
+ dstCM.isAlphaPremultiplied,
+ dstCM.transparency,
+ transferType
+ );
+ }
+ }
+
+ WritableRaster r =
+ dstCM.isCompatibleSampleModel(src.getSampleModel()) ?
+ src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) :
+ dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+ return new BufferedImage(
+ dstCM,
+ r,
+ dstCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else {
+ if (src.getNumBands() != dst.getNumBands()) {
+ throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$ }
+ }
+ if (src.getWidth() != dst.getWidth()){
+ throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$ }
+ }
+ if (src.getHeight() != dst.getHeight()){
+ throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$ }
+ }
+ }
+
+ if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) {
+ // awt.238=The number of arrays in the LookupTable does not meet the restrictions
+ throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$
+ }
+
+ // TODO
+ // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0)
+ if (slowFilter(src, dst, false) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ ColorModel srcCM = src.getColorModel();
+
+ if (srcCM instanceof IndexColorModel) {
+ // awt.220=Source should not have IndexColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$
+ }
+
+ // Check if the number of scaling factors matches the number of bands
+ int nComponents = srcCM.getNumComponents();
+ int nLUTComponents = lut.getNumComponents();
+ boolean skipAlpha;
+ if (srcCM.hasAlpha()) {
+ if (nLUTComponents == 1 || nLUTComponents == nComponents-1) {
+ skipAlpha = true;
+ } else if (nLUTComponents == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.229=Number of components in the LUT does not match the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$
+ }
+ } else if (nLUTComponents == 1 || nLUTComponents == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.229=Number of components in the LUT does not match the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$
+ }
+
+ BufferedImage finalDst = null;
+ if (dst == null) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, null);
+ } else {
+ if (src.getWidth() != dst.getWidth()){
+ throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$
+ }
+
+ if (src.getHeight() != dst.getHeight()){
+ throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$
+ }
+
+ if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and
+ // BufferedImage.TYPE_INT_ARGB as same
+ if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src
+ .getType() == BufferedImage.TYPE_INT_ARGB) && (dst
+ .getType() == BufferedImage.TYPE_INT_RGB || dst
+ .getType() == BufferedImage.TYPE_INT_ARGB))) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, null);
+ }
+ }
+ }
+
+ // TODO
+ //if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0)
+ if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return dst;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) {
+ int minSrcX = src.getMinX();
+ int minDstX = dst.getMinX();
+ int minSrcY = src.getMinY();
+ int minDstY = dst.getMinY();
+
+ int skippingChannels = skipAlpha ? 1 : 0;
+ int numBands2Process = src.getNumBands() - skippingChannels;
+
+ int numBands = src.getNumBands();
+ int srcHeight = src.getHeight();
+ int srcWidth = src.getWidth();
+
+ int[] pixels = null;
+ int offset = lut.getOffset();
+
+ if (lut instanceof ByteLookupTable){
+ byte[][] byteData = ((ByteLookupTable)lut).getTable();
+ pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels);
+
+ if (lut.getNumComponents() != 1){
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = byteData[b][pixels[i+b]-offset] & 0xFF;
+ }
+ }
+ } else {
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = byteData[0][pixels[i+b]-offset] & 0xFF;
+ }
+ }
+ }
+
+ dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels);
+ } else if (lut instanceof ShortLookupTable){
+ short[][] shortData = ((ShortLookupTable)lut).getTable();
+ pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels);
+
+ if (lut.getNumComponents() != 1){
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = shortData[b][pixels[i+b]-offset] & 0xFFFF;
+ }
+ }
+ } else {
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = shortData[0][pixels[i+b]-offset] & 0xFFFF;
+ }
+ }
+ }
+
+ dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels);
+ } else {
+ int pixel[] = new int[src.getNumBands()];
+ int maxY = minSrcY + srcHeight;
+ int maxX = minSrcX + srcWidth;
+ for (int srcY=minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++){
+ for (int srcX=minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++){
+ src.getPixel(srcX, srcY, pixel);
+ lut.lookupPixel(pixel, pixel);
+ dst.setPixel(dstX, dstY, pixel);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Creates the byte levels.
+ *
+ * @param channels the channels
+ * @param skipAlpha the skip alpha
+ * @param levels the levels
+ * @param values the values
+ * @param channelsOrder the channels order
+ */
+ private final void createByteLevels(
+ int channels, boolean skipAlpha,
+ int levels[], int values[], int channelsOrder[]
+ ) {
+ byte data[][] = ((ByteLookupTable)lut).getTable();
+ int nLevels = data[0].length;
+ int offset = lut.getOffset();
+
+ // Use one data array for all channels or use several data arrays
+ int dataIncrement = data.length > 1 ? 1 : 0;
+
+ for (int ch = 0, dataIdx = 0; ch<channels; dataIdx+=dataIncrement, ch++) {
+ int channelOffset = channelsOrder == null ? ch : channelsOrder[ch];
+ int channelBase = nLevels * channelOffset;
+
+ // Skip last channel if needed, zero values are OK -
+ // no changes to the channel information will be done in IPP
+ if ((channelOffset == channels-1 && skipAlpha) || (dataIdx >= data.length)) {
+ continue;
+ }
+
+ System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels);
+ for (int from=0, to=channelBase; from<nLevels; from++, to++) {
+ values[to] = data[dataIdx][from] & 0xFF;
+ }
+ }
+ }
+
+ /**
+ * Creates the short levels.
+ *
+ * @param channels the channels
+ * @param skipAlpha the skip alpha
+ * @param levels the levels
+ * @param values the values
+ * @param channelsOrder the channels order
+ */
+ private final void createShortLevels(
+ int channels, boolean skipAlpha,
+ int levels[], int values[], int channelsOrder[]
+ ) {
+ short data[][] = ((ShortLookupTable)lut).getTable();
+ int nLevels = data[0].length;
+ int offset = lut.getOffset();
+
+ // Use one data array for all channels or use several data arrays
+ int dataIncrement = data.length > 1 ? 1 : 0;
+
+ for (int ch = 0, dataIdx = 0; ch<channels; dataIdx+=dataIncrement, ch++) {
+ int channelOffset = channelsOrder == null ? ch : channelsOrder[ch];
+
+ // Skip last channel if needed, zero values are OK -
+ // no changes to the channel information will be done in IPP
+ if ((channelOffset == channels-1 && skipAlpha) || (dataIdx >= data.length)) {
+ continue;
+ }
+
+ int channelBase = nLevels * channelOffset;
+ System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels);
+ for (int from=0, to=channelBase; from<nLevels; from++, to++) {
+ values[to] = data[dataIdx][from] & 0xFFFF;
+ }
+ }
+ }
+
+ // TODO remove when this method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private final int ippFilter(
+ Raster src, WritableRaster dst,
+ int imageType, boolean skipAlpha
+ ) {
+ int res;
+
+ int srcStride, dstStride;
+ int channels;
+ int offsets[] = null;
+ int channelsOrder[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_INT_RGB: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ channelsOrder = new int[] {2, 1, 0, 3};
+ break;
+ }
+
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ channelsOrder = new int[] {2, 1, 0};
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY:
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Have IPP functions for 1, 3 and 4 channels
+ channels = srcSM.getNumBands();
+ if (!(channels == 1 || channels == 3 || channels == 4)) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride();
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride();
+
+ channelsOrder = ((ComponentSampleModel) srcSM).getBandOffsets();
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 =
+ (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 =
+ (SinglePixelPackedSampleModel) dstSM;
+
+ channels = sppsm1.getNumBands();
+
+ // TYPE_INT_RGB, TYPE_INT_ARGB...
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT ||
+ !(channels == 3 || channels == 4)
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Check compatibility of sample models
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+ }
+
+ channelsOrder = new int[channels];
+ int bitOffsets[] = sppsm1.getBitOffsets();
+ for (int i=0; i<channels; i++) {
+ channelsOrder[i] = bitOffsets[i] / 8;
+ }
+
+ if (channels == 3) { // Don't skip channel now, could be optimized
+ channels = 4;
+ }
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ int levels[] = null, values[] = null;
+ int channelMultiplier = skipAlpha ? -1 : 1;
+ if (channelMultiplier*channels == validForChannels) { // use existing levels/values
+ levels = cachedLevels;
+ values = cachedValues;
+ } else { // create new levels/values
+ if (lut instanceof ByteLookupTable) {
+ byte data[][] = ((ByteLookupTable)lut).getTable();
+ levels = new int[channels*data[0].length];
+ values = new int[channels*data[0].length];
+ createByteLevels(channels, skipAlpha, levels, values, channelsOrder);
+ } else if (lut instanceof ShortLookupTable) {
+ short data[][] = ((ShortLookupTable)lut).getTable();
+ levels = new int[channels*data[0].length];
+ values = new int[channels*data[0].length];
+ createShortLevels(channels, skipAlpha, levels, values, channelsOrder);
+ }
+
+ // cache levels/values
+ validForChannels = channelMultiplier*channels;
+ cachedLevels = levels;
+ cachedValues = values;
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ res = ippLUT(
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ levels, values,
+ channels, offsets,
+ false
+ );
+
+ return res;
+ }
+
+ /**
+ * Ipp lut.
+ *
+ * @param src the src
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dst the dst
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param levels the levels
+ * @param values the values
+ * @param channels the channels
+ * @param offsets the offsets
+ * @param linear the linear
+ *
+ * @return the int
+ */
+ final static native int ippLUT(
+ Object src, int srcWidth, int srcHeight, int srcStride,
+ Object dst, int dstWidth, int dstHeight, int dstStride,
+ int levels[], int values[],
+ int channels, int offsets[],
+ boolean linear
+ );
+}
diff --git a/awt/java/awt/image/LookupTable.java b/awt/java/awt/image/LookupTable.java
new file mode 100644
index 0000000..d15f23c
--- /dev/null
+++ b/awt/java/awt/image/LookupTable.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This abstract LookupTable class represents lookup table which
+ * is defined with the number of components and offset value.
+ * ByteLookupTable and ShortLookupTable classes are subclasses of
+ * LookupTable which contains byte and short data tables as
+ * an input arrays for bands or components of image.
+ */
+public abstract class LookupTable {
+
+ /** The offset. */
+ private int offset;
+
+ /** The num components. */
+ private int numComponents;
+
+ /**
+ * Instantiates a new LookupTable with the specified offset value
+ * and number of components.
+ *
+ * @param offset the offset value.
+ * @param numComponents the number of components.
+ */
+ protected LookupTable(int offset, int numComponents) {
+ if (offset < 0) {
+ // awt.232=Offset should be not less than zero
+ throw new IllegalArgumentException(Messages.getString("awt.232")); //$NON-NLS-1$
+ }
+ if (numComponents < 1) {
+ // awt.233=Number of components should be positive
+ throw new IllegalArgumentException(Messages.getString("awt.233")); //$NON-NLS-1$
+ }
+
+ this.offset = offset;
+ this.numComponents = numComponents;
+ }
+
+ /**
+ * Gets the offset value of this Lookup table.
+ *
+ * @return the offset value of this Lookup table.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Gets the number of components of this Lookup table.
+ *
+ * @return the number components of this Lookup table.
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+ /**
+ * Returns a int array which contains samples of the specified
+ * pixel which is translated with the lookup table of this
+ * LookupTable. The resulted array is stored to the dst array.
+ *
+ * @param src the source array.
+ * @param dst the destination array where the result can be stored.
+ *
+ * @return the int array of translated samples of a pixel.
+ */
+ public abstract int[] lookupPixel(int[] src, int[] dst);
+}
diff --git a/awt/java/awt/image/MemoryImageSource.java b/awt/java/awt/image/MemoryImageSource.java
new file mode 100644
index 0000000..983f19e
--- /dev/null
+++ b/awt/java/awt/image/MemoryImageSource.java
@@ -0,0 +1,512 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The MemoryImageSource class is used to produces pixels of an image from
+ * an array. This class can manage a memory image which
+ * contains an animation or custom rendering.
+ */
+public class MemoryImageSource implements ImageProducer {
+
+ /** The width. */
+ int width;
+
+ /** The height. */
+ int height;
+
+ /** The cm. */
+ ColorModel cm;
+
+ /** The b data. */
+ byte bData[];
+
+ /** The i data. */
+ int iData[];
+
+ /** The offset. */
+ int offset;
+
+ /** The scanline. */
+ int scanline;
+
+ /** The properties. */
+ Hashtable<?, ?> properties;
+
+ /** The consumers. */
+ Vector<ImageConsumer> consumers;
+
+ /** The animated. */
+ boolean animated;
+
+ /** The fullbuffers. */
+ boolean fullbuffers;
+
+ /** The data type. */
+ int dataType;
+
+ /** The Constant DATA_TYPE_BYTE. */
+ static final int DATA_TYPE_BYTE = 0;
+
+ /** The Constant DATA_TYPE_INT. */
+ static final int DATA_TYPE_INT = 1;
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ * @param props the set of properties to be used for image
+ * processing.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, int pix[],
+ int off, int scan, Hashtable<?, ?> props) {
+ init(w, h, cm, pix, off, scan, props);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ * @param props the set of properties to be used for image
+ * processing.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, byte pix[],
+ int off, int scan, Hashtable<?, ?> props) {
+ init(w, h, cm, pix, off, scan, props);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters and default RGB ColorModel.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ * @param props the set of properties to be used for image
+ * processing.
+ */
+ public MemoryImageSource(int w, int h, int pix[], int off, int scan,
+ Hashtable<?, ?> props) {
+ init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, int pix[],
+ int off, int scan) {
+ init(w, h, cm, pix, off, scan, null);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, byte pix[],
+ int off, int scan) {
+ init(w, h, cm, pix, off, scan, null);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters and default RGB ColorModel.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param pix the pixels array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ */
+ public MemoryImageSource(int w, int h, int pix[], int off, int scan) {
+ init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null);
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ return consumers.contains(ic);
+ }
+
+ public void startProduction(ImageConsumer ic) {
+ if(!isConsumer(ic) && ic != null) {
+ consumers.addElement(ic);
+ }
+ try{
+ setHeader(ic);
+ setPixels(ic, 0, 0, width, height);
+ if(animated){
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }else{
+ ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ if(isConsumer(ic)) {
+ removeConsumer(ic);
+ }
+ }
+ }catch(Exception e){
+ if(isConsumer(ic)) {
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ if(isConsumer(ic)) {
+ removeConsumer(ic);
+ }
+ }
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ consumers.removeElement(ic);
+ }
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if(ic == null || consumers.contains(ic)) {
+ return;
+ }
+ consumers.addElement(ic);
+ }
+
+ /**
+ * Replaces the pixel data with a new pixel array for holding
+ * the pixels for this image. If an animation
+ * flag is set to true value by the setAnimated() method,
+ * the new pixels will be immediately delivered to the ImageConsumers.
+ *
+ * @param newpix the new pixel array.
+ * @param newmodel the new ColorModel.
+ * @param offset the offset in the array.
+ * @param scansize the distance from one row of pixels to the next row
+ * in the pixel array
+ */
+ public synchronized void newPixels(int newpix[], ColorModel newmodel,
+ int offset, int scansize) {
+ this.dataType = DATA_TYPE_INT;
+ this.iData = newpix;
+ this.cm = newmodel;
+ this.offset = offset;
+ this.scanline = scansize;
+ newPixels();
+ }
+
+ /**
+ * Replaces the pixel data with a new pixel array for holding
+ * the pixels for this image. If an animation
+ * flag is set to true value by the setAnimated() method,
+ * the new pixels will be immediately delivered to the ImageConsumers.
+ *
+ * @param newpix the new pixel array.
+ * @param newmodel the new ColorModel.
+ * @param offset the offset in the array.
+ * @param scansize the distance from one row of pixels to the next row
+ * in the pixel array
+ */
+ public synchronized void newPixels(byte newpix[], ColorModel newmodel,
+ int offset, int scansize) {
+ this.dataType = DATA_TYPE_BYTE;
+ this.bData = newpix;
+ this.cm = newmodel;
+ this.offset = offset;
+ this.scanline = scansize;
+ newPixels();
+ }
+
+ /**
+ * Sets the full buffer updates flag to true. If this is an
+ * animated image, the image consumers hints are updated
+ * accordingly.
+ *
+ * @param fullbuffers the true if the pixel buffer should be sent always.
+ */
+ public synchronized void setFullBufferUpdates(boolean fullbuffers) {
+ if(this.fullbuffers == fullbuffers) {
+ return;
+ }
+ this.fullbuffers = fullbuffers;
+ if(animated){
+ Object consAr[] = consumers.toArray();
+ for (Object element : consAr) {
+ ImageConsumer con = (ImageConsumer)element;
+ try{
+ if(fullbuffers){
+ con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES);
+ }else{
+ con.setHints(ImageConsumer.RANDOMPIXELORDER);
+ }
+ }catch(Exception e){
+ if(isConsumer(con)) {
+ con.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ if(isConsumer(con)) {
+ removeConsumer(con);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the flag that tells whether this memory image has more
+ * than one frame (for animation): true for multiple frames,
+ * false if this class represents a single frame image.
+ *
+ * @param animated whether this image represents an animation.
+ */
+ public synchronized void setAnimated(boolean animated) {
+ if(this.animated == animated) {
+ return;
+ }
+ Object consAr[] = consumers.toArray();
+ for (Object element : consAr) {
+ ImageConsumer con = (ImageConsumer)element;
+ try{
+ con.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }catch(Exception e){
+ if(isConsumer(con)) {
+ con.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ }
+ if(isConsumer(con)){
+ removeConsumer(con);
+ }
+ }
+ this.animated = animated;
+ }
+
+ /**
+ * Sends the specified rectangular area of the buffer to
+ * ImageConsumers and notifies them that an animation frame
+ * is completed only if framenotify parameter is true.
+ * That works only if the animated flag has been set to true
+ * by the setAnimated() method. If the full buffer update flag
+ * has been set to true by the setFullBufferUpdates() method,
+ * then the entire buffer will always be sent ignoring parameters.
+ *
+ * @param x the X coordinate of the rectangular area.
+ * @param y the Y coordinate of rthe ectangular area.
+ * @param w the width of the rectangular area.
+ * @param h the height of the rectangular area.
+ * @param framenotify true if a SINGLEFRAMEDONE notification
+ * should be sent to the registered consumers, false otherwise.
+ */
+ public synchronized void newPixels(int x, int y, int w, int h,
+ boolean framenotify) {
+ if(animated){
+ if(fullbuffers){
+ x = 0;
+ y = 0;
+ w = width;
+ h = height;
+ }else{
+ if(x < 0){
+ w += x;
+ x = 0;
+ }
+ if(w > width) {
+ w = width - x;
+ }
+ if(y < 0){
+ h += y;
+ y = 0;
+ }
+ }
+ if(h > height) {
+ h = height - y;
+ }
+ Object consAr[] = consumers.toArray();
+ for (Object element : consAr) {
+ ImageConsumer con = (ImageConsumer)element;
+ try{
+ if(w > 0 && h > 0) {
+ setPixels(con, x, y, w, h);
+ }
+ if(framenotify) {
+ con.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+ }catch(Exception ex){
+ if(isConsumer(con)) {
+ con.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ if(isConsumer(con)) {
+ removeConsumer(con);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends the specified rectangular area of the buffer to
+ * the ImageConsumers and notifies them that an animation frame
+ * is completed if the animated flag has been set to true
+ * by the setAnimated() method. If the full buffer update flag
+ * has been set to true by the setFullBufferUpdates() method,
+ * then the entire buffer will always be sent ignoring parameters.
+ *
+ * @param x the X coordinate of the rectangular area.
+ * @param y the Y coordinate of the rectangular area.
+ * @param w the width of the rectangular area.
+ * @param h the height of the rectangular area.
+ */
+ public synchronized void newPixels(int x, int y, int w, int h) {
+ newPixels(x, y, w, h, true);
+ }
+
+ /**
+ * Sends a new buffer of pixels to the ImageConsumers
+ * and notifies them that an animation frame is completed if
+ * the animated flag has been set to true by the setAnimated() method.
+ */
+ public void newPixels() {
+ newPixels(0, 0, width, height, true);
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param width the width
+ * @param height the height
+ * @param model the model
+ * @param pixels the pixels
+ * @param off the off
+ * @param scan the scan
+ * @param prop the prop
+ */
+ private void init(int width, int height, ColorModel model, byte pixels[],
+ int off, int scan, Hashtable<?, ?> prop){
+
+ this.width = width;
+ this.height = height;
+ this.cm = model;
+ this.bData = pixels;
+ this.offset = off;
+ this.scanline = scan;
+ this.properties = prop;
+ this.dataType = DATA_TYPE_BYTE;
+ this.consumers = new Vector<ImageConsumer>();
+
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param width the width
+ * @param height the height
+ * @param model the model
+ * @param pixels the pixels
+ * @param off the off
+ * @param scan the scan
+ * @param prop the prop
+ */
+ private void init(int width, int height, ColorModel model, int pixels[],
+ int off, int scan, Hashtable<?, ?> prop){
+
+ this.width = width;
+ this.height = height;
+ this.cm = model;
+ this.iData = pixels;
+ this.offset = off;
+ this.scanline = scan;
+ this.properties = prop;
+ this.dataType = DATA_TYPE_INT;
+ this.consumers = new Vector<ImageConsumer>();
+ }
+
+ /**
+ * Sets the pixels.
+ *
+ * @param con the con
+ * @param x the x
+ * @param y the y
+ * @param w the w
+ * @param h the h
+ */
+ private void setPixels(ImageConsumer con, int x, int y, int w, int h){
+ int pixelOff = scanline * y + offset + x;
+
+ switch(dataType){
+ case DATA_TYPE_BYTE:
+ con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline);
+ break;
+ case DATA_TYPE_INT:
+ con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline);
+ break;
+ default:
+ // awt.22A=Wrong type of pixels array
+ throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Sets the header.
+ *
+ * @param con the new header
+ */
+ private synchronized void setHeader(ImageConsumer con){
+ con.setDimensions(width, height);
+ con.setProperties(properties);
+ con.setColorModel(cm);
+ con.setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES) : ImageConsumer.RANDOMPIXELORDER) :
+ (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME));
+ }
+
+}
+
diff --git a/awt/java/awt/image/MultiPixelPackedSampleModel.java b/awt/java/awt/image/MultiPixelPackedSampleModel.java
new file mode 100644
index 0000000..dd44b49
--- /dev/null
+++ b/awt/java/awt/image/MultiPixelPackedSampleModel.java
@@ -0,0 +1,454 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The MultiPixelPackedSampleModel class represents image data with one
+ * band. This class packs multiple pixels with one sample in one data
+ * element and supports the following data types: DataBuffer.TYPE_BYTE,
+ * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT.
+ */
+public class MultiPixelPackedSampleModel extends SampleModel {
+
+ /** The pixel bit stride. */
+ private int pixelBitStride;
+
+ /** The scanline stride. */
+ private int scanlineStride;
+
+ /** The data bit offset. */
+ private int dataBitOffset;
+
+ /** The bit mask. */
+ private int bitMask;
+
+ /** The data element size. */
+ private int dataElementSize;
+
+ /** The pixels per data element. */
+ private int pixelsPerDataElement;
+
+ /**
+ * Instantiates a new MultiPixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param numberOfBits the number of bits per pixel.
+ * @param scanlineStride the scanline stride of the of the image data.
+ * @param dataBitOffset the array of the band offsets.
+ */
+ public MultiPixelPackedSampleModel(int dataType, int w, int h,
+ int numberOfBits, int scanlineStride, int dataBitOffset) {
+
+ super(dataType, w, h, 1);
+ if (dataType != DataBuffer.TYPE_BYTE &&
+ dataType != DataBuffer.TYPE_USHORT &&
+ dataType != DataBuffer.TYPE_INT) {
+ // awt.61=Unsupported data type: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
+ dataType));
+ }
+
+ this.scanlineStride = scanlineStride;
+ if(numberOfBits == 0) {
+ // awt.20C=Number of Bits equals to zero
+ throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$
+ }
+ this.pixelBitStride = numberOfBits;
+ this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
+ if(dataElementSize % pixelBitStride != 0) {
+ // awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries
+ throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$
+ }
+
+ if(dataBitOffset % numberOfBits != 0) {
+ // awt.20E=Data Bit offset is not a multiple of pixel bit stride
+ throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$
+ }
+ this.dataBitOffset = dataBitOffset;
+
+ this.pixelsPerDataElement = dataElementSize / pixelBitStride;
+ this.bitMask = (1 << numberOfBits) - 1;
+ }
+
+ /**
+ * Instantiates a new MultiPixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param numberOfBits the number of bits per pixel.
+ */
+ public MultiPixelPackedSampleModel(int dataType, int w, int h,
+ int numberOfBits) {
+
+ this(dataType, w, h, numberOfBits, (numberOfBits * w +
+ DataBuffer.getDataTypeSize(dataType) - 1) /
+ DataBuffer.getDataTypeSize(dataType), 0);
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ if (obj == null) {
+ bdata = new byte[1];
+ } else {
+ bdata = (byte[]) obj;
+ }
+ bdata[0] = (byte) getSample(x, y, 0, data);
+ obj = bdata;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ if (obj == null) {
+ sdata = new short[1];
+ } else {
+ sdata = (short[]) obj;
+ }
+ sdata[0] = (short) getSample(x, y, 0, data);
+ obj = sdata;
+ break;
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ if (obj == null) {
+ idata = new int[1];
+ } else {
+ idata = (int[]) obj;
+ }
+ idata[0] = getSample(x, y, 0, data);
+ obj = idata;
+ break;
+ }
+
+ return obj;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ setSample(x, y, obj, data, 1, 0);
+ }
+
+ /**
+ * Compares this MultiPixelPackedSampleModel object with
+ * the specified object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if the object is a MultiPixelPackedSampleModel
+ * with the same data parameter values as this MultiPixelPackedSampleModel,
+ * false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) {
+ return false;
+ }
+
+ MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel) o;
+ return this.width == model.width &&
+ this.height == model.height &&
+ this.numBands == model.numBands &&
+ this.dataType == model.dataType &&
+ this.pixelBitStride == model.pixelBitStride &&
+ this.bitMask == model.bitMask &&
+ this.pixelsPerDataElement == model.pixelsPerDataElement &&
+ this.dataElementSize == model.dataElementSize &&
+ this.dataBitOffset == model.dataBitOffset &&
+ this.scanlineStride == model.scanlineStride;
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands != null && bands.length != 1) {
+ // awt.20F=Number of bands must be only 1
+ throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$
+ }
+ return createCompatibleSampleModel(width, height);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixel[];
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ pixel[0] = getSample(x, y, 0, data);
+ return pixel;
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ setSample(x, y, iArray, data, 2, 0);
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int bitnum = dataBitOffset + x * pixelBitStride;
+ int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize);
+ int shift = dataElementSize - (bitnum & (dataElementSize - 1)) -
+ pixelBitStride;
+
+ return (elem >> shift) & bitMask;
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (b != 0) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ setSample(x, y, null, data, 3, s);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer dataBuffer = null;
+ int size = scanlineStride * height;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16);
+ break;
+ case DataBuffer.TYPE_INT:
+ dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32);
+ break;
+ }
+ return dataBuffer;
+ }
+
+ /**
+ * Gets the offset of the specified pixel in the data array.
+ *
+ * @param x the X coordinate of the specified pixel.
+ * @param y the Y coordinate of the specified pixel.
+ *
+ * @return the offset of the specified pixel.
+ */
+ public int getOffset(int x, int y) {
+ return y * scanlineStride + (x * pixelBitStride + dataBitOffset) /
+ dataElementSize;
+ }
+
+ @Override
+ public int getSampleSize(int band) {
+ return pixelBitStride;
+ }
+
+ /**
+ * Gets the bit offset in the data element which
+ * is stored for the specified pixel of a scanline.
+ *
+ * @param x the pixel.
+ *
+ * @return the bit offset of the pixel in the data element.
+ */
+ public int getBitOffset(int x) {
+ return (x * pixelBitStride + dataBitOffset) % dataElementSize;
+ }
+
+ @Override
+ public int[] getSampleSize() {
+ int sampleSizes[] = { pixelBitStride };
+ return sampleSizes;
+ }
+
+ /**
+ * Returns a hash code of this MultiPixelPackedSampleModel class.
+ *
+ * @return the hash code of this MultiPixelPackedSampleModel class.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp = 0;
+
+ hash = width;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= height;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= numBands;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataType;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= scanlineStride;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= pixelBitStride;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataBitOffset;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= bitMask;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataElementSize;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= pixelsPerDataElement;
+ return hash;
+ }
+
+ @Override
+ public int getTransferType() {
+ if (pixelBitStride > 16) {
+ return DataBuffer.TYPE_INT;
+ } else if (pixelBitStride > 8) {
+ return DataBuffer.TYPE_USHORT;
+ } else {
+ return DataBuffer.TYPE_BYTE;
+ }
+ }
+
+ /**
+ * Gets the scanline stride of this MultiPixelPackedSampleModel.
+ *
+ * @return the scanline stride of this MultiPixelPackedSampleModel.
+ */
+ public int getScanlineStride() {
+ return scanlineStride;
+ }
+
+ /**
+ * Gets the pixel bit stride of this MultiPixelPackedSampleModel.
+ *
+ * @return the pixel bit stride of this MultiPixelPackedSampleModel.
+ */
+ public int getPixelBitStride() {
+ return pixelBitStride;
+ }
+
+ @Override
+ public int getNumDataElements() {
+ return 1;
+ }
+
+ /**
+ * Gets the data bit offset.
+ *
+ * @return the data bit offset.
+ */
+ public int getDataBitOffset() {
+ return dataBitOffset;
+ }
+
+ /**
+ * This method is used by other methods of this class. The behaviour of
+ * this method depends on the method which has been invoke this one. The
+ * argument methodId is used to choose valid behaviour in a particular case.
+ * If methodId is equal to 1 it means that this method has been invoked by
+ * the setDataElements() method, 2 - means setPixel(), and setSample() in
+ * any other cases.
+ *
+ * @param x the x
+ * @param y the y
+ * @param obj the obj
+ * @param data the data
+ * @param methodId the method id
+ * @param s the s
+ */
+ private void setSample(final int x, final int y, final Object obj,
+ final DataBuffer data, final int methodId, int s) {
+ if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages
+ .getString("awt.63")); //$NON-NLS-1$
+ }
+
+ final int bitnum = dataBitOffset + x * pixelBitStride;
+ final int idx = y * scanlineStride + bitnum / dataElementSize;
+ final int shift = dataElementSize - (bitnum & (dataElementSize - 1))
+ - pixelBitStride;
+ final int mask = ~(bitMask << shift);
+ int elem = data.getElem(idx);
+
+ switch (methodId) {
+ case 1: { // Invoked from setDataElements()
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ s = ((byte[]) obj)[0] & 0xff;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ s = ((short[]) obj)[0] & 0xffff;
+ break;
+ case DataBuffer.TYPE_INT:
+ s = ((int[]) obj)[0];
+ break;
+ }
+ break;
+ }
+ case 2: { // Invoked from setPixel()
+ s = ((int[]) obj)[0];
+ break;
+ }
+ }
+
+ elem &= mask;
+ elem |= (s & bitMask) << shift;
+ data.setElem(idx, elem);
+ }
+}
+
diff --git a/awt/java/awt/image/PackedColorModel.java b/awt/java/awt/image/PackedColorModel.java
new file mode 100644
index 0000000..7aaefbf
--- /dev/null
+++ b/awt/java/awt/image/PackedColorModel.java
@@ -0,0 +1,383 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class PackedColorModel represents a color model where the
+ * components are just the red, green, and blue bands, plus an alpha
+ * band if alpha is supported.
+ */
+public abstract class PackedColorModel extends ColorModel {
+
+ /** The component masks. */
+ int componentMasks[];
+
+ /** The offsets. */
+ int offsets[];
+
+ /** The scales. */
+ float scales[];
+
+ /**
+ * Instantiates a new packed color model.
+ *
+ * @param space the color space
+ * @param bits the array of component masks
+ * @param colorMaskArray the array that gives the bitmask corresponding
+ * to each color band (red, green, and blue)
+ * @param alphaMask the bitmask corresponding to the alpha band
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model
+ * @param trans the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the number of bits in the combined
+ * bitmasks for the color bands is less than one or greater than 32
+ */
+ public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[],
+ int alphaMask, boolean isAlphaPremultiplied, int trans,
+ int transferType) {
+
+ super(bits, createBits(colorMaskArray, alphaMask), space,
+ (alphaMask == 0 ? false : true), isAlphaPremultiplied, trans,
+ validateTransferType(transferType));
+
+ if (pixel_bits < 1 || pixel_bits > 32) {
+ // awt.236=The bits is less than 1 or greater than 32
+ throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
+ }
+
+ componentMasks = new int[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ componentMasks[i] = colorMaskArray[i];
+ }
+
+ if (hasAlpha) {
+ componentMasks[numColorComponents] = alphaMask;
+ if (this.bits[numColorComponents] == 1) {
+ transparency = Transparency.BITMASK;
+ }
+ }
+
+ parseComponents();
+ }
+
+ /**
+ * Instantiates a new packed color model.
+ *
+ * @param space the color space
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ * @param amask the bitmask corresponding to the alpha band
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model
+ * @param trans the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the number of bits in the combined
+ * bitmasks for the color bands is less than one or greater than 32
+ */
+ public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask,
+ int bmask, int amask, boolean isAlphaPremultiplied, int trans,
+ int transferType) {
+
+ super(bits, createBits(rmask, gmask, bmask, amask), space,
+ (amask == 0 ? false : true), isAlphaPremultiplied, trans,
+ validateTransferType(transferType));
+
+ if (pixel_bits < 1 || pixel_bits > 32) {
+ // awt.236=The bits is less than 1 or greater than 32
+ throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
+ }
+
+ if (cs.getType() != ColorSpace.TYPE_RGB) {
+ // awt.239=The space is not a TYPE_RGB space
+ throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$
+ }
+
+ for (int i = 0; i < numColorComponents; i++) {
+ if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+ // awt.23A=The min/max normalized component values are not 0.0/1.0
+ throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$
+ }
+ }
+ componentMasks = new int[numComponents];
+ componentMasks[0] = rmask;
+ componentMasks[1] = gmask;
+ componentMasks[2] = bmask;
+
+ if (hasAlpha) {
+ componentMasks[3] = amask;
+ if (this.bits[3] == 1) {
+ transparency = Transparency.BITMASK;
+ }
+ }
+
+ parseComponents();
+ }
+
+ @Override
+ public WritableRaster getAlphaRaster(WritableRaster raster) {
+ if(!hasAlpha) {
+ return null;
+ }
+
+ int x = raster.getMinX();
+ int y = raster.getMinY();
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+ int band[] = new int[1];
+ band[0] = raster.getNumBands() - 1;
+ return raster.createWritableChild(x, y, w, h, x, y, band);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof PackedColorModel)) {
+ return false;
+ }
+ PackedColorModel cm = (PackedColorModel) obj;
+
+ return (pixel_bits == cm.getPixelSize() &&
+ transferType == cm.getTransferType() &&
+ cs.getType() == cm.getColorSpace().getType() &&
+ hasAlpha == cm.hasAlpha() &&
+ isAlphaPremultiplied == cm.isAlphaPremultiplied() &&
+ transparency == cm.getTransparency() &&
+ numColorComponents == cm.getNumColorComponents()&&
+ numComponents == cm.getNumComponents() &&
+ Arrays.equals(bits, cm.getComponentSize()) &&
+ Arrays.equals(componentMasks, cm.getMasks()));
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ if (sm == null) {
+ return false;
+ }
+ if (!(sm instanceof SinglePixelPackedSampleModel)) {
+ return false;
+ }
+ SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel) sm;
+
+ return ((esm.getNumBands() == numComponents) &&
+ (esm.getTransferType() == transferType) &&
+ Arrays.equals(esm.getBitMasks(), componentMasks));
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new SinglePixelPackedSampleModel(transferType, w, h,
+ componentMasks);
+ }
+
+ /**
+ * Gets the bitmask corresponding to the specified color component.
+ *
+ * @param index the index of the desired color
+ *
+ * @return the mask
+ */
+ public final int getMask(int index) {
+ return componentMasks[index];
+ }
+
+ /**
+ * Gets the bitmasks of the components.
+ *
+ * @return the masks
+ */
+ public final int[] getMasks() {
+ return (componentMasks.clone());
+ }
+
+ /**
+ * Creates the bits.
+ *
+ * @param colorMaskArray the color mask array
+ * @param alphaMask the alpha mask
+ *
+ * @return the int[]
+ */
+ private static int[] createBits(int colorMaskArray[], int alphaMask) {
+ int bits[];
+ int numComp;
+ if (alphaMask == 0) {
+ numComp = colorMaskArray.length;
+ } else {
+ numComp = colorMaskArray.length + 1;
+ }
+
+ bits = new int[numComp];
+ int i = 0;
+ for (; i < colorMaskArray.length; i++) {
+ bits[i] = countCompBits(colorMaskArray[i]);
+ if (bits[i] < 0) {
+ // awt.23B=The mask of the {0} component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$
+ }
+ }
+
+ if (i < numComp) {
+ bits[i] = countCompBits(alphaMask);
+
+ if (bits[i] < 0) {
+ // awt.23C=The mask of the alpha component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
+ }
+ }
+
+ return bits;
+ }
+
+ /**
+ * Creates the bits.
+ *
+ * @param rmask the rmask
+ * @param gmask the gmask
+ * @param bmask the bmask
+ * @param amask the amask
+ *
+ * @return the int[]
+ */
+ private static int[] createBits(int rmask, int gmask, int bmask,
+ int amask) {
+
+ int numComp;
+ if (amask == 0) {
+ numComp = 3;
+ } else {
+ numComp = 4;
+ }
+ int bits[] = new int[numComp];
+
+ bits[0] = countCompBits(rmask);
+ if (bits[0] < 0) {
+ // awt.23D=The mask of the red component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$
+ }
+
+ bits[1] = countCompBits(gmask);
+ if (bits[1] < 0) {
+ // awt.23E=The mask of the green component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$
+ }
+
+ bits[2] = countCompBits(bmask);
+ if (bits[2] < 0) {
+ // awt.23F=The mask of the blue component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$
+ }
+
+ if (amask != 0) {
+ bits[3] = countCompBits(amask);
+ if (bits[3] < 0) {
+ // awt.23C=The mask of the alpha component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
+ }
+ }
+
+ return bits;
+ }
+
+ /**
+ * Count comp bits.
+ *
+ * @param compMask the comp mask
+ *
+ * @return the int
+ */
+ private static int countCompBits(int compMask) {
+ int bits = 0;
+ if (compMask != 0) {
+ // Deleting final zeros
+ while ((compMask & 1) == 0) {
+ compMask >>>= 1;
+ }
+ // Counting component bits
+ while ((compMask & 1) == 1) {
+ compMask >>>= 1;
+ bits++;
+ }
+ }
+
+ if (compMask != 0) {
+ return -1;
+ }
+
+ return bits;
+ }
+
+ /**
+ * Validate transfer type.
+ *
+ * @param transferType the transfer type
+ *
+ * @return the int
+ */
+ private static int validateTransferType(int transferType) {
+ if (transferType != DataBuffer.TYPE_BYTE &&
+ transferType != DataBuffer.TYPE_USHORT &&
+ transferType != DataBuffer.TYPE_INT) {
+ // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
+ throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$
+ }
+ return transferType;
+}
+
+ /**
+ * Parses the components.
+ */
+ private void parseComponents() {
+ offsets = new int[numComponents];
+ scales = new float[numComponents];
+ for (int i = 0; i < numComponents; i++) {
+ int off = 0;
+ int mask = componentMasks[i];
+ while ((mask & 1) == 0) {
+ mask >>>= 1;
+ off++;
+ }
+ offsets[i] = off;
+ if (bits[i] == 0) {
+ scales[i] = 256.0f; // May be any value different from zero,
+ // because will dividing by zero
+ } else {
+ scales[i] = 255.0f / maxValues[i];
+ }
+ }
+
+ }
+
+}
+
diff --git a/awt/java/awt/image/PixelGrabber.java b/awt/java/awt/image/PixelGrabber.java
new file mode 100644
index 0000000..cecd5c8
--- /dev/null
+++ b/awt/java/awt/image/PixelGrabber.java
@@ -0,0 +1,408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class PixelGrabber implements ImageConsumer {
+
+ int width;
+ int height;
+ int X;
+ int Y;
+ int offset;
+ int scanline;
+ ImageProducer producer;
+
+ byte bData[];
+ int iData[];
+ ColorModel cm;
+
+ private int grabberStatus;
+ private int dataType;
+ private boolean isGrabbing;
+ private boolean isRGB;
+
+
+ private static final int DATA_TYPE_BYTE = 0;
+ private static final int DATA_TYPE_INT = 1;
+ private static final int DATA_TYPE_UNDEFINED = 2;
+
+ private static final int ALL_BITS = (ImageObserver.FRAMEBITS |
+ ImageObserver.ALLBITS);
+
+ private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR;
+
+
+
+ public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix,
+ int off, int scansize) {
+ initialize(ip, x, y, w, h, pix, off, scansize, true);
+ }
+
+ public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix,
+ int off, int scansize) {
+ initialize(img.getSource(), x, y, w, h, pix, off, scansize, true);
+ }
+
+ public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) {
+ initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB);
+ }
+
+ public void setProperties(Hashtable<?, ?> props) {
+ return;
+ }
+
+ public synchronized Object getPixels() {
+ switch(dataType){
+ case DATA_TYPE_BYTE:
+ return bData;
+ case DATA_TYPE_INT:
+ return iData;
+ default:
+ return null;
+ }
+ }
+
+ public void setColorModel(ColorModel model) {
+ return;
+ }
+
+ public void setPixels(int srcX, int srcY, int srcW, int srcH,
+ ColorModel model, byte[] pixels, int srcOff, int srcScan) {
+ if(srcY < Y){
+ int delta = Y - srcY;
+ if(delta >= height) {
+ return;
+ }
+ srcY += delta;
+ srcH -= delta;
+ srcOff += srcScan * delta;
+ }
+
+ if(srcY + srcH > Y + height){
+ srcH = Y + height - srcY;
+ if(srcH <= 0) {
+ return;
+ }
+ }
+
+ if(srcX < X){
+ int delta = X - srcX;
+ if(delta >= width) {
+ return;
+ }
+ srcW -= delta;
+ srcX += delta;
+ srcOff += delta;
+ }
+
+ if(srcX + srcW > X + width){
+ srcW = X + width - srcX;
+ if(srcW <= 0) {
+ return;
+ }
+ }
+ if(scanline == 0) {
+ scanline = width;
+ }
+ int realOff = offset + (srcY - Y) * scanline + (srcX - X);
+ switch(dataType){
+ case DATA_TYPE_UNDEFINED:
+ cm = model;
+ if(model != ColorModel.getRGBdefault()){
+ bData = new byte[width * height];
+ isRGB = false;
+ dataType = DATA_TYPE_BYTE;
+ }else{
+ iData = new int[width * height];
+ isRGB = true;
+ dataType = DATA_TYPE_INT;
+ }
+ case DATA_TYPE_BYTE:
+ if(!isRGB && cm == model){
+ for(int y = 0; y < srcH; y++){
+ System.arraycopy(pixels, srcOff, bData, realOff, srcW);
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ break;
+ }
+ forceToRGB();
+ case DATA_TYPE_INT:
+ for(int y = 0; y < srcH; y++){
+ for(int x = 0; x < srcW; x++){
+ iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff);
+ }
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ }
+
+ return;
+ }
+
+ public void setPixels(int srcX, int srcY, int srcW, int srcH,
+ ColorModel model, int[] pixels, int srcOff, int srcScan) {
+
+ if(srcY < Y){
+ int delta = Y - srcY;
+ if(delta >= height) {
+ return;
+ }
+ srcY += delta;
+ srcH -= delta;
+ srcOff += srcScan * delta;
+ }
+
+ if(srcY + srcH > Y + height){
+ srcH = Y + height - srcY;
+ if(srcH <= 0) {
+ return;
+ }
+ }
+
+ if(srcX < X){
+ int delta = X - srcX;
+ if(delta >= width) {
+ return;
+ }
+ srcW -= delta;
+ srcX += delta;
+ srcOff += delta;
+ }
+
+ if(srcX + srcW > X + width){
+ srcW = X + width - srcX;
+ if(srcW <= 0) {
+ return;
+ }
+ }
+ if(scanline == 0) {
+ scanline = width;
+ }
+ int realOff = offset + (srcY - Y) * scanline + (srcX - X);
+
+ int mask = 0xFF;
+
+ switch(dataType){
+ case DATA_TYPE_UNDEFINED:
+ cm = model;
+ iData = new int[width * height];
+ dataType = DATA_TYPE_INT;
+ isRGB = (cm == ColorModel.getRGBdefault());
+
+ case DATA_TYPE_INT:
+ if(cm == model){
+ for(int y = 0; y < srcH; y++){
+ System.arraycopy(pixels, srcOff, iData, realOff, srcW);
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ break;
+ }
+ mask = 0xFFFFFFFF;
+
+ case DATA_TYPE_BYTE:
+ forceToRGB();
+ for(int y = 0; y < srcH; y++){
+ for(int x = 0; x < srcW; x++){
+ iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask);
+ }
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ }
+ }
+
+ public synchronized ColorModel getColorModel() {
+ return cm;
+ }
+
+ public synchronized boolean grabPixels(long ms)
+ throws InterruptedException {
+ if((grabberStatus & GRABBING_STOP) != 0){
+ return ((grabberStatus & ALL_BITS) != 0);
+ }
+
+ long start = System.currentTimeMillis();
+
+ if(!isGrabbing){
+ isGrabbing = true;
+ grabberStatus &= ~ImageObserver.ABORT;
+ producer.startProduction(this);
+ }
+ while((grabberStatus & GRABBING_STOP) == 0){
+ if(ms != 0){
+ ms = start + ms - System.currentTimeMillis();
+ if(ms <= 0) {
+ break;
+ }
+ }
+ wait(ms);
+ }
+
+ return ((grabberStatus & ALL_BITS) != 0);
+ }
+
+ public void setDimensions(int w, int h) {
+ if(width < 0) {
+ width = w - X;
+ }
+ if(height < 0) {
+ height = h - Y;
+ }
+
+ grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
+
+ if(width <=0 || height <=0){
+ imageComplete(STATICIMAGEDONE);
+ return;
+ }
+
+ if(isRGB && dataType == DATA_TYPE_UNDEFINED){
+ iData = new int[width * height];
+ dataType = DATA_TYPE_INT;
+ scanline = width;
+ }
+ }
+
+ public void setHints(int hints) {
+ return;
+ }
+
+ public synchronized void imageComplete(int status) {
+ switch(status){
+ case IMAGEABORTED:
+ grabberStatus |= ImageObserver.ABORT;
+ break;
+ case IMAGEERROR:
+ grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT;
+ break;
+ case SINGLEFRAMEDONE:
+ grabberStatus |= ImageObserver.FRAMEBITS;
+ break;
+ case STATICIMAGEDONE:
+ grabberStatus |= ImageObserver.ALLBITS;
+ break;
+ default:
+ // awt.26A=Incorrect ImageConsumer completion status
+ throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$
+ }
+ isGrabbing = false;
+ producer.removeConsumer(this);
+ notifyAll();
+ }
+
+ public boolean grabPixels() throws InterruptedException {
+ return grabPixels(0);
+ }
+
+ public synchronized void startGrabbing() {
+ if((grabberStatus & GRABBING_STOP) != 0){
+ return;
+ }
+ if(!isGrabbing){
+ isGrabbing = true;
+ grabberStatus &= ~ImageObserver.ABORT;
+ producer.startProduction(this);
+ }
+ }
+
+ public synchronized void abortGrabbing() {
+ imageComplete(IMAGEABORTED);
+ }
+
+ public synchronized int status() {
+ return grabberStatus;
+ }
+
+ public synchronized int getWidth() {
+ if(width < 0) {
+ return -1;
+ }
+ return width;
+ }
+
+ public synchronized int getStatus() {
+ return grabberStatus;
+ }
+
+ public synchronized int getHeight() {
+ if(height < 0) {
+ return -1;
+ }
+ return height;
+ }
+
+ private void initialize(ImageProducer ip, int x, int y, int w, int h,
+ int pixels[], int off, int scansize, boolean forceRGB){
+
+ producer = ip;
+ X = x;
+ Y = y;
+ width = w;
+ height = h;
+ iData = pixels;
+ dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT;
+ offset = off;
+ scanline = scansize;
+ if(forceRGB){
+ cm = ColorModel.getRGBdefault();
+ isRGB = true;
+ }
+ }
+
+ /**
+ * Force pixels to INT RGB mode
+ */
+ private void forceToRGB(){
+ if (isRGB)
+ return;
+
+ switch(dataType){
+ case DATA_TYPE_BYTE:
+ iData = new int[width * height];
+ for(int i = 0; i < iData.length; i++){
+ iData[i] = cm.getRGB(bData[i] & 0xff);
+ }
+ dataType = DATA_TYPE_INT;
+ bData = null;
+ break;
+
+ case DATA_TYPE_INT:
+ int buff[] = new int[width * height];
+ for(int i = 0; i < iData.length; i++){
+ buff[i] = cm.getRGB(iData[i]);
+ }
+ iData = buff;
+ break;
+ }
+ offset = 0;
+ scanline = width;
+ cm = ColorModel.getRGBdefault();
+ isRGB = true;
+ }
+
+}
diff --git a/awt/java/awt/image/PixelInterleavedSampleModel.java b/awt/java/awt/image/PixelInterleavedSampleModel.java
new file mode 100644
index 0000000..e41473e
--- /dev/null
+++ b/awt/java/awt/image/PixelInterleavedSampleModel.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The PixelInterleavedSampleModel class represents image data
+ * as represented as interleaved pixels and for which each sample of
+ * a pixel takes one data element of the DataBuffer.
+ */
+public class PixelInterleavedSampleModel extends ComponentSampleModel {
+
+ /**
+ * Instantiates a new PixelInterleavedSampleModel with the
+ * specified parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param pixelStride the pixel stride of the image data.
+ * @param scanlineStride the scanline stride of the of the image data.
+ * @param bandOffsets the array of the band offsets.
+ */
+ public PixelInterleavedSampleModel(int dataType, int w, int h,
+ int pixelStride, int scanlineStride, int bandOffsets[]) {
+
+ super(dataType, w, h, pixelStride, scanlineStride, bandOffsets);
+
+ int maxOffset = bandOffsets[0];
+ int minOffset = bandOffsets[0];
+ for (int i = 1; i < bandOffsets.length; i++) {
+ if (bandOffsets[i] > maxOffset) {
+ maxOffset = bandOffsets[i];
+ }
+ if (bandOffsets[i] < minOffset) {
+ minOffset = bandOffsets[i];
+ }
+ }
+
+ maxOffset -= minOffset;
+
+ if (maxOffset > scanlineStride) {
+ // awt.241=Any offset between bands is greater than the Scanline stride
+ throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$
+ }
+
+ if (maxOffset > pixelStride) {
+ // awt.242=Pixel stride is less than any offset between bands
+ throw new IllegalArgumentException(Messages.getString("awt.242")); //$NON-NLS-1$
+ }
+
+ if (pixelStride * w > scanlineStride) {
+ // awt.243=Product of Pixel stride and w is greater than Scanline stride
+ throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$
+ }
+
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ int newOffsets[] = new int[bands.length];
+ for (int i = 0; i < bands.length; i++) {
+ newOffsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new PixelInterleavedSampleModel(dataType, width, height,
+ pixelStride, scanlineStride, newOffsets);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ int newOffsets[];
+ int minOffset = bandOffsets[0];
+
+ for (int i = 1; i < numBands; i++) {
+ if (bandOffsets[i] < minOffset) {
+ minOffset = bandOffsets[i];
+ }
+ }
+
+ if (minOffset > 0) {
+ newOffsets = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ newOffsets[i] = bandOffsets[i] - minOffset;
+ }
+ } else {
+ newOffsets = bandOffsets;
+ }
+
+ return new PixelInterleavedSampleModel(dataType, w, h, pixelStride,
+ pixelStride * w, newOffsets);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ int tmp = hash >>> 8;
+ hash <<= 8;
+ hash |= tmp;
+
+ return hash ^ 0x66;
+ }
+
+}
+
diff --git a/awt/java/awt/image/RGBImageFilter.java b/awt/java/awt/image/RGBImageFilter.java
new file mode 100644
index 0000000..9a76997
--- /dev/null
+++ b/awt/java/awt/image/RGBImageFilter.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * The RGBImageFilter class represents a filter which modifies
+ * pixels of an image in the default RGB ColorModel.
+ */
+public abstract class RGBImageFilter extends ImageFilter {
+
+ /**
+ * The origmodel is the ColorModel to be replaced by newmodel
+ * when substituteColorModel is called.
+ */
+ protected ColorModel origmodel;
+
+ /**
+ * The newmodel is the ColorModel with which to replace origmodel
+ * when substituteColorModel is called.
+ */
+ protected ColorModel newmodel;
+
+ /**
+ * The canFilterIndexColorModel indicates if it is
+ * acceptable to apply the color filtering of the filterRGB
+ * method to the color table entries of an IndexColorModel
+ * object.
+ * */
+ protected boolean canFilterIndexColorModel;
+
+ /**
+ * Instantiates a new RGBImageFilter.
+ */
+ public RGBImageFilter() {}
+
+ /**
+ * Filters an IndexColorModel object by calling filterRGB function for
+ * each entry of IndexColorModel.
+ *
+ * @param icm the IndexColorModel to be filtered.
+ *
+ * @return the IndexColorModel.
+ */
+ public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
+ int transferType = icm.getTransferType();
+ int bits = icm.getPixelSize();
+ int mapSize = icm.getMapSize();
+ int colorMap[] = new int[mapSize];
+ int filteredColorMap[] = new int[mapSize];
+ icm.getRGBs(colorMap);
+ int trans = -1;
+ boolean hasAlpha = false;
+ for(int i = 0; i < mapSize; i++){
+ filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]);
+ int alpha = filteredColorMap[i] >>> 24;
+ if(alpha != 0xff){
+ if(!hasAlpha) {
+ hasAlpha = true;
+ }
+ if(alpha == 0 && trans < 0) {
+ trans = i;
+ }
+ }
+ }
+
+ return new IndexColorModel(bits, mapSize, filteredColorMap, 0,
+ hasAlpha, trans, transferType);
+ }
+
+ /**
+ * Replaces the original color model and the new one.
+ *
+ * @param oldcm the old ColorModel.
+ * @param newcm the new ColorModel.
+ */
+ public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
+ origmodel = oldcm;
+ newmodel = newcm;
+ }
+
+ @Override
+ public void setColorModel(ColorModel model) {
+ if(model instanceof IndexColorModel &&
+ canFilterIndexColorModel){
+ IndexColorModel icm = (IndexColorModel) model;
+ ColorModel filteredModel = filterIndexColorModel(icm);
+ substituteColorModel(model, filteredModel);
+ consumer.setColorModel(filteredModel);
+ }else{
+ consumer.setColorModel(ColorModel.getRGBdefault());
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ int[] pixels, int off, int scansize) {
+
+ if(model == null || model == origmodel){
+ consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
+ }else{
+ int rgbPixels[] = new int[w];
+ for(int sy = y, pixelsOff = off; sy < y + h;
+ sy++, pixelsOff += scansize){
+
+ for(int sx = x, idx = 0; sx < x + w; sx++, idx++){
+ rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]);
+ }
+ filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w);
+ }
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ byte[] pixels, int off, int scansize) {
+
+ if(model == null || model == origmodel){
+ consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
+ }else{
+ int rgbPixels[] = new int[w];
+ for(int sy = y, pixelsOff = off; sy < y + h;
+ sy++, pixelsOff += scansize){
+
+ for(int sx = x, idx = 0; sx < x + w; sx++, idx++){
+ rgbPixels[idx] =
+ model.getRGB(pixels[pixelsOff + idx] & 0xff);
+ }
+ filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w);
+ }
+ }
+ }
+
+ /**
+ * Filters a region of pixels in the default RGB ColorModel
+ * by calling the filterRGB method for them.
+ *
+ * @param x the X coordinate of region.
+ * @param y the Y coordinate of region.
+ * @param w the width ofregion.
+ * @param h the height of region.
+ * @param pixels the pixels array.
+ * @param off the offset of array.
+ * @param scansize the distance between rows of pixels in the array.
+ */
+ public void filterRGBPixels(int x, int y, int w, int h,
+ int[] pixels, int off, int scansize) {
+
+ for(int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize){
+ for(int sx = x, idx = 0; sx < x + w; sx++, idx++){
+ pixels[lineOff + idx] =
+ filterRGB(sx, sy, pixels[lineOff + idx]);
+ }
+ }
+ consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(),
+ pixels, off, scansize);
+ }
+
+ /**
+ * Coverts a single input pixel in the default RGB ColorModel
+ * to a single output pixel.
+ *
+ * @param x the X pixel's coordinate.
+ * @param y the Y pixel's coordinate.
+ * @param rgb a pixel in the default RGB color model.
+ *
+ * @return a filtered pixel in the default RGB color model.
+ */
+ public abstract int filterRGB(int x, int y, int rgb);
+
+}
+
diff --git a/awt/java/awt/image/Raster.java b/awt/java/awt/image/Raster.java
new file mode 100644
index 0000000..4b2426e
--- /dev/null
+++ b/awt/java/awt/image/Raster.java
@@ -0,0 +1,1412 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Raster class represents a rectangular area of pixels.
+ * This class is defined by DataBuffer and SampleModel objects.
+ * The DataBuffer object stores sample values and DSampleModel defines
+ * the location of sample in this DataBuffer.
+ */
+public class Raster {
+
+ /** The DataBuffer of this Raster. */
+ protected DataBuffer dataBuffer;
+
+ /** The height of this Raster. */
+ protected int height;
+
+ /** The X coordinate of the upper left pixel in this Raster. */
+ protected int minX;
+
+ /** The Y coordinate of the upper left pixel in this Raster. */
+ protected int minY;
+
+ /** The number of bands in this Raster. */
+ protected int numBands;
+
+ /** The number of data elements. */
+ protected int numDataElements;
+
+ /** The parent of this Raster. */
+ protected Raster parent;
+
+ /** The SampleModel of this Raster. */
+ protected SampleModel sampleModel;
+
+ /**
+ * The X translation from the coordinate space of the
+ * SampleModel of this Raster.
+ */
+ protected int sampleModelTranslateX;
+
+ /**
+ * The Y translation from the coordinate space of the
+ * SampleModel of this Raster.
+ */
+ protected int sampleModelTranslateY;
+
+ /** The width of this Raster. */
+ protected int width;
+
+ /**
+ * Creates a Raster object with a BandedSampleModel and the specified
+ * DataBuffer. The number of bands is defined by the length of bandOffsets
+ * or bankIndices arrays.
+ *
+ * @param dataBuffer the specified DataBuffer.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bankIndices the bank indices of bands.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createBandedRaster(DataBuffer dataBuffer,
+ int w, int h, int scanlineStride, int bankIndices[],
+ int bandOffsets[], Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bankIndices == null || bandOffsets == null) {
+ // awt.277=bankIndices or bandOffsets is null
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h,
+ scanlineStride, bankIndices, bandOffsets);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+ }
+
+ /**
+ * Creates a Raster object with a BandedSampleModel and the specified
+ * data type. The Data type can be one of the following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of the samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bankIndices the bank indices of bands.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createBandedRaster(int dataType, int w, int h,
+ int scanlineStride, int bankIndices[], int bandOffsets[],
+ Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bankIndices == null || bandOffsets == null) {
+ // awt.277=bankIndices or bandOffsets is null
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ int maxOffset = bandOffsets[0];
+ int maxBank = bankIndices[0];
+
+ for (int i = 0; i < bankIndices.length; i++) {
+ if (bandOffsets[i] > maxOffset) {
+ maxOffset = bandOffsets[i];
+ }
+ if (bankIndices[i] > maxBank) {
+ maxBank = bankIndices[i];
+ }
+ }
+
+ int numBanks = maxBank + 1;
+ int dataSize = scanlineStride * (h - 1) + w + maxOffset;
+
+ DataBuffer data = null;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(dataSize, numBanks);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(dataSize, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(dataSize, numBanks);
+ break;
+ }
+ return createBandedRaster(data, w, h, scanlineStride, bankIndices,
+ bandOffsets, location);
+ }
+
+ /**
+ * Creates a Raster object with a BandedSampleModel and the specified
+ * data type. The Data type can be one of the following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of the samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bands the number of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createBandedRaster(int dataType, int w, int h,
+ int bands, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bands < 1) {
+ // awt.279=bands is less than 1
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.279")); //$NON-NLS-1$
+ }
+
+ int bandOffsets[] = new int[bands];
+ int bankIndices[] = new int[bands];
+
+ for (int i = 0; i < bands; i++) {
+ bandOffsets[i] = 0;
+ bankIndices[i] = i;
+ }
+ return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets,
+ location);
+ }
+
+ /**
+ * Creates a Raster object with a PixelInterleavedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataBuffer the DataBuffer.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param pixelStride the pixel stride of image data.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer,
+ int w, int h, int scanlineStride, int pixelStride,
+ int bandOffsets[], Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer.getNumBanks() > 1) {
+ // awt.27A=dataBuffer has more than one bank
+ throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+ }
+
+ if (bandOffsets == null) {
+ // awt.27B=bandOffsets is null
+ throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$
+ }
+
+ PixelInterleavedSampleModel sampleModel =
+ new PixelInterleavedSampleModel(dataType, w, h,
+ pixelStride, scanlineStride, bandOffsets);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+
+ }
+
+ /**
+ * Creates a Raster object with a PixelInterleavedSampleModel
+ * and the specified data type. The Data type can be one of the
+ * following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of the samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param pixelStride the pixel stride of image data.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createInterleavedRaster(int dataType, int w,
+ int h, int scanlineStride, int pixelStride, int bandOffsets[],
+ Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (bandOffsets == null) {
+ // awt.27B=bandOffsets is null
+ throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$
+ }
+
+ int minOffset = bandOffsets[0];
+ for (int i = 1; i < bandOffsets.length; i++) {
+ if (bandOffsets[i] < minOffset) {
+ minOffset = bandOffsets[i];
+ }
+ }
+ int size = (h - 1) * scanlineStride + w * pixelStride + minOffset;
+ DataBuffer data = null;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size);
+ break;
+ }
+
+ return createInterleavedRaster(data, w, h, scanlineStride, pixelStride,
+ bandOffsets, location);
+ }
+
+ /**
+ * Creates a Raster object with a PixelInterleavedSampleModel
+ * and the specified data type. The Data type can be one of the
+ * following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param bands the number of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createInterleavedRaster(int dataType, int w,
+ int h, int bands, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ int bandOffsets[] = new int[bands];
+ for (int i = 0; i < bands; i++) {
+ bandOffsets[i] = i;
+ }
+
+ return createInterleavedRaster(dataType, w, h, w * bands, bands,
+ bandOffsets, location);
+ }
+
+ /**
+ * Creates a Raster object with a SinglePixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataBuffer the DataBuffer.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bandMasks the band masks.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(DataBuffer dataBuffer,
+ int w, int h, int scanlineStride, int bandMasks[], Point location) {
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bandMasks == null) {
+ // awt.27C=bandMasks is null
+ throw new RasterFormatException(Messages.getString("awt.27C")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer.getNumBanks() > 1) {
+ // awt.27A=dataBuffer has more than one bank
+ throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ SinglePixelPackedSampleModel sampleModel =
+ new SinglePixelPackedSampleModel(dataType, w, h,
+ scanlineStride, bandMasks);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+ }
+
+ /**
+ * Creates a Raster object with a MultiPixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataBuffer the DataBuffer.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bitsPerPixel the number of bits per pixel.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(DataBuffer dataBuffer,
+ int w, int h, int bitsPerPixel, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer.getNumBanks() > 1) {
+ // awt.27A=dataBuffer has more than one bank
+ throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ MultiPixelPackedSampleModel sampleModel =
+ new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+
+ }
+
+ /**
+ * Creates a Raster object with a MultiPixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataType the data type of samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bands the number of bands.
+ * @param bitsPerBand the number of bits per band.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(int dataType, int w, int h,
+ int bands, int bitsPerBand, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bands < 1 || bitsPerBand < 1) {
+ // awt.27D=bitsPerBand or bands is not greater than zero
+ throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) {
+ // awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType
+ throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$
+ }
+
+ if (bands > 1) {
+
+ int bandMasks[] = new int[bands];
+ int mask = (1 << bitsPerBand) - 1;
+
+ for (int i = 0; i < bands; i++) {
+ bandMasks[i] = mask << (bitsPerBand * (bands - 1 - i));
+ }
+
+ return createPackedRaster(dataType, w, h, bandMasks, location);
+ }
+ DataBuffer data = null;
+ int size = ((bitsPerBand * w +
+ DataBuffer.getDataTypeSize(dataType) - 1) /
+ DataBuffer.getDataTypeSize(dataType)) * h;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size);
+ break;
+ }
+ return createPackedRaster(data, w, h, bitsPerBand, location);
+ }
+
+ /**
+ * Creates a Raster object with a SinglePixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataType the data type of samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bandMasks the band masks.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(int dataType, int w, int h,
+ int bandMasks[], Point location) {
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bandMasks == null) {
+ // awt.27C=bandMasks is null
+ throw new NullPointerException(Messages.getString("awt.27C")); //$NON-NLS-1$
+ }
+
+ DataBuffer data = null;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(w * h);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(w * h);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(w * h);
+ break;
+ }
+
+ return createPackedRaster(data, w, h, w, bandMasks, location);
+ }
+
+ /**
+ * Creates a Raster object with the specified DataBuffer and SampleModel.
+ *
+ * @param sm the specified SampleModel.
+ * @param db the specified DataBuffer.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the Raster.
+ */
+ public static Raster createRaster(SampleModel sm, DataBuffer db,
+ Point location) {
+
+ if (sm == null || db == null) {
+ // awt.27F=SampleModel or DataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ return new Raster(sm, db, location);
+ }
+
+ /**
+ * Creates a WritableRaster with the specified SampleModel and DataBuffer.
+ *
+ * @param sm the specified SampleModel.
+ * @param db the specified DataBuffer.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createWritableRaster(SampleModel sm,
+ DataBuffer db, Point location) {
+
+ if (sm == null || db == null) {
+ // awt.27F=SampleModel or DataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ return new OrdinaryWritableRaster(sm, db, location);
+ }
+
+ /**
+ * Creates a WritableRaster with the specified SampleModel.
+ *
+ * @param sm the specified SampleModel.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createWritableRaster(SampleModel sm,
+ Point location) {
+
+ if (sm == null) {
+ // awt.280=SampleModel is null
+ throw new NullPointerException(Messages.getString("awt.280")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ return createWritableRaster(sm, sm.createDataBuffer(), location);
+ }
+
+ /**
+ * Instantiates a new Raster object with the specified SampleModel and
+ * DataBuffer.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param origin the specified origin.
+ */
+ protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Point origin) {
+
+ this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
+ sampleModel.getWidth(), sampleModel.getHeight()), origin, null);
+ }
+
+ /**
+ * Instantiates a new Raster object with the specified SampleModel,
+ * DataBuffer, rectangular region and parent Raster.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param aRegion the a rectangular region which defines the new image bounds.
+ * @param sampleModelTranslate this point defines the translation point
+ * from the SampleModel coordinates to the new Raster coordinates.
+ * @param parent the parent of this Raster.
+ */
+ protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Rectangle aRegion, Point sampleModelTranslate, Raster parent) {
+
+ if (sampleModel == null || dataBuffer == null || aRegion == null
+ || sampleModelTranslate == null) {
+ // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null
+ throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$
+ }
+
+ if (aRegion.width <= 0 || aRegion.height <= 0) {
+ // awt.282=aRegion has width or height less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$
+ }
+
+ if ((long) aRegion.x + (long) aRegion.width > Integer.MAX_VALUE) {
+ // awt.283=Overflow X coordinate of Raster
+ throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$
+ }
+
+ if ((long) aRegion.y + (long) aRegion.height > Integer.MAX_VALUE) {
+ // awt.284=Overflow Y coordinate of Raster
+ throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$
+ }
+
+ if (sampleModel instanceof ComponentSampleModel) {
+ validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+ ((ComponentSampleModel) sampleModel).getScanlineStride());
+ } else if (sampleModel instanceof MultiPixelPackedSampleModel) {
+ validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+ ((MultiPixelPackedSampleModel) sampleModel)
+ .getScanlineStride());
+ } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
+ validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+ ((SinglePixelPackedSampleModel) sampleModel)
+ .getScanlineStride());
+ }
+
+ this.sampleModel = sampleModel;
+ this.dataBuffer = dataBuffer;
+ this.minX = aRegion.x;
+ this.minY = aRegion.y;
+ this.width = aRegion.width;
+ this.height = aRegion.height;
+ this.sampleModelTranslateX = sampleModelTranslate.x;
+ this.sampleModelTranslateY = sampleModelTranslate.y;
+ this.parent = parent;
+ this.numBands = sampleModel.getNumBands();
+ this.numDataElements = sampleModel.getNumDataElements();
+
+ }
+
+ /**
+ * Instantiates a new Raster with the specified SampleModel.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param origin the origin.
+ */
+ protected Raster(SampleModel sampleModel, Point origin) {
+ this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(
+ origin.x, origin.y, sampleModel.getWidth(), sampleModel
+ .getHeight()), origin, null);
+ }
+
+ /**
+ * Creates the child of this Raster by sharing the specified rectangular
+ * area in this Raste. The parentX, parentY, width
+ * and height parameters specify the rectangular area to be shared.
+ *
+ * @param parentX the X coordinate of the upper left corner of this Raster.
+ * @param parentY the Y coordinate of the upper left corner of this Raster.
+ * @param width the width of the child area.
+ * @param height the height of the child area.
+ * @param childMinX the X coordinate of child area mapped to the parentX
+ * coordinate.
+ * @param childMinY the Y coordinate of child area mapped to the parentY
+ * coordinate.
+ * @param bandList the array of band indicies.
+ *
+ * @return the Raster.
+ */
+ public Raster createChild(int parentX, int parentY, int width, int height,
+ int childMinX, int childMinY, int bandList[]) {
+ if (width <= 0 || height <= 0) {
+ // awt.285=Width or Height of child Raster is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$
+ }
+
+ if (parentX < this.minX || parentX + width > this.minX + this.width) {
+ // awt.286=parentX disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.286")); //$NON-NLS-1$
+ }
+
+ if (parentY < this.minY || parentY + height > this.minY + this.height) {
+ // awt.287=parentY disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$
+ }
+
+ if ((long) parentX + width > Integer.MAX_VALUE) {
+ // awt.288=parentX + width results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$
+ }
+
+ if ((long) parentY + height > Integer.MAX_VALUE) {
+ // awt.289=parentY + height results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinX + width > Integer.MAX_VALUE) {
+ // awt.28A=childMinX + width results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinY + height > Integer.MAX_VALUE) {
+ // awt.28B=childMinY + height results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$
+ }
+
+ SampleModel childModel;
+
+ if (bandList == null) {
+ childModel = sampleModel;
+ } else {
+ childModel = sampleModel.createSubsetSampleModel(bandList);
+ }
+
+ int childTranslateX = childMinX - parentX;
+ int childTranslateY = childMinY - parentY;
+
+ return new Raster(childModel, dataBuffer, new Rectangle(childMinX,
+ childMinY, width, height), new Point(childTranslateX
+ + sampleModelTranslateX, childTranslateY
+ + sampleModelTranslateY), this);
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster() {
+ return new OrdinaryWritableRaster(sampleModel, new Point(0, 0));
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster and the specified size.
+ *
+ * @param w the width of the new WritableRaster.
+ * @param h the height of the new WritableRaster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
+
+ return new OrdinaryWritableRaster(sm, new Point(0, 0));
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster and the specified size and location.
+ *
+ * @param x the X coordinate of the new WritableRaster.
+ * @param y the Y coordinate of the new WritableRaster.
+ * @param w the width of the new WritableRaster.
+ * @param h the height of the new WritableRaster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster(int x, int y, int w,
+ int h) {
+
+ WritableRaster raster = createCompatibleWritableRaster(w, h);
+
+ return raster.createWritableChild(0, 0, w, h, x, y, null);
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster and the specified rectangle which determines
+ * new WritableRaster's location and size.
+ *
+ * @param rect the specified Rectangle.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster(Rectangle rect) {
+ if (rect == null) {
+ // awt.28C=Rect is null
+ throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$
+ }
+
+ return createCompatibleWritableRaster(rect.x, rect.y, rect.width,
+ rect.height);
+ }
+
+ /**
+ * Creates the translated child of this Raster. The New Raster
+ * object is a reference to the this Raster with a
+ * different location.
+ *
+ * @param childMinX the X coordinate of the new Raster.
+ * @param childMinY the Y coordinate of the new Raster.
+ *
+ * @return the Raster.
+ */
+ public Raster createTranslatedChild(int childMinX, int childMinY) {
+ return createChild(minX, minY, width, height, childMinX, childMinY,
+ null);
+ }
+
+ /**
+ * Gets the bounds of this Raster as a rectangle.
+ *
+ * @return the bounds of this Raster.
+ */
+ public Rectangle getBounds() {
+ return new Rectangle(minX, minY, width, height);
+ }
+
+ /**
+ * Gets the DataBuffer associated with this Raster.
+ *
+ * @return the DataBuffer associated with this Raster.
+ */
+ public DataBuffer getDataBuffer() {
+ return dataBuffer;
+ }
+
+ /**
+ * Gets the data elements which represent the pixel data of the specified
+ * rectangle area as a primitive array. The following image data types
+ * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+ * or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param outData the resulting array.
+ *
+ * @return the data elements of the specified area of this Raster.
+ */
+ public Object getDataElements(int x, int y, int w, int h, Object outData) {
+ return sampleModel.getDataElements(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, outData, dataBuffer);
+ }
+
+ /**
+ * Gets the data elements which represent the specified pixel of
+ * this Raster as a primitive array. The following image data types
+ * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+ * or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param outData the resulting data.
+ *
+ * @return the data elements of the specified pixel of this Raster.
+ */
+ public Object getDataElements(int x, int y, Object outData) {
+ return sampleModel.getDataElements(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, outData, dataBuffer);
+ }
+
+ /**
+ * Gets the height of this Raster.
+ *
+ * @return the height of this Raster.
+ */
+ public final int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the minimum X coordinate of this Raster.
+ *
+ * @return the minimum X coordinate of this Raster.
+ */
+ public final int getMinX() {
+ return minX;
+ }
+
+ /**
+ * Gets the minimum Y coordinate of this Raster.
+ *
+ * @return the minimum Y coordinate of this Raster.
+ */
+ public final int getMinY() {
+ return minY;
+ }
+
+ /**
+ * Gets the number of bands in this Raster.
+ *
+ * @return the number of bands in this Raster.
+ */
+ public final int getNumBands() {
+ return numBands;
+ }
+
+ /**
+ * Gets the number of data elements for one pixel.
+ *
+ * @return the number of data elements for one pixel.
+ */
+ public final int getNumDataElements() {
+ return numDataElements;
+ }
+
+ /**
+ * Gets the parent Raster for this Raster object.
+ *
+ * @return the parent Raster for this Raster object.
+ */
+ public Raster getParent() {
+ return parent;
+ }
+
+ /**
+ * Gets a double array of samples for the specified pixel in this Raster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param dArray the double array where result array will be stored.
+ *
+ * @return the double array of samples for the specified pixel in
+ * this Raster.
+ */
+ public double[] getPixel(int x, int y, double dArray[]) {
+ return sampleModel.getPixel(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, dArray, dataBuffer);
+ }
+
+ /**
+ * Gets a float array of samples for the specified pixel in this Raster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param fArray the float array where the result array will be stored.
+ *
+ * @return the float array of samples for the specified pixel in
+ * this Raster.
+ */
+ public float[] getPixel(int x, int y, float fArray[]) {
+ return sampleModel.getPixel(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, fArray, dataBuffer);
+ }
+
+ /**
+ * Gets an int array of samples for the specified pixel in this Raster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param iArray the int array where the result array will be stored.
+ *
+ * @return the int array of samples for the specified pixel in
+ * this Raster.
+ */
+ public int[] getPixel(int x, int y, int iArray[]) {
+ return sampleModel.getPixel(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, iArray, dataBuffer);
+ }
+
+ /**
+ * Gets an double array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param dArray the resulting array.
+ *
+ * @return the double array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ */
+ public double[] getPixels(int x, int y, int w, int h, double dArray[]) {
+ return sampleModel.getPixels(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, dArray, dataBuffer);
+ }
+
+ /**
+ * Gets an float array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param fArray the resulting array.
+ *
+ * @return the float array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ */
+ public float[] getPixels(int x, int y, int w, int h, float fArray[]) {
+ return sampleModel.getPixels(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, fArray, dataBuffer);
+ }
+
+ /**
+ * Gets an int array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of pixel's the area of pixels.
+ * @param h the height of pixel's the area of pixels.
+ * @param iArray the resulting array.
+ *
+ * @return the int array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ */
+ public int[] getPixels(int x, int y, int w, int h, int iArray[]) {
+ return sampleModel.getPixels(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, iArray, dataBuffer);
+ }
+
+ /**
+ * Gets the sample for the specified band of the specified
+ * pixel as an int.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the sample for the specified band of the specified
+ * pixel as an int.
+ */
+ public int getSample(int x, int y, int b) {
+ return sampleModel.getSample(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, b, dataBuffer);
+ }
+
+ /**
+ * Gets the sample for the specified band of the specified
+ * pixel as a double.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the sample for the specified band of the specified
+ * pixel as a double.
+ */
+ public double getSampleDouble(int x, int y, int b) {
+ return sampleModel.getSampleDouble(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, b, dataBuffer);
+ }
+
+ /**
+ * Gets the sample for the specified band of the specified
+ * pixel as a float.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the sample for the specified band of the specified
+ * pixel as a float.
+ */
+ public float getSampleFloat(int x, int y, int b) {
+ return sampleModel.getSampleFloat(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, b, dataBuffer);
+ }
+
+ /**
+ * Gets the SampleModel associated with this Raster.
+ *
+ * @return the SampleModel associated with this Raster.
+ */
+ public SampleModel getSampleModel() {
+ return sampleModel;
+ }
+
+ /**
+ * Gets the translation of the X coordinate from the SampleModel
+ * coordinate system to the Rasters's coordinate system.
+ *
+ * @return the value of the translation of the X coordinate from
+ * the SampleModel coordinate system to the Rasters's
+ * coordinate system.
+ */
+ public final int getSampleModelTranslateX() {
+ return sampleModelTranslateX;
+ }
+
+ /**
+ * Gets the translation of the Y coordinate from the SampleModel
+ * coordinate system to the Rasters's coordinate system.
+ *
+ * @return the value of the translation of the Y coordinate from
+ * the SampleModel coordinate system to the Rasters's
+ * coordinate system.
+
+ */
+ public final int getSampleModelTranslateY() {
+ return sampleModelTranslateY;
+ }
+
+ /**
+ * Gets the double array of samples for the specified band
+ * of the specified rectangular area of pixels in this Raster
+ * as a double array.
+ *
+ * @param x the X coordinate of the rectangular area of pixels.
+ * @param y the Y coordinate of the rectangular area of pixels.
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param b the band.
+ * @param dArray the resulting double array.
+ *
+ * @return the double array of samples for the specified band
+ * of the specified rectangular area of pixels.
+ */
+ public double[] getSamples(int x, int y, int w, int h, int b,
+ double dArray[]) {
+
+ return sampleModel.getSamples(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, b, dArray, dataBuffer);
+ }
+
+ /**
+ * Gets the float array of samples for the specified band
+ * of the specified rectangular area of pixels in this Raster
+ * as a float array.
+ *
+ * @param x the X coordinate of the rectangular area of pixels.
+ * @param y the Y coordinate of the rectangular area of pixels.
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param b the band.
+ * @param fArray the resulting float array.
+ *
+ * @return the float array of samples for the specified band
+ * of the specified rectangular area of pixels.
+ */
+ public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) {
+
+ return sampleModel.getSamples(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, b, fArray, dataBuffer);
+ }
+
+ /**
+ * Gets the int array of samples for the specified band
+ * of the specified rectangular area of pixels in this Raster
+ * as a int array.
+ *
+ * @param x the X coordinate of the rectangular area of pixels.
+ * @param y the Y coordinate of the rectangular area of pixels.
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param b the band.
+ * @param iArray the resulting int array.
+ *
+ * @return the int array of samples for the specified band
+ * of the specified rectangular area of pixels.
+ */
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) {
+ return sampleModel.getSamples(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, b, iArray, dataBuffer);
+ }
+
+ /**
+ * Gets the transfer type for pixels of this Raster.
+ * @see SampleModel#getTransferType()
+ *
+ * @return the transfer type for pixels of this Raster.
+ */
+ public final int getTransferType() {
+ return sampleModel.getTransferType();
+ }
+
+ /**
+ * Gets the width of this Raster.
+ *
+ * @return the width of this Raster.
+ */
+ public final int getWidth() {
+ return width;
+ }
+
+ /**
+ * Validate data buffer.
+ *
+ * @param dataBuffer the data buffer
+ * @param w the w
+ * @param h the h
+ * @param scanlineStride the scanline stride
+ */
+ private static void validateDataBuffer(final DataBuffer dataBuffer, final int w,
+ final int h, final int scanlineStride) {
+ if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) {
+ // awt.298=dataBuffer is too small
+ throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$
+ }
+ }
+}
+
+
diff --git a/awt/java/awt/image/RasterFormatException.java b/awt/java/awt/image/RasterFormatException.java
new file mode 100644
index 0000000..8577dad
--- /dev/null
+++ b/awt/java/awt/image/RasterFormatException.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * The RasterFormatException class represents the exception
+ * that is thrown when there's an invalid layout
+ * in the Raster.
+ */
+public class RasterFormatException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 96598996116164315L;
+
+ /**
+ * Instantiates a new RasterFormatException with the
+ * specified detail message.
+ *
+ * @param s the detail message.
+ */
+ public RasterFormatException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/image/RasterOp.java b/awt/java/awt/image/RasterOp.java
new file mode 100644
index 0000000..e8933ee
--- /dev/null
+++ b/awt/java/awt/image/RasterOp.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The RasterOp interface provides methods for performing transformations
+ * from source data to destination data for Raster objects. The source and
+ * destination objects should contain the appropriate number of bands for
+ * the particular classes which implement this interface.
+ */
+public interface RasterOp {
+
+ /**
+ * Creates a destination WritableRaster with the specified Raster;
+ * this destination image data is empty and has the correct size
+ * and number of bands.
+ *
+ * @param src the source Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleDestRaster(Raster src);
+
+ /**
+ * Performs a filter operation on the source Raster and stores the resulting
+ * image data to the destination WritableRaster.
+ *
+ * @param src the source Raster.
+ * @param dst the destination WritableRaster, where the result is stored.
+ *
+ * @return the filtered WritableRaster.
+ */
+ public WritableRaster filter(Raster src, WritableRaster dst);
+
+ /**
+ * Gets the bounds of the filtered Raster.
+ *
+ * @param src the source Raster to be filtered.
+ *
+ * @return the rectangle bounds of the filtered Raster.
+ */
+ public Rectangle2D getBounds2D(Raster src);
+
+ /**
+ * Gets the point of the destination image which corresponds
+ * to the specified point in the source raster.
+ *
+ * @param srcPoint the point of the source raster.
+ * @param dstPoint the point where the result will be stored.
+ *
+ * @return the destination point.
+ */
+ public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint);
+
+ /**
+ * Gets the RenderingHints of the RasterOp.
+ *
+ * @return the RenderingHints of the RasterOp.
+ */
+ public RenderingHints getRenderingHints();
+}
diff --git a/awt/java/awt/image/RenderedImage.java b/awt/java/awt/image/RenderedImage.java
new file mode 100644
index 0000000..db3a4c8
--- /dev/null
+++ b/awt/java/awt/image/RenderedImage.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Rectangle;
+import java.util.Vector;
+
+/**
+ * The RenderedImage interface should be implemented by all objects which
+ * contains image data. The image data is represented as a single tile or
+ * an array of tiles.
+ */
+public interface RenderedImage {
+
+ /**
+ * Gets the property with the specified name from the property set
+ * of this RenderedImage.
+ *
+ * @param name the property's name.
+ *
+ * @return the property value corresponded to this property's name.
+ */
+ public Object getProperty(String name);
+
+ /**
+ * Copies the region of this RenderedImage to the specified
+ * WritableRaster. The bounds of the region are the bounds of the
+ * WritableRaster.
+ *
+ * @param raster the WritableRaster.
+ *
+ * @return the created WritableRaster.
+ */
+ public WritableRaster copyData(WritableRaster raster);
+
+ /**
+ * Gets the image data of the image's region as one tile.
+ *
+ * @param rect the rectangular region of RenderedImage.
+ *
+ * @return the image data of the image's region as one tile.
+ */
+ public Raster getData(Rectangle rect);
+
+ /**
+ * Gets all RenderedImage objects which are the source of this
+ * RenderedImage object.
+ *
+ * @return a Vector of RenderedImage objects which are the source
+ * of this RenderedImage object or null, if there is no information
+ * about them.
+ */
+ public Vector<RenderedImage> getSources();
+
+ /**
+ * Gets the set of all property names for this RenderedImage.
+ *
+ * @return the array of all property names for this RenderedImage.
+ */
+ public String[] getPropertyNames();
+
+ /**
+ * Gets the SampleModel of this RenderedImage.
+ *
+ * @return the SampleModel of this RenderedImage.
+ */
+ public SampleModel getSampleModel();
+
+ /**
+ * Gets the tile corresponded to the specified indices in the tile
+ * array.
+ *
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ *
+ * @return the tile corresponded to the specified indices in the tile
+ * array.
+ */
+ public Raster getTile(int tileX, int tileY);
+
+ /**
+ * Gets the image data of this image as one tile.
+ *
+ * @return the image data of this image as one tile.
+ */
+ public Raster getData();
+
+ /**
+ * Gets the ColorModel of this RenderedImage.
+ *
+ * @return the ColorModel of this RenderedImage.
+ */
+ public ColorModel getColorModel();
+
+ /**
+ * Gets the width of the RenderedImage.
+ *
+ * @return the width of the RenderedImage.
+ */
+ public int getWidth();
+
+ /**
+ * Gets the tile width.
+ *
+ * @return the tile width in pixels.
+ */
+ public int getTileWidth();
+
+ /**
+ * Gets the tile height.
+ *
+ * @return the tile height in pixels.
+ */
+ public int getTileHeight();
+
+ /**
+ * Gets the Y offset of the tile grid.
+ *
+ * @return the Y offset of the tile grid.
+ */
+ public int getTileGridYOffset();
+
+ /**
+ * Gets the X offset of the tile grid.
+ *
+ * @return the X offset of the tile grid.
+ */
+ public int getTileGridXOffset();
+
+ /**
+ * Gets the number of tiles along Y direction.
+ *
+ * @return the number of tiles along Y direction.
+ */
+ public int getNumYTiles();
+
+ /**
+ * Gets the number of tiles along X direction.
+ *
+ * @return the number of tiles along X direction.
+ */
+ public int getNumXTiles();
+
+ /**
+ * Gets the minimum Y coordinate of this RenderedImage.
+ *
+ * @return the minimum Y coordinate of this RenderedImage.
+ */
+ public int getMinY();
+
+ /**
+ * Gets the minimum X coordinate of this RenderedImage.
+ *
+ * @return the minimum X coordinate of this RenderedImage.
+ */
+ public int getMinX();
+
+ /**
+ * Gets the minimum tile's index along the Y direction.
+ *
+ * @return the minimum tile's index along the Y direction.
+ */
+ public int getMinTileY();
+
+ /**
+ * Gets the minimum tile's index along the X direction.
+ *
+ * @return the minimum tile's index along the X direction.
+ */
+ public int getMinTileX();
+
+ /**
+ * Gets the height of the RenderedImage.
+ *
+ * @return the height of the RenderedImage.
+ */
+ public int getHeight();
+
+}
+
diff --git a/awt/java/awt/image/ReplicateScaleFilter.java b/awt/java/awt/image/ReplicateScaleFilter.java
new file mode 100644
index 0000000..9298125
--- /dev/null
+++ b/awt/java/awt/image/ReplicateScaleFilter.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * The ReplicateScaleFilter class scales an source image
+ * by replicating rows and columns of pixels to scale up or
+ * omitting rows and columns of pixels to scale down.
+ */
+public class ReplicateScaleFilter extends ImageFilter {
+
+ /** The width of a source image. */
+ protected int srcWidth;
+
+ /** The height of a source image. */
+ protected int srcHeight;
+
+ /** The width of a destination image. */
+ protected int destWidth;
+
+ /** The height of a destination image. */
+ protected int destHeight;
+
+ /** The int array of source rows. */
+ protected int[] srcrows;
+
+ /** The int array of source columns. */
+ protected int[] srccols;
+
+ /**
+ * An Object (byte array with a destination width) provides
+ * a row of pixel data to the ImageConsumer.
+ */
+ protected Object outpixbuf;
+
+ /**
+ * Instantiates a new ReplicateScaleFilter that filters
+ * the image with the specified width and height.
+ *
+ * @param width the width of scaled image.
+ * @param height the height of scaled image.
+ */
+ public ReplicateScaleFilter(int width, int height) {
+ if(width == 0 || height == 0) {
+ // awt.234=Width or Height equals zero
+ throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$
+ }
+
+ this.destWidth = width;
+ this.destHeight = height;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setProperties(Hashtable<?, ?> props) {
+ Hashtable<Object, Object> fprops;
+ if(props == null) {
+ fprops = new Hashtable<Object, Object>();
+ } else {
+ fprops = (Hashtable<Object, Object>) props.clone();
+ }
+ String propName = "Rescale Filters"; //$NON-NLS-1$
+ String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$
+ "destHeight=" + destHeight; //$NON-NLS-1$
+ Object o = fprops.get(propName);
+ if(o != null){
+ if(o instanceof String){
+ prop = (String)o + "; " + prop; //$NON-NLS-1$
+ }else{
+ prop = o.toString() + "; " + prop; //$NON-NLS-1$
+ }
+ }
+ fprops.put(propName, prop);
+ consumer.setProperties(fprops);
+ }
+
+ // setPixels methods produce pixels according to Java API Spacification
+
+ @Override
+ public void setPixels(int x, int y, int w, int h,
+ ColorModel model, int[] pixels, int off, int scansize) {
+
+ if(srccols == null) {
+ initArrays();
+ }
+ int buff[];
+ if(outpixbuf == null || !(outpixbuf instanceof int[])){
+ buff = new int[destWidth];
+ outpixbuf = buff;
+ }else{
+ buff = (int[])outpixbuf;
+ }
+
+ int wa = (srcWidth - 1) >>> 1;
+ int ha = (srcHeight - 1) >>> 1;
+ int dstX = (x * destWidth + wa) / srcWidth;
+ int dstY = (y * destHeight + ha) / srcHeight;
+
+ int sx, sy, dx, dy;
+ dy = dstY;
+ while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){
+ dx = dstX;
+ int srcOff = off + (sy - y) * scansize;
+ while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){
+ buff[dx] = pixels[srcOff + (sx - x)];
+ dx++;
+ }
+
+ consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff,
+ dstX, destWidth);
+ dy++;
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h,
+ ColorModel model, byte[] pixels, int off, int scansize) {
+
+ if(srccols == null) {
+ initArrays();
+ }
+ byte buff[];
+ if(outpixbuf == null || !(outpixbuf instanceof byte[])){
+ buff = new byte[destWidth];
+ outpixbuf = buff;
+ }else{
+ buff = (byte[])outpixbuf;
+ }
+
+ int wa = (srcWidth - 1) >>> 1;
+ int ha = (srcHeight - 1) >>> 1;
+ int dstX = (x * destWidth + wa) / srcWidth;
+ int dstY = (y * destHeight + ha) / srcHeight;
+
+ int sx, sy, dx, dy;
+ dy = dstY;
+ while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){
+ dx = dstX;
+ int srcOff = off + (sy - y) * scansize;
+ while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){
+ buff[dx] = pixels[srcOff + (sx - x)];
+ dx++;
+ }
+
+ consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff,
+ dstX, destWidth);
+ dy++;
+ }
+ }
+
+ @Override
+ public void setDimensions(int w, int h) {
+ srcWidth = w;
+ srcHeight = h;
+
+ if(destWidth < 0 && destHeight < 0){
+ destWidth = srcWidth;
+ destHeight = srcHeight;
+ }else if(destWidth < 0){
+ destWidth = destHeight * srcWidth / srcHeight;
+ }else if(destHeight < 0){
+ destHeight = destWidth * srcHeight / srcWidth;
+ }
+ consumer.setDimensions(destWidth, destHeight);
+ }
+
+ /**
+ * Initialization of srccols and srcrows arrays.
+ */
+ private void initArrays(){
+ if ((destWidth < 0) || (destHeight < 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ srccols = new int[destWidth];
+ int ca = srcWidth >>> 1;
+ for(int i = 0; i < destWidth; i++){
+ srccols[i] = (i * srcWidth + ca) / destWidth;
+ }
+
+ srcrows = new int[destHeight];
+ int ra = srcHeight >>> 1;
+ for(int i = 0; i < destHeight; i++){
+ srcrows[i] = (i * srcHeight + ra) / destHeight;
+ }
+ }
+
+}
+
+
diff --git a/awt/java/awt/image/RescaleOp.java b/awt/java/awt/image/RescaleOp.java
new file mode 100644
index 0000000..0e96031
--- /dev/null
+++ b/awt/java/awt/image/RescaleOp.java
@@ -0,0 +1,659 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 6, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.*;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RescaleOp performs rescaling of the source image data
+ * by multiplying the pixel values with a scale factor
+ * and then adding an offset.
+ */
+public class RescaleOp implements BufferedImageOp, RasterOp {
+
+ /** The scale factors. */
+ private float scaleFactors[];
+
+ /** The offsets. */
+ private float offsets[];
+
+ /** The hints. */
+ private RenderingHints hints;
+
+ static {
+ // TODO
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new RescaleOp object with the specified
+ * scale factors and offsets.
+ *
+ * @param scaleFactors the array of scale factor values.
+ * @param offsets the array of offset values.
+ * @param hints the RenderingHints or null.
+ */
+ public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) {
+ int numFactors = Math.min(scaleFactors.length, offsets.length);
+
+ this.scaleFactors = new float[numFactors];
+ this.offsets = new float[numFactors];
+
+ System.arraycopy(scaleFactors, 0, this.scaleFactors, 0, numFactors);
+ System.arraycopy(offsets, 0, this.offsets, 0, numFactors);
+
+ this.hints = hints;
+ }
+
+ /**
+ * Instantiates a new RescaleOp object with the specified
+ * scale factor and offset.
+ *
+ * @param scaleFactor the scale factor.
+ * @param offset the offset.
+ * @param hints the RenderingHints or null.
+ */
+ public RescaleOp(float scaleFactor, float offset, RenderingHints hints) {
+ scaleFactors = new float[1];
+ offsets = new float[1];
+
+ scaleFactors[0] = scaleFactor;
+ offsets[0] = offset;
+
+ this.hints = hints;
+ }
+
+ /**
+ * Gets the number of scaling factors.
+ *
+ * @return the number of scaling factors.
+ */
+ public final int getNumFactors() {
+ return scaleFactors.length;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ /**
+ * Gets the scale factors of this RescaleOp.
+ *
+ * @param scaleFactors the desired scale factors array will be copied
+ * to this array.
+ *
+ * @return the scale factors array.
+ */
+ public final float[] getScaleFactors(float[] scaleFactors) {
+ if (scaleFactors == null) {
+ scaleFactors = new float[this.scaleFactors.length];
+ }
+
+ int minLength = Math.min(scaleFactors.length, this.scaleFactors.length);
+ System.arraycopy(this.scaleFactors, 0, scaleFactors, 0, minLength);
+ return scaleFactors;
+ }
+
+ /**
+ * Gets the offsets array of this RescaleOp.
+ *
+ * @param offsets the desired offsets array will be copied to this array.
+ *
+ * @return the offsets array of this RescaleOp.
+ */
+ public final float[] getOffsets(float[] offsets) {
+ if (offsets == null) {
+ offsets = new float[this.offsets.length];
+ }
+
+ int minLength = Math.min(offsets.length, this.offsets.length);
+ System.arraycopy(this.offsets, 0, offsets, 0, minLength);
+ return offsets;
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ return src.createCompatibleWritableRaster();
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+ if (dstCM == null) {
+ dstCM = src.getColorModel();
+ }
+
+ if (dstCM instanceof IndexColorModel) {
+ dstCM = ColorModel.getRGBdefault();
+ }
+
+ WritableRaster r =
+ dstCM.isCompatibleSampleModel(src.getSampleModel()) ?
+ src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) :
+ dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+ return new BufferedImage(
+ dstCM,
+ r,
+ dstCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else {
+ if (src.getNumBands() != dst.getNumBands()) {
+ // awt.21D=Number of src bands ({0}) does not match number of dst bands ({1})
+ throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$
+ src.getNumBands(), dst.getNumBands()));
+ }
+ }
+
+ if (
+ this.scaleFactors.length != 1 &&
+ this.scaleFactors.length != src.getNumBands()
+ ) {
+ // awt.21E=Number of scaling constants is not equal to the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+ }
+
+ // TODO
+ //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0)
+ if (slowFilter(src, dst, false) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) {
+ SampleModel sm = src.getSampleModel();
+
+ int numBands = src.getNumBands();
+ int srcHeight = src.getHeight();
+ int srcWidth = src.getWidth();
+
+ int srcMinX = src.getMinX();
+ int srcMinY = src.getMinY();
+ int dstMinX = dst.getMinX();
+ int dstMinY = dst.getMinY();
+
+ int[] maxValues = new int[numBands];
+ int[] masks = new int[numBands];
+ int[] sampleSizes = sm.getSampleSize();
+
+ for (int i=0; i < numBands; i++){
+ maxValues[i] = (1 << sampleSizes[i]) - 1;
+ masks[i] = ~(maxValues[i]);
+ }
+
+ // Processing bounds
+ float[] pixels = null;
+ pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels);
+
+ // Cycle over pixels to be calculated
+ if (skipAlpha) { // Always suppose that alpha channel is the last band
+ if (scaleFactors.length > 1) {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+
+ i++;
+ }
+ } else {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[0] + offsets[0];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+
+ i++;
+ }
+ }
+ } else {
+ if (scaleFactors.length > 1) {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[0] + offsets[0];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, pixels);
+
+ return 0;
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ ColorModel srcCM = src.getColorModel();
+
+ if (srcCM instanceof IndexColorModel) {
+ // awt.220=Source should not have IndexColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$
+ }
+
+ // Check if the number of scaling factors matches the number of bands
+ int nComponents = srcCM.getNumComponents();
+ boolean skipAlpha;
+ if (srcCM.hasAlpha()) {
+ if (scaleFactors.length == 1 || scaleFactors.length == nComponents-1) {
+ skipAlpha = true;
+ } else if (scaleFactors.length == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.21E=Number of scaling constants is not equal to the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+ }
+ } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.21E=Number of scaling constants is not equal to the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+ }
+
+ BufferedImage finalDst = null;
+ if (dst == null) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ } else if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same
+ if (
+ !((src.getType() == BufferedImage.TYPE_INT_RGB ||
+ src.getType() == BufferedImage.TYPE_INT_ARGB) &&
+ (dst.getType() == BufferedImage.TYPE_INT_RGB ||
+ dst.getType() == BufferedImage.TYPE_INT_ARGB))
+ ) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ }
+ }
+
+ // TODO
+ //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0)
+ if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return finalDst;
+ }
+
+ // Don't forget to pass allocated arrays for levels and values, size should be numBands*4
+ /**
+ * Creates the levels.
+ *
+ * @param sm the sm
+ * @param numBands the num bands
+ * @param skipAlpha the skip alpha
+ * @param levels the levels
+ * @param values the values
+ * @param channelsOrder the channels order
+ */
+ private final void createLevels(
+ SampleModel sm, int numBands, boolean skipAlpha,
+ int levels[], int values[], int channelsOrder[]
+ ) {
+ // Suppose same sample size for all channels, otherwise use slow filter
+ int maxValue = (1 << sm.getSampleSize(0)) - 1;
+
+ // For simplicity introduce these arrays
+ float extScaleFactors[] = new float[numBands];
+ float extOffsets[] = new float[numBands];
+
+ if (scaleFactors.length != 1) {
+ System.arraycopy(scaleFactors, 0, extScaleFactors, 0, scaleFactors.length);
+ System.arraycopy(offsets, 0, extOffsets, 0, scaleFactors.length);
+ } else {
+ for (int i = 0; i < numBands; i++) {
+ extScaleFactors[i] = scaleFactors[0];
+ extOffsets[i] = offsets[0];
+ }
+ }
+
+ if (skipAlpha) {
+ extScaleFactors[numBands-1] = 1;
+ extOffsets[numBands-1] = 0;
+ }
+
+ // Create a levels
+ for (int i=0; i<numBands; i++) {
+ if (extScaleFactors[i] == 0) {
+ levels[i*4] = 0;
+ levels[i*4+1] = 0;
+ levels[i*4+2] = maxValue+1;
+ levels[i*4+3] = maxValue+1;
+ }
+
+ float minLevel = -extOffsets[i] / extScaleFactors[i];
+ float maxLevel = (maxValue - extOffsets[i]) / extScaleFactors[i];
+
+ if (minLevel < 0) {
+ minLevel = 0;
+ } else if (minLevel > maxValue){
+ minLevel = maxValue;
+ }
+
+ if (maxLevel < 0) {
+ maxLevel = 0;
+ } else if (maxLevel > maxValue){
+ maxLevel = maxValue;
+ }
+
+ levels[i*4] = 0;
+ if (minLevel > maxLevel) {
+ levels[i*4+1] = (int) maxLevel;
+ levels[i*4+2] = (int) minLevel;
+ } else {
+ levels[i*4+1] = (int) minLevel;
+ levels[i*4+2] = (int) maxLevel;
+ }
+ levels[i*4+3] = maxValue+1;
+
+ // Fill values
+ for (int k=0; k<4; k++) {
+ int idx = i*4+k;
+ values[idx] = (int) (extScaleFactors[i] * levels[idx] + extOffsets[i]);
+ if (values[idx] < 0) {
+ values[idx] = 0;
+ } else if (values[idx] > maxValue){
+ values[idx] = maxValue;
+ }
+ }
+ }
+
+ // Reorder data if channels are stored in different order
+ if (channelsOrder != null) {
+ int len = numBands*4;
+ int savedLevels[] = new int[len];
+ int savedValues[] = new int[len];
+ System.arraycopy(levels, 0, savedLevels, 0, len);
+ System.arraycopy(values, 0, savedValues, 0, len);
+ for (int i = 0; i < channelsOrder.length; i++) {
+ System.arraycopy(savedLevels, i*4, levels, channelsOrder[i]*4, 4);
+ System.arraycopy(savedValues, i*4, values, channelsOrder[i]*4, 4);
+ }
+ }
+ }
+
+ // TODO remove when this method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private final int ippFilter(
+ Raster src, WritableRaster dst,
+ int imageType, boolean skipAlpha
+ ) {
+ int res;
+
+ int srcStride, dstStride;
+ int channels;
+ int offsets[] = null;
+ int channelsOrder[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_INT_RGB: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ channelsOrder = new int[] {2, 1, 0, 3};
+ break;
+ }
+
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ channelsOrder = new int[] {2, 1, 0};
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY:
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels
+ if (!(channels == 1 || channels == 3 || channels == 4)) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride();
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride();
+
+ channelsOrder = ((ComponentSampleModel) srcSM).getBandOffsets();
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ channels = sppsm1.getNumBands();
+
+ // TYPE_INT_RGB, TYPE_INT_ARGB...
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT ||
+ !(channels == 3 || channels == 4)
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Check compatibility of sample models
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+ }
+
+ channelsOrder = new int[channels];
+ int bitOffsets[] = sppsm1.getBitOffsets();
+ for (int i=0; i<channels; i++) {
+ channelsOrder[i] = bitOffsets[i] / 8;
+ }
+
+ if (channels == 3) { // Don't skip channel now, could be optimized
+ channels = 4;
+ }
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ int levels[] = new int[4*channels];
+ int values[] = new int[4*channels];
+
+ createLevels(src.getSampleModel(), channels, skipAlpha, levels, values, channelsOrder);
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ res = LookupOp.ippLUT(
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ levels, values,
+ channels, offsets,
+ true
+ );
+
+ return res;
+ }
+}
diff --git a/awt/java/awt/image/SampleModel.java b/awt/java/awt/image/SampleModel.java
new file mode 100644
index 0000000..44059a0
--- /dev/null
+++ b/awt/java/awt/image/SampleModel.java
@@ -0,0 +1,1053 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The SampleModel class is abstract class for retrieving pixel's samples
+ * in the data of an image. Each pixel contains several samples. A
+ * sample is the set of values of the bands for single pixel.
+ * For example, each pixel in the RGB model contains three samples
+ * and there are three corresponding bands in the image
+ * data of such pixels representing red, green and blue components.
+ * <p>
+ * The image data is represented as a Raster with a DataBuffer
+ * and a SampleModel. The SampleModel allows access to the samples in the
+ * DataBuffer.
+ */
+public abstract class SampleModel {
+
+ /** The width of the image data which this SampleModel describes. */
+ protected int width;
+
+ /** The height of the image data which this SampleModel describes. */
+ protected int height;
+
+ /** The number of bands of image data which this SampleModel describes. */
+ protected int numBands;
+
+ /** The data type of the image data which this SampleModel describes. */
+ protected int dataType;
+
+ /**
+ * Instantiates a new SampleModel with the specified data type,
+ * width, height and number of bands.
+ *
+ * @param dataType the data type of the image data.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param numBands the number of bands of the image data.
+ */
+ public SampleModel(int dataType, int w, int h, int numBands) {
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ double squre = ((double) w) * ((double) h);
+ if (squre >= Integer.MAX_VALUE) {
+ // awt.22F=The product of w and h is greater than Integer.MAX_VALUE
+ throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$
+ }
+
+ if (dataType < DataBuffer.TYPE_BYTE ||
+ dataType > DataBuffer.TYPE_DOUBLE &&
+ dataType != DataBuffer.TYPE_UNDEFINED) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (numBands < 1) {
+ // awt.231=Number of bands must be more then 0
+ throw new IllegalArgumentException(Messages.getString("awt.231")); //$NON-NLS-1$
+ }
+
+ this.dataType = dataType;
+ this.width = w;
+ this.height = h;
+ this.numBands = numBands;
+
+ }
+
+ /**
+ * Gets the data array for the specified pixel of the specified
+ * DataBuffer with one of the following types:
+ * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param obj the Object is a data where the result will be stored.
+ * @param data the image data.
+ *
+ * @return the data array for the specified pixel of the specified
+ * DataBuffer.
+ */
+ public abstract Object getDataElements(int x, int y, Object obj,
+ DataBuffer data);
+
+ /**
+ * Gets the array of pixel data for the specified rectangular
+ * area of pixels of the specified DataBuffer with one of
+ * the following types:
+ * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ *
+ * @param x the X coordinate of the rectangular pixel area.
+ * @param y the Y coordinate of the rectangular pixel area.
+ * @param w the width of the rectangular pixel area.
+ * @param h the height of the rectangular pixel area.
+ * @param obj the Object is an array with the primitive type,
+ * where the result array will be stored.
+ * @param data the image data.
+ *
+ * @return the array of pixel data for the specified rectangular
+ * area of pixels of the specified DataBuffer object.
+ */
+ public Object getDataElements(int x, int y, int w, int h, Object obj,
+ DataBuffer data) {
+ int numDataElements = getNumDataElements();
+ int idx = 0;
+
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ byte bbuf[] = null;
+
+ if (obj == null) {
+ bdata = new byte[numDataElements * w * h];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ bbuf = (byte[]) getDataElements(j, i, bbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ bdata[idx++] = bbuf[n];
+ }
+ }
+ }
+ obj = bdata;
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ short sbuf[] = null;
+
+ if (obj == null) {
+ sdata = new short[numDataElements * w * h];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ sbuf = (short[]) getDataElements(j, i, sbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ sdata[idx++] = sbuf[n];
+ }
+ }
+ }
+ obj = sdata;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ int ibuf[] = null;
+
+ if (obj == null) {
+ idata = new int[numDataElements * w * h];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ ibuf = (int[]) getDataElements(j, i, ibuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ idata[idx++] = ibuf[n];
+ }
+ }
+ }
+ obj = idata;
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fdata[];
+ float fbuf[] = null;
+
+ if (obj == null) {
+ fdata = new float[numDataElements * w * h];
+ } else {
+ fdata = (float[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ fbuf = (float[]) getDataElements(j, i, fbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ fdata[idx++] = fbuf[n];
+ }
+ }
+ }
+ obj = fdata;
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double ddata[];
+ double dbuf[] = null;
+
+ if (obj == null) {
+ ddata = new double[numDataElements * w * h];
+ } else {
+ ddata = (double[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ dbuf = (double[]) getDataElements(j, i, dbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ ddata[idx++] = dbuf[n];
+ }
+ }
+ }
+ obj = ddata;
+ break;
+
+ }
+
+ return obj;
+ }
+
+ /**
+ * Sets the data for a single pixel in the specified DataBuffer
+ * from a primitive array with one of the following types:
+ * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param obj the Object - the array of primitive pixel data
+ * to be set.
+ * @param data the image data.
+ */
+ public abstract void setDataElements(int x, int y, Object obj,
+ DataBuffer data);
+
+ /**
+ * Sets the data elements for a rectangular area of pixels in
+ * the specified DataBuffer from a primitive array with one of
+ * the following types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the specified rectangular area.
+ * @param y the Y coordinate of the specified rectangular area.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ * @param obj the Object - the array of primitive pixel data
+ * to be set.
+ * @param data the image data.
+ */
+ public void setDataElements(int x, int y, int w, int h, Object obj,
+ DataBuffer data) {
+ int numDataElements = getNumDataElements();
+ int idx = 0;
+
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bbuf[] = new byte[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ bbuf[n] = ((byte[]) obj)[idx++];
+ }
+ setDataElements(j, i, bbuf, data);
+ }
+ }
+
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sbuf[] = new short[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ sbuf[n] = ((short[]) obj)[idx++];
+ }
+ setDataElements(j, i, sbuf, data);
+ }
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ibuf[] = new int[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ ibuf[n] = ((int[]) obj)[idx++];
+ }
+ setDataElements(j, i, ibuf, data);
+ }
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fbuf[] = new float[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ fbuf[n] = ((float[]) obj)[idx++];
+ }
+ setDataElements(j, i, fbuf, data);
+ }
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dbuf[] = new double[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ dbuf[n] = ((double[]) obj)[idx++];
+ }
+ setDataElements(j, i, dbuf, data);
+ }
+ }
+ break;
+
+ }
+ }
+
+ /**
+ * Creates a new SampleModel with the specified bands of
+ * this SampleModel.
+ *
+ * @param bands the array of bands from this SampleModel.
+ *
+ * @return the SampleModel with the specified bands of
+ * this SampleModel.
+ */
+ public abstract SampleModel createSubsetSampleModel(int bands[]);
+
+ /**
+ * Creates the SampleModel which has the same data as in
+ * this SampleModel with a different width and height.
+ *
+ * @param a0 the width of the image data.
+ * @param a1 the height of the image data.
+ *
+ * @return the SampleModel which has the same data as in
+ * this SampleModel with a different width and height.
+ */
+ public abstract SampleModel createCompatibleSampleModel(int a0, int a1);
+
+ /**
+ * Gets the samples of the specified pixel as a int array.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param iArray the int array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the int array with the samples of the specified pixel.
+
+ */
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixel[];
+
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Sets a pixel of the DataBuffer from a int array of samples.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param iArray the int array.
+ * @param data the image data.
+ */
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ /**
+ * Gets the samples of the specified pixel as a float array.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param fArray the float array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the float array with the samples of the specified pixel.
+ */
+ public float[] getPixel(int x, int y, float fArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ float pixel[];
+
+ if (fArray == null) {
+ pixel = new float[numBands];
+ } else {
+ pixel = fArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSampleFloat(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Sets a pixel of the DataBuffer from a float array of samples.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param fArray the float array.
+ * @param data the image data.
+ */
+ public void setPixel(int x, int y, float fArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, fArray[i], data);
+ }
+ }
+
+ /**
+ * Gets the samples of the specified pixel as a double array.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param dArray the double array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the double array with the samples of the specified pixel.
+ */
+ public double[] getPixel(int x, int y, double dArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ double pixel[];
+
+ if (dArray == null) {
+ pixel = new double[numBands];
+ } else {
+ pixel = dArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSampleDouble(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Sets a pixel of the DataBuffer from a double array of samples.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param dArray the double array.
+ * @param data the image data.
+ */
+ public void setPixel(int x, int y, double dArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, dArray[i], data);
+ }
+ }
+
+ /**
+ * Gets the sample of a specified band for the specified pixel
+ * as an int.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param b the specified band.
+ * @param data the image data.
+ *
+ * @return the sample of a specified band for the specified pixel.
+ */
+ public abstract int getSample(int x, int y, int b, DataBuffer data);
+
+ /**
+ * Gets the sample of a specified band for the specified pixel
+ * as a float.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param b the specified band.
+ * @param data the image data.
+ *
+ * @return the sample of a specified band for the specified pixel.
+
+ */
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ return getSample(x, y, b, data);
+ }
+
+ /**
+ * Gets the sample of a specified band for the specified pixel
+ * as a double.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param b the specified band.
+ * @param data the image data.
+ *
+ * @return the sample of a specified band for the specified pixel.
+ */
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ return getSample(x, y, b, data);
+ }
+
+ /**
+ * Gets the samples of the specified rectangular area of pixels
+ * as a int array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param iArray the int array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the int array with the samples of the specified
+ * rectangular area of pixels.
+ */
+ public int[] getPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixels[];
+ int idx = 0;
+
+ if (iArray == null) {
+ pixels = new int[w * h * numBands];
+ } else {
+ pixels = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSample(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Sets all of the samples for a rectangular area of pixels of the DataBuffer
+ * from an int array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param iArray the int array.
+ * @param data the image data.
+ */
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of the specified rectangular area of pixels
+ * as a float array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param fArray the float array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the float array with the samples of the specified
+ * rectangular area of pixels.
+ */
+ public float[] getPixels(int x, int y, int w, int h, float fArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ float pixels[];
+ int idx = 0;
+
+ if (fArray == null) {
+ pixels = new float[w * h * numBands];
+ } else {
+ pixels = fArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSampleFloat(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Sets all of the samples for a rectangular area of pixels of the DataBuffer
+ * from a float array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param fArray the float array.
+ * @param data the image data.
+ */
+ public void setPixels(int x, int y, int w, int h, float fArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, fArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of the specified rectangular area of pixels
+ * as a double array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param dArray the double array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the double array with the samples of the specified
+ * rectangular area of pixels.
+ */
+ public double[] getPixels(int x, int y, int w, int h, double dArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ double pixels[];
+ int idx = 0;
+
+ if (dArray == null) {
+ pixels = new double[w * h * numBands];
+ } else {
+ pixels = dArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSampleDouble(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Sets all of the samples for a rectangular area of pixels of the DataBuffer
+ * from a double array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param dArray the double array.
+ * @param data the image data.
+ */
+ public void setPixels(int x, int y, int w, int h, double dArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, dArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets a sample of the specified band for the specified pixel
+ * in the DataBuffer as int value.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample as an int value.
+ * @param data the image data.
+ */
+ public abstract void setSample(int x, int y, int b, int s, DataBuffer data);
+
+ /**
+ * Gets the samples of a specified band for a specified rectangular
+ * area of pixels as a int array.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param iArray the int array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the samples of a specified band for a specified rectangular
+ * area of pixels.
+ */
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ /**
+ * Sets the samples from an int array in the specified band for
+ * the specified rectangle of pixels.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param iArray the int array.
+ * @param data the image data.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, iArray[idx++], data);
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of a specified band for a specified rectangular
+ * area of pixels as a float array.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param fArray the float array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the samples of a specified band for a specified rectangular
+ * area of pixels.
+ */
+ public float[] getSamples(int x, int y, int w, int h, int b,
+ float fArray[], DataBuffer data) {
+ float samples[];
+ int idx = 0;
+
+ if (fArray == null) {
+ samples = new float[w * h];
+ } else {
+ samples = fArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSampleFloat(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ /**
+ * Sets the samples from an float array in the specified band for
+ * the specified rectangle of pixels.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param fArray the float array
+ * @param data the image data.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, float fArray[],
+ DataBuffer data) {
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, fArray[idx++], data);
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of a specified band for a specified rectangular
+ * area of pixels as a double array.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param dArray the double array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the samples of a specified band for a specified rectangular
+ * area of pixels.
+ */
+ public double[] getSamples(int x, int y, int w, int h, int b,
+ double dArray[], DataBuffer data) {
+ double samples[];
+ int idx = 0;
+
+ if (dArray == null) {
+ samples = new double[w * h];
+ } else {
+ samples = dArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSampleDouble(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ /**
+ * Sets the samples from an double array in the specified band for
+ * the specified rectangle of pixels.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param dArray the double array
+ * @param data the image data.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, double dArray[],
+ DataBuffer data) {
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, dArray[idx++], data);
+ }
+ }
+ }
+
+ /**
+ * Sets a sample of the specified band for the specified pixel
+ * in the DataBuffer as float value.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample as float value.
+ * @param data the image data.
+ */
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ setSample(x, y, b, (int) s, data);
+ }
+
+ /**
+ * Sets a sample of the specified band for the specified pixel
+ * in the DataBuffer as double value.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample as double value.
+ * @param data the image data.
+ */
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ setSample(x, y, b, (int) s, data);
+ }
+
+ /**
+ * Creates a DataBuffer object which corresponds to the SampleModel.
+ *
+ * @return the DataBuffer object which corresponds to
+ * the SampleModel.
+ */
+ public abstract DataBuffer createDataBuffer();
+
+ /**
+ * Gets the sample size in bits for the specified band.
+ *
+ * @param band the specified band.
+ *
+ * @return the sample size in bits for the specified band.
+ */
+ public abstract int getSampleSize(int band);
+
+ /**
+ * Gets an array of the sample size in bits for all bands.
+ *
+ * @return an array of the sample size in bits for all bands.
+ */
+ public abstract int[] getSampleSize();
+
+ /**
+ * Gets the width of the image data of this SampleModel object.
+ *
+ * @return the width of the image data of this SampleModel object.
+ */
+ public final int getWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the transfer type used to transfer pixels via
+ * the getDataElements and setDataElements methods.
+ * Transfer type value can be one of the predefined type
+ * from DataBuffer class or not.
+ *
+ * @return the transfer type.
+ */
+ public int getTransferType() {
+ return dataType;
+ }
+
+ /**
+ * Returns the number of data elements for pixel transfering
+ * via the getDataElements and setDataElements methods.
+ *
+ * @return the number of data elements for pixel transfering
+ * via the getDataElements and setDataElements methods.
+ */
+ public abstract int getNumDataElements();
+
+ /**
+ * Gets the number of bands in the image data of this
+ * SampleModel object.
+ *
+ * @return the number of bands in the image data of this
+ * SampleModel object.
+ */
+ public final int getNumBands() {
+ return numBands;
+ }
+
+ /**
+ * Gets the height of the image data of this SampleModel object.
+ *
+ * @return the height of the image data of this SampleModel object.
+ */
+ public final int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the data type of image data of this SampleModel object.
+ *
+ * @return the data type of image data of this SampleModel object.
+ */
+ public final int getDataType() {
+ return dataType;
+ }
+
+}
+
diff --git a/awt/java/awt/image/ShortLookupTable.java b/awt/java/awt/image/ShortLookupTable.java
new file mode 100644
index 0000000..77c9c45
--- /dev/null
+++ b/awt/java/awt/image/ShortLookupTable.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+
+/**
+ * The ShortLookupTable class provides provides functionality for
+ * lookup operations, and is defined by an input short array for
+ * bands or components of image and an offset value.
+ * The offset value will be subtracted from the input values before
+ * indexing the input arrays. The output of a lookup operation is
+ * represented as an unsigned short array.
+ */
+public class ShortLookupTable extends LookupTable {
+
+ /** The data. */
+ private short data[][];
+
+ /**
+ * Instantiates a new ShortLookupTable with the specified offset value
+ * and the specified short array which represents lookup table for
+ * all bands.
+ *
+ * @param offset the offset value.
+ * @param data the data array.
+ */
+ public ShortLookupTable(int offset, short[] data) {
+ super(offset, 1);
+ this.data = new short[1][data.length];
+ // The data array stored as a reference
+ this.data[0] = data;
+ }
+
+ /**
+ * Instantiates a new ShortLookupTable with the specified offset value
+ * and the specified short array of arrays which represents lookup table
+ * for each band.
+ *
+ * @param offset the offset value.
+ * @param data the data array of arrays for each band.
+ */
+ public ShortLookupTable(int offset, short[][] data) {
+ super(offset, data.length);
+ this.data = new short[data.length][data[0].length];
+ for (int i = 0; i < data.length; i++) {
+ // The data array for each band stored as a reference
+ this.data[i] = data[i];
+ }
+ }
+
+ /**
+ * Gets the lookup table of this ShortLookupTable object. If
+ * this ShortLookupTable object has one short array for all bands,
+ * the returned array length is one.
+ *
+ * @return the lookup table of this ShortLookupTable object.
+ */
+ public final short[][] getTable() {
+ return data;
+ }
+
+ /**
+ * Returns a short array which contains samples of the specified
+ * pixel which is translated with the lookup table of this
+ * ShortLookupTable object. The resulted array is stored to
+ * the dst array.
+ *
+ * @param src the source array.
+ * @param dst the destination array where the result can be stored.
+ *
+ * @return the short array of translated samples of a pixel.
+ */
+ public short[] lookupPixel(short[] src, short[] dst) {
+ if (dst == null) {
+ dst = new short[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+
+ @Override
+ public int[] lookupPixel(int[] src, int[] dst) {
+ if (dst == null) {
+ dst = new int[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+}
diff --git a/awt/java/awt/image/SinglePixelPackedSampleModel.java b/awt/java/awt/image/SinglePixelPackedSampleModel.java
new file mode 100644
index 0000000..311395a
--- /dev/null
+++ b/awt/java/awt/image/SinglePixelPackedSampleModel.java
@@ -0,0 +1,508 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The SinglePixelPackedSampleModel class represents pixel data
+ * where several samples combine to create a single pixel and
+ * are stored in a single data array element. This class
+ * supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data types.
+ */
+public class SinglePixelPackedSampleModel extends SampleModel {
+
+ /** The bit masks. */
+ private int bitMasks[];
+
+ /** The bit offsets. */
+ private int bitOffsets[];
+
+ /** The bit sizes. */
+ private int bitSizes[];
+
+ /** The scanline stride. */
+ private int scanlineStride;
+
+ /** The max bit size. */
+ private int maxBitSize;
+
+ /**
+ * Instantiates a new SinglePixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bitMasks the bit masks for all the bands.
+ */
+ public SinglePixelPackedSampleModel(int dataType, int w, int h,
+ int bitMasks[]) {
+ this(dataType, w, h, w, bitMasks);
+ }
+
+ /**
+ * Instantiates a new SinglePixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param scanlineStride The scanline stride of the image data.
+ * @param bitMasks the bit masks for all the bands.
+ */
+ public SinglePixelPackedSampleModel(int dataType, int w, int h,
+ int scanlineStride, int bitMasks[]) {
+
+ super(dataType, w, h, bitMasks.length);
+
+ if (dataType != DataBuffer.TYPE_BYTE &&
+ dataType != DataBuffer.TYPE_USHORT &&
+ dataType != DataBuffer.TYPE_INT) {
+ // awt.61=Unsupported data type: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
+ dataType));
+ }
+
+ this.scanlineStride = scanlineStride;
+ this.bitMasks = bitMasks.clone();
+ this.bitOffsets = new int[this.numBands];
+ this.bitSizes = new int[this.numBands];
+
+ this.maxBitSize = 0;
+
+ for (int i = 0; i < this.numBands; i++) {
+ int offset = 0;
+ int size = 0;
+ int mask = bitMasks[i];
+
+ if (mask != 0) {
+ while ((mask & 1) == 0) {
+ mask >>>= 1;
+ offset++;
+ }
+
+ while ((mask & 1) == 1) {
+ mask >>>= 1;
+ size++;
+ }
+
+ if (mask != 0) {
+ // awt.62=Wrong mask : {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "awt.62", bitMasks[i])); //$NON-NLS-1$
+ }
+ }
+
+ this.bitOffsets[i] = offset;
+ this.bitSizes[i] = size;
+
+ if (this.maxBitSize < size) {
+ this.maxBitSize = size;
+ }
+
+ }
+
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ if (obj == null) {
+ bdata = new byte[1];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ bdata[0] = (byte) data.getElem(y * scanlineStride + x);
+ obj = bdata;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ if (obj == null) {
+ sdata = new short[1];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ sdata[0] = (short) data.getElem(y * scanlineStride + x);
+ obj = sdata;
+ break;
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ if (obj == null) {
+ idata = new int[1];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ idata[0] = data.getElem(y * scanlineStride + x);
+ obj = idata;
+ break;
+ }
+ return obj;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ data.setElem(y * scanlineStride + x, ((byte[]) obj)[0] & 0xff);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data.setElem(y * scanlineStride + x, ((short[]) obj)[0] & 0xffff);
+ break;
+ case DataBuffer.TYPE_INT:
+ data.setElem(y * scanlineStride + x, ((int[]) obj)[0]);
+ break;
+ }
+ }
+
+ /**
+ * Compares this SinglePixelPackedSampleModel object with
+ * the specified object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if this SinglePixelPackedSampleModel object is
+ * equal to the specified object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
+ return false;
+ }
+
+ SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel) o;
+ return this.width == model.width &&
+ this.height == model.height &&
+ this.numBands == model.numBands &&
+ this.dataType == model.dataType &&
+ Arrays.equals(this.bitMasks, model.bitMasks) &&
+ Arrays.equals(this.bitOffsets, model.bitOffsets) &&
+ Arrays.equals(this.bitSizes, model.bitSizes) &&
+ this.scanlineStride == model.scanlineStride;
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands.length > this.numBands) {
+ // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+ throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+ }
+
+ int masks[] = new int[bands.length];
+ for (int i = 0; i < bands.length; i++) {
+ masks[i] = this.bitMasks[bands[i]];
+ }
+ return new SinglePixelPackedSampleModel(this.dataType, this.width,
+ this.height, this.scanlineStride, masks);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new SinglePixelPackedSampleModel(this.dataType, w, h,
+ this.bitMasks);
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixel[];
+ if (iArray == null) {
+ pixel = new int[this.numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < this.numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < this.numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int sample = data.getElem(y * scanlineStride + x);
+ return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]);
+ }
+
+ @Override
+ public int[] getPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int pixels[];
+
+ if (iArray == null) {
+ pixels = new int[w * h * this.numBands];
+ } else {
+ pixels = iArray;
+ }
+
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < this.numBands; n++) {
+ pixels[idx++] = getSample(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages
+ .getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < this.numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int tmp = data.getElem(y * scanlineStride + x);
+ tmp &= ~this.bitMasks[b];
+ tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b];
+ data.setElem(y * scanlineStride + x, tmp);
+ }
+
+ @Override
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages
+ .getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(x + j, y + i, b, iArray[idx++], data);
+ }
+ }
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer data = null;
+ int size = (this.height - 1) * scanlineStride + width;
+
+ switch (this.dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size);
+ break;
+ }
+ return data;
+ }
+
+ /**
+ * Gets the offset of the specified pixel in the data array.
+ *
+ * @param x the X coordinate of the specified pixel.
+ * @param y the Y coordinate of the specified pixel.
+ *
+ * @return the offset of the specified pixel.
+ */
+ public int getOffset(int x, int y) {
+ return (y * scanlineStride + x);
+ }
+
+ @Override
+ public int getSampleSize(int band) {
+ return bitSizes[band];
+ }
+
+ @Override
+ public int[] getSampleSize() {
+ return bitSizes.clone();
+ }
+
+ /**
+ * Gets an array of the bit offsets of the data array elements.
+ *
+ * @return an array of the bit offsets.
+ */
+ public int[] getBitOffsets() {
+ return bitOffsets.clone();
+ }
+
+ /**
+ * Gets an array of the bit masks for all bands.
+ *
+ * @return an array of the bit masks for all bands.
+ */
+ public int[] getBitMasks() {
+ return bitMasks.clone();
+ }
+
+ /**
+ * Returns a hash code of this MultiPixelPackedSampleModel class.
+ *
+ * @return the hash code of this MultiPixelPackedSampleModel class.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp = 0;
+
+ hash = width;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= height;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= numBands;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataType;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ for (int element : bitMasks) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ for (int element : bitOffsets) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ for (int element : bitSizes) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ hash ^= scanlineStride;
+ return hash;
+ }
+
+ /**
+ * Gets the scanline stride.
+ *
+ * @return the scanline stride
+ */
+ public int getScanlineStride() {
+ return this.scanlineStride;
+ }
+
+ @Override
+ public int getNumDataElements() {
+ return 1;
+ }
+
+}
+
diff --git a/awt/java/awt/image/TileObserver.java b/awt/java/awt/image/TileObserver.java
new file mode 100644
index 0000000..39ded02
--- /dev/null
+++ b/awt/java/awt/image/TileObserver.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * An asynchronous update interface for receiving notifications
+ * about tile information when tiles of a WritableRenderedImage
+ * become modifiable or unmodifiable.
+ */
+public interface TileObserver {
+
+ /**
+ * This method is called when information about a tile
+ * update is available.
+ *
+ * @param source the source image.
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ * @param willBeWritable parameter which indicates whether
+ * the tile will be grabbed for writing or be released.
+ */
+ public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, boolean willBeWritable);
+
+}
+
diff --git a/awt/java/awt/image/VolatileImage.java b/awt/java/awt/image/VolatileImage.java
new file mode 100644
index 0000000..3b0cfb2
--- /dev/null
+++ b/awt/java/awt/image/VolatileImage.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.ImageCapabilities;
+import java.awt.Transparency;
+
+/**
+ * The VolatileImage abstract class represents an image which can lose
+ * its contents at any point. VolatileImage objects are device specific.
+ * This class provies methods for checking if operation of this image
+ * are compatible for the GraphicsConfiguration.
+ */
+public abstract class VolatileImage extends Image
+ // Volatile image implements Transparency since 1.5
+ implements Transparency {
+
+ /**
+ * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage
+ * is not applicable for the GraphicsConfiguration object.
+ */
+ public static final int IMAGE_INCOMPATIBLE = 2;
+
+ /**
+ * The Constant IMAGE_OK indicates that VolatileImage is ready
+ * for using.
+ */
+ public static final int IMAGE_OK = 0;
+
+ /**
+ * The Constant IMAGE_RESTORED indicates that VolatileImage
+ * will be ready to use after restoring.
+ */
+ public static final int IMAGE_RESTORED = 1;
+
+ /**
+ * The transparency value of this image.
+ */
+ protected int transparency = OPAQUE;
+
+ /**
+ * Instantiates a new VolatileImage object.
+ */
+ public VolatileImage() {
+ super();
+ }
+
+ /**
+ * Returns true if rendering data is lost during validating.
+ * This method should be called after rendering operation of image.
+ *
+ * @return true, if contents lost during validating, false otherwise.
+ */
+
+ public abstract boolean contentsLost();
+
+ /**
+ * Creates a Graphics2D used to draw in this VolatileImage.
+ *
+ * @return the Graphics2D object.
+ */
+ public abstract Graphics2D createGraphics();
+
+ /**
+ * Gets the ImageCapabilities of this VolatileImage.
+ *
+ * @return the ImageCapabilities of this VolatileImage.
+ */
+ public abstract ImageCapabilities getCapabilities();
+
+ /**
+ * Gets the height of this VolatileImage.
+ *
+ * @return the height of this VolatileImage.
+ */
+ public abstract int getHeight();
+
+ /**
+ * Gets a BufferedImage representation of current VolatileImage that
+ * won't be affected by any changes to this VolatileImage.
+ *
+ * @return a BufferedImage representation of current VolatileImage.
+ */
+ public abstract BufferedImage getSnapshot();
+
+ /**
+ * Gets the width of this VolatileImage.
+ *
+ * @return the width of this VolatileImage.
+ */
+ public abstract int getWidth();
+
+ /**
+ * Validates the drawing surface of the image if the surface had been
+ * lost and if the spacified GraphicsConfiguration object is
+ * applicable to this image.
+ *
+ * @param gc GraphicsConfiguration object.
+ *
+ * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or
+ * IMAGE_INCOMPATIBLE.
+ */
+ public abstract int validate(GraphicsConfiguration gc);
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public Graphics getGraphics() {
+ return createGraphics();
+ }
+
+ @Override
+ public ImageProducer getSource() {
+ return getSnapshot().getSource();
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+}
diff --git a/awt/java/awt/image/WritableRaster.java b/awt/java/awt/image/WritableRaster.java
new file mode 100644
index 0000000..0893915
--- /dev/null
+++ b/awt/java/awt/image/WritableRaster.java
@@ -0,0 +1,516 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The WritableRaster class provides functionality for
+ * writing samples and pixel capabilities to the Raster.
+ */
+public class WritableRaster extends Raster {
+
+ /**
+ * Instantiates a new WritableRaster object with the specified
+ * SampleModel, DataBuffer, rectangular region and parent
+ * WritableRaster.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param aRegion the rectangular region which defines the new image bounds.
+ * @param sampleModelTranslate this point defines the translation point
+ * from the SampleModel to the new WritableRaster coordinates.
+ * @param parent the parent of this WritableRaster.
+ */
+ protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Rectangle aRegion, Point sampleModelTranslate,
+ WritableRaster parent) {
+ super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent);
+ }
+
+ /**
+ * Instantiates a new WritableRaster object with the specified
+ * SampleModel which defines a layout of this WritableRaster and
+ * DataBuffer objects which defines the image data.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param origin the point of origin.
+ */
+ protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Point origin) {
+ this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
+ sampleModel.width, sampleModel.height), origin, null);
+ }
+
+ /**
+ * Instantiates a new WritableRaster with the specified SampleModel.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param origin the origin.
+ */
+ protected WritableRaster(SampleModel sampleModel, Point origin) {
+ this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(
+ origin.x, origin.y, sampleModel.width, sampleModel.height),
+ origin, null);
+ }
+
+ /**
+ * Sets the data for a single pixel from an input Object which
+ * represents an array of primitive types: DataBuffer.TYPE_BYTE,
+ * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param inData the input data.
+ */
+ public void setDataElements(int x, int y, Object inData) {
+ sampleModel.setDataElements(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, inData, dataBuffer);
+ }
+
+ /**
+ * Sets the data elements which represent pixel data to the specified
+ * rectangle area as a primitive array. The following image data types
+ * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+ * or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param inData the array of primitive type data to be set to the
+ * specified area.
+ */
+ public void setDataElements(int x, int y, int w, int h, Object inData) {
+ sampleModel.setDataElements(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, inData, dataBuffer);
+ }
+
+ /**
+ * Creates the child of this WritableRaster by sharing the specified
+ * rectangular area in this WritableRaster.
+ * The parentX, parentY, width and height parameters specify rectangular
+ * area to be shared.
+ *
+ * @param parentX the X coordinate of the upper left corner of
+ * the shared rectangle with respect to this WritableRaster' coordinates.
+ * @param parentY the Y coordinate of the upper left corner of
+ * the shared rectangle with respect to this WritableRaster' coordinates.
+ * @param w the width of the child area.
+ * @param h the height of the child area.
+ * @param childMinX the X coordinate of child area mapped to the parentX
+ * coordinate.
+ * @param childMinY the Y coordinate of child area mapped to the parentY
+ * coordinate.
+ * @param bandList the array of band indicies.
+ *
+ * @return the child WritableRaster.
+ */
+ public WritableRaster createWritableChild(int parentX, int parentY, int w,
+ int h, int childMinX, int childMinY, int bandList[]) {
+ if (w <= 0 || h <= 0) {
+ // awt.244=Width or Height of child Raster is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$
+ }
+
+ if (parentX < this.minX || parentX + w > this.minX + this.width) {
+ // awt.245=parentX disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.245")); //$NON-NLS-1$
+ }
+
+ if (parentY < this.minY || parentY + h > this.minY + this.height) {
+ // awt.246=parentY disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$
+ }
+
+ if ((long) parentX + w > Integer.MAX_VALUE) {
+ // awt.247=parentX + w results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$
+ }
+
+ if ((long) parentY + h > Integer.MAX_VALUE) {
+ // awt.248=parentY + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinX + w > Integer.MAX_VALUE) {
+ // awt.249=childMinX + w results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinY + h > Integer.MAX_VALUE) {
+ // awt.24A=childMinY + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$
+ }
+
+ SampleModel childModel;
+
+ if (bandList == null) {
+ childModel = sampleModel;
+ } else {
+ childModel = sampleModel.createSubsetSampleModel(bandList);
+ }
+
+ int childTranslateX = childMinX - parentX;
+ int childTranslateY = childMinY - parentY;
+
+ return new WritableRaster(childModel, dataBuffer,
+ new Rectangle(childMinX, childMinY, w, h),
+ new Point(childTranslateX + sampleModelTranslateX,
+ childTranslateY + sampleModelTranslateY),
+ this);
+ }
+
+ /**
+ * Creates the translated child of this WritableRaster.
+ * New WritableRaster object is a reference to the this
+ * WritableRaster and with different location.
+ *
+ * @param childMinX the X coordinate of the new WritableRaster.
+ * @param childMinY the Y coordinate of the new WritableRaster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createWritableTranslatedChild(int childMinX,
+ int childMinY) {
+ return createWritableChild(minX, minY, width, height, childMinX,
+ childMinY, null);
+ }
+
+ /**
+ * Gets the parent WritableRaster for this WritableRaster object.
+ *
+ * @return the parent WritableRaster for this WritableRaster object.
+ */
+ public WritableRaster getWritableParent() {
+ return (WritableRaster) parent;
+ }
+
+ /**
+ * Sets pixels from the specified source Raster srcRaster to this
+ * WritableRaster.
+ *
+ * @param srcRaster the source Raster.
+ */
+ public void setRect(Raster srcRaster) {
+ setRect(0, 0, srcRaster);
+ }
+
+ /**
+ * Sets pixels from the specified source Raster srcRaster to this
+ * WritableRaster. Each pixel with (x, y) coordinates from the source
+ * Raster is copied to pixel with (x+dx, y+dy) coordinates in this
+ * WritableRaster. The pixels with (x+dx, y+dy) coordinates which
+ * are out the bounds of this raster are ignored.
+ *
+ * @param dx the distance the pixel's X coordinate in the source
+ * Raster is translated when writtien to this WritableRaster.
+ * @param dy the distance the pixel's Y coordinate in the source
+ * Raster is translated when writtien to this WritableRaster.
+ * @param srcRaster the source Raster.
+ */
+ public void setRect(int dx, int dy, Raster srcRaster) {
+ int w = srcRaster.getWidth();
+ int h = srcRaster.getHeight();
+
+ int srcX = srcRaster.getMinX();
+ int srcY = srcRaster.getMinY();
+
+ int dstX = srcX + dx;
+ int dstY = srcY + dy;
+
+ if (dstX < this.minX) {
+ int minOffX = this.minX - dstX;
+ w -= minOffX;
+ dstX = this.minX;
+ srcX += minOffX;
+ }
+
+ if (dstY < this.minY) {
+ int minOffY = this.minY - dstY;
+ h -= minOffY;
+ dstY = this.minY;
+ srcY += minOffY;
+ }
+
+ if (dstX + w > this.minX + this.width) {
+ int maxOffX = (dstX + w) - (this.minX + this.width);
+ w -= maxOffX;
+ }
+
+ if (dstY + h > this.minY + this.height) {
+ int maxOffY = (dstY + h) - (this.minY + this.height);
+ h -= maxOffY;
+ }
+
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ switch (sampleModel.getDataType()) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ int iPixelsLine[] = null;
+ for (int i = 0; i < h; i++) {
+ iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1,
+ iPixelsLine);
+ setPixels(dstX, dstY + i, w, 1, iPixelsLine);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fPixelsLine[] = null;
+ for (int i = 0; i < h; i++) {
+ fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1,
+ fPixelsLine);
+ setPixels(dstX, dstY + i, w, 1, fPixelsLine);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dPixelsLine[] = null;
+ for (int i = 0; i < h; i++) {
+ dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1,
+ dPixelsLine);
+ setPixels(dstX, dstY + i, w, 1, dPixelsLine);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Sets the data for a rectangle of pixels from an input Raster to
+ * this WritableRaster.
+ *
+ * @param x the X coordinate of the point where the data of
+ * the input Raster is to be written.
+ * @param y the Y coordinate of the point where the data of
+ * the input Raster is to be written.
+ * @param inRaster the input Raster.
+ */
+ public void setDataElements(int x, int y, Raster inRaster) {
+ int dstX = x + inRaster.getMinX();
+ int dstY = y + inRaster.getMinY();
+
+ int w = inRaster.getWidth();
+ int h = inRaster.getHeight();
+
+ if (dstX < this.minX || dstX + w > this.minX + this.width ||
+ dstY < this.minY || dstY + h > this.minY + this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int srcX = inRaster.getMinX();
+ int srcY = inRaster.getMinY();
+ Object line = null;
+
+ for (int i = 0; i < h; i++) {
+ line = inRaster.getDataElements(srcX, srcY + i, w, 1, line);
+ setDataElements(dstX, dstY + i, w, 1, line);
+ }
+ }
+
+ /**
+ * Sets a int array of samples for the specified pixel
+ * in this WritableRaster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param iArray the int array of samples.
+ */
+ public void setPixel(int x, int y, int iArray[]) {
+ sampleModel.setPixel(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, iArray, dataBuffer);
+ }
+
+ /**
+ * Sets a float array of samples for the specified pixel
+ * in this WritableRaster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param fArray the float array of samples.
+ */
+ public void setPixel(int x, int y, float fArray[]) {
+ sampleModel.setPixel(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, fArray, dataBuffer);
+ }
+
+ /**
+ * Sets a double array of samples for the specified pixel
+ * in this WritableRaster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param dArray the double array of samples.
+ */
+ public void setPixel(int x, int y, double dArray[]) {
+ sampleModel.setPixel(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, dArray, dataBuffer);
+ }
+
+ /**
+ * Sets a int array of samples for the specified rectangular area
+ * of pixels in this WritableRaster.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param iArray the int array of samples.
+ */
+ public void setPixels(int x, int y, int w, int h, int iArray[]) {
+ sampleModel.setPixels(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, iArray, dataBuffer);
+ }
+
+ /**
+ * Sets a float array of samples for the specified rectangular area
+ * of pixels in this WritableRaster.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param fArray the float array of samples.
+ */
+ public void setPixels(int x, int y, int w, int h, float fArray[]) {
+ sampleModel.setPixels(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, fArray, dataBuffer);
+ }
+
+ /**
+ * Sets a double array of samples for the specified rectangular area
+ * of pixels in this WritableRaster.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param dArray the double array of samples.
+ */
+ public void setPixels(int x, int y, int w, int h, double dArray[]) {
+ sampleModel.setPixels(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, dArray, dataBuffer);
+ }
+
+ /**
+ * Sets the samples for the specified band and the specified
+ * rectangular area of pixels with an int array of samples.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param b the specified band.
+ * @param iArray the int array of samples.
+
+ */
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[]) {
+ sampleModel.setSamples(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, b, iArray, dataBuffer);
+ }
+
+ /**
+ * Sets the samples for the specified band and the specified
+ * rectangular area of pixels with a float array of samples.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param b the specified band.
+ * @param fArray the float array of samples.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, float fArray[]) {
+ sampleModel.setSamples(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, b, fArray, dataBuffer);
+ }
+
+ /**
+ * Sets the samples for the specified band and the specified
+ * rectangular area of pixels with a double array of samples.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param b the specified band.
+ * @param dArray the double array of samples.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, double dArray[]) {
+ sampleModel.setSamples(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, b, dArray, dataBuffer);
+ }
+
+ /**
+ * Sets the sample for the specified band and the specified
+ * pixel with an int sample.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample to be set.
+ */
+ public void setSample(int x, int y, int b, int s) {
+ sampleModel.setSample(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, b, s, dataBuffer);
+ }
+
+ /**
+ * Sets the sample for the specified band and the specified
+ * pixel with a float sample.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample to be set.
+ */
+ public void setSample(int x, int y, int b, float s) {
+ sampleModel.setSample(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, b, s, dataBuffer);
+ }
+
+ /**
+ * Sets the sample for the specified band and the specified
+ * pixel with a int sample.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample to be set.
+ */
+ public void setSample(int x, int y, int b, double s) {
+ sampleModel.setSample(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, b, s, dataBuffer);
+ }
+
+}
+
diff --git a/awt/java/awt/image/WritableRenderedImage.java b/awt/java/awt/image/WritableRenderedImage.java
new file mode 100644
index 0000000..ee1cb9e
--- /dev/null
+++ b/awt/java/awt/image/WritableRenderedImage.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Point;
+
+/**
+ * The WriteableRenderedImage interface is interface for objects which
+ * contains Raster data of one or several tiles. This interface provides
+ * notification mehanism for obtaining tile's writing status.
+ */
+public interface WritableRenderedImage extends RenderedImage {
+
+ /**
+ * Gets and checks out the writable tile for writing.
+ *
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster getWritableTile(int tileX, int tileY);
+
+ /**
+ * Removes the registered TileObserver.
+ *
+ * @param to the TileObserver which is registered for this
+ * WritableRenderedImage.
+ */
+ public void removeTileObserver(TileObserver to);
+
+ /**
+ * Adds the specified TileObserver to this WritableRenderedImage.
+ *
+ * @param to the TileObserver object to be added.
+ */
+ public void addTileObserver(TileObserver to);
+
+ /**
+ * Sets this image to the contents of the specified Raster.
+ *
+ * @param r the specified Raster.
+ */
+ public void setData(Raster r);
+
+ /**
+ * Gets the array of points wich represent indices of tiles which
+ * are check out for writing.
+ *
+ * @return the array of Points.
+ */
+ public Point[] getWritableTileIndices();
+
+ /**
+ * Checks if the specified tile is writable or not.
+ *
+ * @param tileX the X index of tile.
+ * @param tileY the Y index of tile.
+ *
+ * @return true, if the specified tile is writable,
+ * false otherwise.
+ */
+ public boolean isTileWritable(int tileX, int tileY);
+
+ /**
+ * Release the specified writable tile. This method removes the writer
+ * from the tile.
+ *
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ */
+ public void releaseWritableTile(int tileX, int tileY);
+
+ /**
+ * Checks if there is a tile which is checked out for writing.
+ *
+ * @return true, if any tile is checked out for writing, false if there
+ * is no such tile.
+ */
+ public boolean hasTileWriters();
+
+}
+
diff --git a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
new file mode 100644
index 0000000..3e96637
--- /dev/null
+++ b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+
+/**
+ * A factory for creating ContextualRenderedImage objects with utilities
+ * for manipulating the properties in the parameter block.
+ */
+public interface ContextualRenderedImageFactory extends RenderedImageFactory {
+
+ /**
+ * Maps a render context to a parameter block and a renderable image.
+ *
+ * @param a0 the index
+ * @param a1 the RenderContext
+ * @param a2 the ParameterBlock
+ * @param a3 the RenderableImage
+ *
+ * @return the render context
+ */
+ public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, RenderableImage a3);
+
+ /**
+ * Gets the value of the property from the parameter block.
+ *
+ * @param a0 the parameter block to examine to find the property
+ * @param a1 the name of the property
+ *
+ * @return the value of the property
+ */
+ public Object getProperty(ParameterBlock a0, String a1);
+
+ /**
+ * Creates the rendered image determined by the render context and
+ * parameter block.
+ *
+ * @param a0 the RenderContext
+ * @param a1 the ParameterBlock
+ *
+ * @return the rendered image
+ */
+ public RenderedImage create(RenderContext a0, ParameterBlock a1);
+
+ /**
+ * Gets the bounding rectangle from the parameter block.
+ *
+ * @param a0 the parameter block to read the bounds from
+ *
+ * @return the bounding rectangle
+ */
+ public Rectangle2D getBounds2D(ParameterBlock a0);
+
+ /**
+ * Gets the names of all of the supported properties.
+ *
+ * @return the property names
+ */
+ public String[] getPropertyNames();
+
+ /**
+ * Checks if this image factory is dynamic.
+ *
+ * @return true, if this image factory is dynamic
+ */
+ public boolean isDynamic();
+
+}
+
diff --git a/awt/java/awt/image/renderable/ParameterBlock.java b/awt/java/awt/image/renderable/ParameterBlock.java
new file mode 100644
index 0000000..1555f45
--- /dev/null
+++ b/awt/java/awt/image/renderable/ParameterBlock.java
@@ -0,0 +1,548 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.image.RenderedImage;
+import java.io.Serializable;
+import java.util.Vector;
+
+/**
+ * The Class ParameterBlock groups an indexed set of parameter data
+ * with a set of renderable (source) images. The mapping between
+ * the indexed parameters and their property names is provided
+ * by a {@link ContextualRenderedImageFactory}
+ */
+public class ParameterBlock implements Cloneable, Serializable {
+
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -7577115551785240750L;
+
+ /** The sources (renderable images). */
+ protected Vector<Object> sources = new Vector<Object>();
+
+ /** The parameters. */
+ protected Vector<Object> parameters = new Vector<Object>();
+
+ /**
+ * Instantiates a new parameter block.
+ *
+ * @param sources the vector of source images
+ * @param parameters the vector of parameters
+ */
+ public ParameterBlock(Vector<Object> sources, Vector<Object> parameters) {
+ setSources(sources);
+ setParameters(parameters);
+ }
+
+ /**
+ * Instantiates a new parameter block with no parameters.
+ *
+ * @param sources the vector of source images
+ */
+ public ParameterBlock(Vector<Object> sources) {
+ setSources(sources);
+ }
+
+ /**
+ * Instantiates a new parameter block with no image or parameter vectors.
+ */
+ public ParameterBlock() {}
+
+ /**
+ * Sets the source image at the specified index.
+ *
+ * @param source the source image
+ * @param index the index where the source will be placed
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock setSource(Object source, int index) {
+ if(sources.size() < index + 1){
+ sources.setSize(index + 1);
+ }
+ sources.setElementAt(source, index);
+ return this;
+ }
+
+ /**
+ * Sets the parameter value object at the specified index.
+ *
+ * @param obj the parameter value to place at the desired index
+ * @param index the index where the object is to be placed in the
+ * vector of parameters
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(Object obj, int index) {
+ if(parameters.size() < index + 1){
+ parameters.setSize(index + 1);
+ }
+ parameters.setElementAt(obj, index);
+ return this;
+ }
+
+ /**
+ * Adds a source to the vector of sources.
+ *
+ * @param source the source to add
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock addSource(Object source) {
+ sources.addElement(source);
+ return this;
+ }
+
+ /**
+ * Adds the object to the vector of parameter values
+ *
+ * @param obj the obj to add
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(Object obj) {
+ parameters.addElement(obj);
+ return this;
+ }
+
+ /**
+ * Sets the vector of sources, replacing the existing
+ * vector of sources, if any.
+ *
+ * @param sources the new sources
+ */
+ public void setSources(Vector<Object> sources) {
+ this.sources = sources;
+ }
+
+ /**
+ * Sets the vector of parameters, replacing the existing
+ * vector of parameters, if any.
+ *
+ * @param parameters the new parameters
+ */
+ public void setParameters(Vector<Object> parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Gets the vector of sources.
+ *
+ * @return the sources
+ */
+ public Vector<Object> getSources() {
+ return sources;
+ }
+
+ /**
+ * Gets the vector of parameters.
+ *
+ * @return the parameters
+ */
+ public Vector<Object> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Gets the source at the specified index.
+ *
+ * @param index the index
+ *
+ * @return the source object found at the specified index
+ */
+ public Object getSource(int index) {
+ return sources.elementAt(index);
+ }
+
+ /**
+ * Gets the object parameter found at the specified index.
+ *
+ * @param index the index
+ *
+ * @return the parameter object found at the specified index
+ */
+ public Object getObjectParameter(int index) {
+ return parameters.elementAt(index);
+ }
+
+ /**
+ * Shallow clone (clones using the superclass clone method).
+ *
+ * @return the clone of this object
+ */
+ public Object shallowClone() {
+ try{
+ return super.clone();
+ }catch(Exception e){
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone() {
+ ParameterBlock replica;
+ try{
+ replica = (ParameterBlock)super.clone();
+ }catch(Exception e){
+ return null;
+ }
+ if(sources != null){
+ replica.setSources((Vector<Object>)(sources.clone()));
+ }
+ if(parameters != null){
+ replica.setParameters((Vector<Object>)(parameters.clone()));
+ }
+ return replica;
+ }
+
+ /**
+ * Gets an array of classes corresponding to all of the parameter
+ * values found in the array of parameters, in order.
+ *
+ * @return the parameter classes
+ */
+ public Class[] getParamClasses() {
+ int count = parameters.size();
+ Class paramClasses[] = new Class[count];
+
+ for(int i = 0; i < count; i++){
+ paramClasses[i] = parameters.elementAt(i).getClass();
+ }
+ return paramClasses;
+ }
+
+ /**
+ * Gets the renderable source image found at the specified index
+ * in the source array.
+ *
+ * @param index the index
+ *
+ * @return the renderable source image
+ */
+ public RenderableImage getRenderableSource(int index) {
+ return (RenderableImage)sources.elementAt(index);
+ }
+
+ /**
+ * Wraps the short value in a Short and places it in the
+ * parameter block at the specified index.
+ *
+ * @param s the short value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(short s, int index) {
+ return set(new Short(s), index);
+ }
+
+ /**
+ * Wraps the short value in a Short and adds it to the
+ * parameter block.
+ *
+ * @param s the short value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(short s) {
+ return add(new Short(s));
+ }
+
+ /**
+ * Wraps the long value in a Long and places it in the
+ * parameter block at the specified index.
+ *
+ * @param l the long value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(long l, int index) {
+ return set(new Long(l), index);
+ }
+
+ /**
+ * Wraps the long value in a Long and adds it to the
+ * parameter block.
+ *
+ * @param l the long value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(long l) {
+ return add(new Long(l));
+ }
+
+ /**
+ * Wraps the int value in an Integer and places it in the
+ * parameter block at the specified index.
+ *
+ * @param i the int value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(int i, int index) {
+ return set(new Integer(i), index);
+ }
+
+ /**
+ * Wraps the int value in an Integer and adds it to the
+ * parameter block.
+ *
+ * @param i the int value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(int i) {
+ return add(new Integer(i));
+ }
+
+ /**
+ * Wraps the float value in a Float and places it in the
+ * parameter block at the specified index.
+ *
+ * @param f the float value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(float f, int index) {
+ return set(new Float(f), index);
+ }
+
+ /**
+ * Wraps the float value in a Float and adds it to the
+ * parameter block.
+ *
+ * @param f the float value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(float f) {
+ return add(new Float(f));
+ }
+
+ /**
+ * Wraps the double value in a Double and places it in the
+ * parameter block at the specified index.
+ *
+ * @param d the double value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(double d, int index) {
+ return set(new Double(d), index);
+ }
+
+ /**
+ * Wraps the double value in a Double and adds it to the
+ * parameter block.
+ *
+ * @param d the double value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(double d) {
+ return add(new Double(d));
+ }
+
+ /**
+ * Wraps the char value in a Character and places it in the
+ * parameter block at the specified index.
+ *
+ * @param c the char value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(char c, int index) {
+ return set(new Character(c), index);
+ }
+
+ /**
+ * Wraps the char value in a Character and adds it to the
+ * parameter block.
+ *
+ * @param c the char value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(char c) {
+ return add(new Character(c));
+ }
+
+ /**
+ * Wraps the byte value in a Byte and places it in the
+ * parameter block at the specified index.
+ *
+ * @param b the byte value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(byte b, int index) {
+ return set(new Byte(b), index);
+ }
+
+ /**
+ * Wraps the byte value in a Byte and adds it to the
+ * parameter block.
+ *
+ * @param b the byte value of the parameter
+ *
+ * @return the parameter block
+ */
+ public ParameterBlock add(byte b) {
+ return add(new Byte(b));
+ }
+
+ /**
+ * Gets the RenderedImage at the specified index from the
+ * vector of source images.
+ *
+ * @param index the index
+ *
+ * @return the rendered image
+ */
+ public RenderedImage getRenderedSource(int index) {
+ return (RenderedImage)sources.elementAt(index);
+ }
+
+ /**
+ * Gets the short-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the short parameter
+ */
+ public short getShortParameter(int index) {
+ return ((Short)parameters.elementAt(index)).shortValue();
+ }
+
+ /**
+ * Gets the long-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the long parameter
+ */
+ public long getLongParameter(int index) {
+ return ((Long)parameters.elementAt(index)).longValue();
+ }
+
+ /**
+ * Gets the int-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the int parameter
+ */
+ public int getIntParameter(int index) {
+ return ((Integer)parameters.elementAt(index)).intValue();
+ }
+
+ /**
+ * Gets the float-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the float parameter
+ */
+ public float getFloatParameter(int index) {
+ return ((Float)parameters.elementAt(index)).floatValue();
+ }
+
+ /**
+ * Gets the double-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the double parameter
+ */
+ public double getDoubleParameter(int index) {
+ return ((Double)parameters.elementAt(index)).doubleValue();
+ }
+
+ /**
+ * Gets the char-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the char parameter
+ */
+ public char getCharParameter(int index) {
+ return ((Character)parameters.elementAt(index)).charValue();
+ }
+
+ /**
+ * Gets the byte-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the byte parameter
+ */
+ public byte getByteParameter(int index) {
+ return ((Byte)parameters.elementAt(index)).byteValue();
+ }
+
+ /**
+ * Clears the vector of sources.
+ */
+ public void removeSources() {
+ sources.removeAllElements();
+ }
+
+ /**
+ * Clears the vector of parameters.
+ */
+ public void removeParameters() {
+ parameters.removeAllElements();
+ }
+
+ /**
+ * Gets the number of elements in the vector of sources.
+ *
+ * @return the number of elements in the vector of sources
+ */
+ public int getNumSources() {
+ return sources.size();
+ }
+
+ /**
+ * Gets the number of elements in the vector of parameters.
+ *
+ * @return the number of elements in the vector of parameters
+ */
+ public int getNumParameters() {
+ return parameters.size();
+ }
+}
diff --git a/awt/java/awt/image/renderable/RenderContext.java b/awt/java/awt/image/renderable/RenderContext.java
new file mode 100644
index 0000000..3a3b93c
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderContext.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+
+/**
+ * The Class RenderContext stores data on how an image is to be
+ * rendered: the affine transform, the area of interest, and
+ * the rendering hints.
+ */
+public class RenderContext implements Cloneable {
+
+ /** The affine transform. */
+ AffineTransform transform;
+
+ /** The area of interest. */
+ Shape aoi;
+
+ /** The rendering hints. */
+ RenderingHints hints;
+
+ /**
+ * Instantiates a new render context.
+ *
+ * @param usr2dev the affine transform
+ * @param aoi the area of interest
+ * @param hints the rendering hints
+ */
+ public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) {
+ this.transform = (AffineTransform)usr2dev.clone();
+ this.aoi = aoi;
+ this.hints = hints;
+ }
+
+ /**
+ * Instantiates a new render context with no specified hints.
+ *
+ * @param usr2dev the affine transform
+ * @param aoi the area of interest
+ */
+ public RenderContext(AffineTransform usr2dev, Shape aoi) {
+ this(usr2dev, aoi, null);
+ }
+
+ /**
+ * Instantiates a new render context with no specified area of interest.
+ *
+ * @param usr2dev the affine transform
+ * @param hints the rendering hints
+ */
+ public RenderContext(AffineTransform usr2dev, RenderingHints hints) {
+ this(usr2dev, null, hints);
+ }
+
+ /**
+ * Instantiates a new render context with no rendering hints or
+ * area of interest.
+ *
+ * @param usr2dev the affine transform
+ */
+ public RenderContext(AffineTransform usr2dev) {
+ this(usr2dev, null, null);
+ }
+
+ @Override
+ public Object clone() {
+ return new RenderContext(transform, aoi, hints);
+ }
+
+ /**
+ * Sets the affine transform for this render context.
+ *
+ * @param newTransform the new affine transform
+ */
+ public void setTransform(AffineTransform newTransform) {
+ transform = (AffineTransform)newTransform.clone();
+ }
+
+ /**
+ * Concatenates the current transform with the specified transform
+ * (so they are applied with the specified transform acting first)
+ * and sets the resulting transform as the affine transform of
+ * this rendering context.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ *
+ * @deprecated use {@link RenderContext#preConcatenateTransform(AffineTransform)}
+ */
+ @Deprecated
+ public void preConcetenateTransform(AffineTransform modTransform) {
+ preConcatenateTransform(modTransform);
+ }
+
+ /**
+ * Concatenates the current transform with the specified transform
+ * (so they are applied with the specified transform acting first)
+ * and sets the resulting transform as the affine transform of
+ * this rendering context.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ */
+ public void preConcatenateTransform(AffineTransform modTransform) {
+ transform.preConcatenate(modTransform);
+ }
+
+ /**
+ * Concatenate the specified transform with the current transform.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ *
+ * @deprecated use {@link RenderContext#concatenateTransform(AffineTransform)}
+ */
+ @Deprecated
+ public void concetenateTransform(AffineTransform modTransform) {
+ concatenateTransform(modTransform);
+ }
+
+ /**
+ * Concatenate the specified transform with the current transform.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ */
+ public void concatenateTransform(AffineTransform modTransform) {
+ transform.concatenate(modTransform);
+ }
+
+ /**
+ * Gets the transform.
+ *
+ * @return the transform
+ */
+ public AffineTransform getTransform() {
+ return (AffineTransform)transform.clone();
+ }
+
+ /**
+ * Sets the area of interest.
+ *
+ * @param newAoi the new area of interest
+ */
+ public void setAreaOfInterest(Shape newAoi) {
+ aoi = newAoi;
+ }
+
+ /**
+ * Gets the area of interest.
+ *
+ * @return the area of interest
+ */
+ public Shape getAreaOfInterest() {
+ return aoi;
+ }
+
+ /**
+ * Sets the rendering hints.
+ *
+ * @param hints the new rendering hints
+ */
+ public void setRenderingHints(RenderingHints hints) {
+ this.hints = hints;
+ }
+
+ /**
+ * Gets the rendering hints.
+ *
+ * @return the rendering hints
+ */
+ public RenderingHints getRenderingHints() {
+ return hints;
+ }
+}
diff --git a/awt/java/awt/image/renderable/RenderableImage.java b/awt/java/awt/image/renderable/RenderableImage.java
new file mode 100644
index 0000000..885dc06
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImage.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+/**
+ * The Interface RenderableImage is implemented by an object that
+ * collects all of the image-specific data that defines a single image
+ * that could be rendered to different rendering targets.
+ */
+public interface RenderableImage {
+
+ /** The Constant HINTS_OBSERVED indicates that the rendering
+ * hints are applied rather than ignored. */
+ public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$
+
+ /**
+ * Gets the property from the RenderableImage's parameter block.
+ *
+ * @param name the name of the property to get.
+ *
+ * @return the value of the property
+ */
+ public Object getProperty(String name);
+
+ /**
+ * Creates the rendered image based on the information contained
+ * in the parameters and the render context.
+ *
+ * @param renderContext the render context giving rendering specifications
+ * such as transformations
+ *
+ * @return the rendered image
+ */
+ public RenderedImage createRendering(RenderContext renderContext);
+
+ /**
+ * Creates the scaled rendered image based on the information contained
+ * in the parameters and the render context.
+ *
+ * @param w the desired width after scaling or zero if the scaling
+ * should be proportional, based on the height
+ * @param h the desired height after scaling or zero if the scaling
+ * should be proportional, based on the width
+ * @param hints the rendering hints to use
+ *
+ * @return the rendered image
+ *
+ * @throws IllegalArgumentException if both the height and width are zero
+ */
+ public RenderedImage createScaledRendering(int w, int h, RenderingHints hints);
+
+ /**
+ * Gets the vector of sources from the parameter block.
+ *
+ * @return the sources
+ */
+ public Vector<RenderableImage> getSources();
+
+ /**
+ * Gets the names of all of the supported properties in the current context.
+ *
+ * @return the property names
+ */
+ public String[] getPropertyNames();
+
+ /**
+ * Creates the default rendering (using the identity transform
+ * and default render context).
+ *
+ * @return the rendered image
+ */
+ public RenderedImage createDefaultRendering();
+
+ /**
+ * Checks if this context supports dynamic rendering.
+ *
+ * @return true, if this context supports dynamic rendering
+ */
+ public boolean isDynamic();
+
+ /**
+ * Gets the width of the image.
+ *
+ * @return the width of the image
+ */
+ public float getWidth();
+
+ /**
+ * Gets the y coordinate of the upper left corner.
+ *
+ * @return the y coordinate of the upper left corner
+ */
+ public float getMinY();
+
+ /**
+ * Gets the x coordinate of the upper left corner.
+ *
+ * @return the x coordinate of the upper left corner
+ */
+ public float getMinX();
+
+ /**
+ * Gets the height of the image.
+ *
+ * @return the height of the image
+ */
+ public float getHeight();
+
+}
+
diff --git a/awt/java/awt/image/renderable/RenderableImageOp.java b/awt/java/awt/image/renderable/RenderableImageOp.java
new file mode 100644
index 0000000..993ba5f
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImageOp.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RenderableImageOp is a basic implementation of RenderableImage,
+ * with methods to access the parameter data and perform rendering
+ * operations.
+ */
+public class RenderableImageOp implements RenderableImage {
+
+ /** The CRIF. */
+ ContextualRenderedImageFactory CRIF;
+
+ /** The param block. */
+ ParameterBlock paramBlock;
+
+ /** The height. */
+ float minX, minY, width, height;
+
+ /**
+ * Instantiates a new renderable image op.
+ *
+ * @param CRIF the cRIF
+ * @param paramBlock the param block
+ */
+ public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) {
+ this.CRIF = CRIF;
+ this.paramBlock = (ParameterBlock) paramBlock.clone();
+ Rectangle2D r = CRIF.getBounds2D(paramBlock);
+ minX = (float) r.getMinX();
+ minY = (float) r.getMinY();
+ width = (float) r.getWidth();
+ height = (float) r.getHeight();
+ }
+
+ public Object getProperty(String name) {
+ return CRIF.getProperty(paramBlock, name);
+ }
+
+ /**
+ * Sets the parameter block.
+ *
+ * @param paramBlock the param block
+ *
+ * @return the parameter block
+ */
+ public ParameterBlock setParameterBlock(ParameterBlock paramBlock) {
+ ParameterBlock oldParam = this.paramBlock;
+ this.paramBlock = (ParameterBlock) paramBlock.clone();
+ return oldParam;
+ }
+
+ public RenderedImage createRendering(RenderContext renderContext) {
+
+ Vector<RenderableImage> sources = getSources();
+ ParameterBlock rdParam = (ParameterBlock) paramBlock.clone();
+
+ if (sources != null) {
+ Vector<Object> rdSources = new Vector<Object>();
+ int i = 0;
+ while (i < sources.size()) {
+ RenderContext newContext = CRIF.mapRenderContext(i, renderContext, paramBlock,
+ this);
+ RenderedImage rdim = sources.elementAt(i).createRendering(newContext);
+
+ if (rdim != null) {
+ rdSources.addElement(rdim);
+ }
+ i++;
+ }
+ if (rdSources.size() > 0) {
+ rdParam.setSources(rdSources);
+ }
+ }
+ return CRIF.create(renderContext, rdParam);
+ }
+
+ public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) {
+ if(w == 0 && h == 0) {
+ // awt.60=Width and Height mustn't be equal zero both
+ throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$
+ }
+ if(w == 0){
+ w = Math.round(h*(getWidth()/getHeight()));
+ }
+
+ if(h == 0){
+ h = Math.round(w*(getHeight()/getWidth()));
+ }
+
+ double sx = (double)w/getWidth();
+ double sy = (double)h/getHeight();
+
+ AffineTransform at = AffineTransform.getScaleInstance(sx, sy);
+ RenderContext context = new RenderContext(at, hints);
+ return createRendering(context);
+ }
+
+ public Vector<RenderableImage> getSources() {
+ if(paramBlock.getNumSources() == 0) {
+ return null;
+ }
+ Vector<RenderableImage> v = new Vector<RenderableImage>();
+ int i = 0;
+ while(i < paramBlock.getNumSources()){
+ Object o = paramBlock.getSource(i);
+ if(o instanceof RenderableImage){
+ v.addElement((RenderableImage) o);
+ }
+ i++;
+ }
+ return v;
+ }
+
+ public String[] getPropertyNames() {
+ return CRIF.getPropertyNames();
+ }
+
+ /**
+ * Gets the parameter block.
+ *
+ * @return the parameter block
+ */
+ public ParameterBlock getParameterBlock() {
+ return paramBlock;
+ }
+
+ public RenderedImage createDefaultRendering() {
+ AffineTransform at = new AffineTransform();
+ RenderContext context = new RenderContext(at);
+ return createRendering(context);
+ }
+
+ public boolean isDynamic() {
+ return CRIF.isDynamic();
+ }
+
+ public float getWidth() {
+ return width;
+ }
+
+ public float getMinY() {
+ return minY;
+ }
+
+ public float getMinX() {
+ return minX;
+ }
+
+ public float getHeight() {
+ return height;
+ }
+
+}
+
diff --git a/awt/java/awt/image/renderable/RenderableImageProducer.java b/awt/java/awt/image/renderable/RenderableImageProducer.java
new file mode 100644
index 0000000..7fda98c
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImageProducer.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+/**
+ * The Class RenderableImageProducer provides the implementation for
+ * the image rendering.
+ */
+public class RenderableImageProducer implements ImageProducer, Runnable {
+
+ /** The rbl. */
+ RenderableImage rbl;
+
+ /** The rc. */
+ RenderContext rc;
+
+ /** The consumers. */
+ Vector<ImageConsumer> consumers = new Vector<ImageConsumer>();
+
+ /**
+ * Instantiates a new renderable image producer.
+ *
+ * @param rdblImage the rdbl image
+ * @param rc the rc
+ */
+ public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) {
+ this.rbl = rdblImage;
+ this.rc = rc;
+ }
+
+ /**
+ * Sets the render context.
+ *
+ * @param rc the new render context
+ */
+ public synchronized void setRenderContext(RenderContext rc) {
+ this.rc = rc;
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ return consumers.contains(ic);
+ }
+
+ public synchronized void startProduction(ImageConsumer ic) {
+ addConsumer(ic);
+ Thread t = new Thread(this, "RenderableImageProducer thread"); //$NON-NLS-1$
+ t.start();
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {}
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ if(ic != null) {
+ consumers.removeElement(ic);
+ }
+ }
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if(ic != null && !consumers.contains(ic)){
+ consumers.addElement(ic);
+ }
+ }
+
+ /**
+ * Creates the rendered image in a new thread.
+ */
+ public void run() {
+ if(rbl == null) {
+ return;
+ }
+
+ RenderedImage rd;
+ if(rc != null) {
+ rd = rbl.createRendering(rc);
+ } else {
+ rd = rbl.createDefaultRendering();
+ }
+
+ ColorModel cm = rd.getColorModel();
+ if(cm == null) {
+ cm = ColorModel.getRGBdefault();
+ }
+
+ Raster r = rd.getData();
+ int w = r.getWidth();
+ int h = r.getHeight();
+
+ for (ImageConsumer c : consumers) {
+ c.setDimensions(w, h);
+ c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEFRAME |
+ ImageConsumer.SINGLEPASS);
+ }
+
+ int scanLine[] = new int[w];
+ int pixel[] = null;
+
+ for(int y = 0; y < h; y++){
+ for(int x = 0; x < w; x++){
+ pixel = r.getPixel(x, y, pixel);
+ scanLine[x] = cm.getDataElement(pixel, 0);
+ }
+
+ for (ImageConsumer c : consumers) {
+ c.setPixels(0, y, w, 1, cm, scanLine, 0, w);
+ }
+ }
+
+ for (ImageConsumer c : consumers) {
+ c.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/image/renderable/RenderedImageFactory.java b/awt/java/awt/image/renderable/RenderedImageFactory.java
new file mode 100644
index 0000000..345d82c
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderedImageFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+
+/**
+ * A factory for creating RenderedImage objects based on parameters
+ * and rendering hints.
+ */
+public interface RenderedImageFactory {
+
+ /**
+ * Creates the rendered image.
+ *
+ * @param a0 the ParameterBlock
+ * @param a1 the RenderingHints
+ *
+ * @return the rendered image
+ */
+ public RenderedImage create(ParameterBlock a0, RenderingHints a1);
+
+}
+
diff --git a/awt/java/awt/peer/ButtonPeer.java b/awt/java/awt/peer/ButtonPeer.java
new file mode 100644
index 0000000..cc45b49
--- /dev/null
+++ b/awt/java/awt/peer/ButtonPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ButtonPeer {
+
+}
diff --git a/awt/java/awt/peer/CanvasPeer.java b/awt/java/awt/peer/CanvasPeer.java
new file mode 100644
index 0000000..e276366
--- /dev/null
+++ b/awt/java/awt/peer/CanvasPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CanvasPeer {
+
+}
diff --git a/awt/java/awt/peer/CheckboxMenuItemPeer.java b/awt/java/awt/peer/CheckboxMenuItemPeer.java
new file mode 100644
index 0000000..296f422
--- /dev/null
+++ b/awt/java/awt/peer/CheckboxMenuItemPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CheckboxMenuItemPeer {
+
+}
diff --git a/awt/java/awt/peer/CheckboxPeer.java b/awt/java/awt/peer/CheckboxPeer.java
new file mode 100644
index 0000000..e9f8dd1
--- /dev/null
+++ b/awt/java/awt/peer/CheckboxPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CheckboxPeer {
+
+}
diff --git a/awt/java/awt/peer/ChoicePeer.java b/awt/java/awt/peer/ChoicePeer.java
new file mode 100644
index 0000000..57b7629
--- /dev/null
+++ b/awt/java/awt/peer/ChoicePeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ChoicePeer {
+
+}
diff --git a/awt/java/awt/peer/ComponentPeer.java b/awt/java/awt/peer/ComponentPeer.java
new file mode 100644
index 0000000..bc26791
--- /dev/null
+++ b/awt/java/awt/peer/ComponentPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ComponentPeer {
+
+}
diff --git a/awt/java/awt/peer/DialogPeer.java b/awt/java/awt/peer/DialogPeer.java
new file mode 100644
index 0000000..8ae3049
--- /dev/null
+++ b/awt/java/awt/peer/DialogPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface DialogPeer {
+
+}
diff --git a/awt/java/awt/peer/FileDialogPeer.java b/awt/java/awt/peer/FileDialogPeer.java
new file mode 100644
index 0000000..0d15e48
--- /dev/null
+++ b/awt/java/awt/peer/FileDialogPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FileDialogPeer {
+
+}
diff --git a/awt/java/awt/peer/FontPeer.java b/awt/java/awt/peer/FontPeer.java
new file mode 100644
index 0000000..fd9815f
--- /dev/null
+++ b/awt/java/awt/peer/FontPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FontPeer {
+
+}
diff --git a/awt/java/awt/peer/FramePeer.java b/awt/java/awt/peer/FramePeer.java
new file mode 100644
index 0000000..9cfc40b
--- /dev/null
+++ b/awt/java/awt/peer/FramePeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FramePeer {
+
+}
diff --git a/awt/java/awt/peer/LabelPeer.java b/awt/java/awt/peer/LabelPeer.java
new file mode 100644
index 0000000..052ca9d
--- /dev/null
+++ b/awt/java/awt/peer/LabelPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface LabelPeer {
+
+}
diff --git a/awt/java/awt/peer/LightweightPeer.java b/awt/java/awt/peer/LightweightPeer.java
new file mode 100644
index 0000000..1dee905
--- /dev/null
+++ b/awt/java/awt/peer/LightweightPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface LightweightPeer {
+
+}
diff --git a/awt/java/awt/peer/ListPeer.java b/awt/java/awt/peer/ListPeer.java
new file mode 100644
index 0000000..0a27885
--- /dev/null
+++ b/awt/java/awt/peer/ListPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ListPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuBarPeer.java b/awt/java/awt/peer/MenuBarPeer.java
new file mode 100644
index 0000000..3ad2c16
--- /dev/null
+++ b/awt/java/awt/peer/MenuBarPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuBarPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuComponentPeer.java b/awt/java/awt/peer/MenuComponentPeer.java
new file mode 100644
index 0000000..3ac3b34
--- /dev/null
+++ b/awt/java/awt/peer/MenuComponentPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuComponentPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuItemPeer.java b/awt/java/awt/peer/MenuItemPeer.java
new file mode 100644
index 0000000..b133897
--- /dev/null
+++ b/awt/java/awt/peer/MenuItemPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuItemPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuPeer.java b/awt/java/awt/peer/MenuPeer.java
new file mode 100644
index 0000000..d643ce7
--- /dev/null
+++ b/awt/java/awt/peer/MenuPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuPeer {
+
+}
diff --git a/awt/java/awt/peer/MouseInfoPeer.java b/awt/java/awt/peer/MouseInfoPeer.java
new file mode 100644
index 0000000..9173a62
--- /dev/null
+++ b/awt/java/awt/peer/MouseInfoPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MouseInfoPeer {
+
+}
diff --git a/awt/java/awt/peer/PanelPeer.java b/awt/java/awt/peer/PanelPeer.java
new file mode 100644
index 0000000..1faa1fe
--- /dev/null
+++ b/awt/java/awt/peer/PanelPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface PanelPeer {
+
+}
diff --git a/awt/java/awt/peer/PopupMenuPeer.java b/awt/java/awt/peer/PopupMenuPeer.java
new file mode 100644
index 0000000..cf1ef61
--- /dev/null
+++ b/awt/java/awt/peer/PopupMenuPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface PopupMenuPeer {
+
+}
diff --git a/awt/java/awt/peer/ScrollPanePeer.java b/awt/java/awt/peer/ScrollPanePeer.java
new file mode 100644
index 0000000..df3de83
--- /dev/null
+++ b/awt/java/awt/peer/ScrollPanePeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ScrollPanePeer {
+
+}
diff --git a/awt/java/awt/peer/ScrollbarPeer.java b/awt/java/awt/peer/ScrollbarPeer.java
new file mode 100644
index 0000000..eec8961
--- /dev/null
+++ b/awt/java/awt/peer/ScrollbarPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ScrollbarPeer {
+
+}
diff --git a/awt/java/awt/peer/TextAreaPeer.java b/awt/java/awt/peer/TextAreaPeer.java
new file mode 100644
index 0000000..636707f
--- /dev/null
+++ b/awt/java/awt/peer/TextAreaPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface TextAreaPeer {
+
+}
diff --git a/awt/java/awt/peer/TextFieldPeer.java b/awt/java/awt/peer/TextFieldPeer.java
new file mode 100644
index 0000000..2b8232a
--- /dev/null
+++ b/awt/java/awt/peer/TextFieldPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface TextFieldPeer {
+
+}
diff --git a/awt/java/awt/peer/WindowPeer.java b/awt/java/awt/peer/WindowPeer.java
new file mode 100644
index 0000000..384646f
--- /dev/null
+++ b/awt/java/awt/peer/WindowPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface WindowPeer {
+
+}
diff --git a/awt/java/beans/FeatureDescriptor.java b/awt/java/beans/FeatureDescriptor.java
new file mode 100644
index 0000000..2945c65
--- /dev/null
+++ b/awt/java/beans/FeatureDescriptor.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.beans;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * Common base class for Descriptors.
+ */
+public class FeatureDescriptor {
+
+ private Map<String, Object> values;
+
+ boolean preferred, hidden, expert;
+
+ String shortDescription;
+
+ String name;
+
+ String displayName;
+
+ /**
+ * <p>
+ * Constructs an instance.
+ * </p>
+ */
+ public FeatureDescriptor() {
+ this.values = new HashMap<String, Object>();
+ }
+
+ /**
+ * <p>
+ * Sets the value for the named attribute.
+ * </p>
+ *
+ * @param attributeName
+ * The name of the attribute to set a value with.
+ * @param value
+ * The value to set.
+ */
+ public void setValue(String attributeName, Object value) {
+ if (attributeName == null || value == null) {
+ throw new NullPointerException();
+ }
+ values.put(attributeName, value);
+ }
+
+ /**
+ * <p>
+ * Gets the value associated with the named attribute.
+ * </p>
+ *
+ * @param attributeName
+ * The name of the attribute to get a value for.
+ * @return The attribute's value.
+ */
+ public Object getValue(String attributeName) {
+ Object result = null;
+ if (attributeName != null) {
+ result = values.get(attributeName);
+ }
+ return result;
+ }
+
+ /**
+ * <p>
+ * Enumerates the attribute names.
+ * </p>
+ *
+ * @return An instance of {@link Enumeration}.
+ */
+ public Enumeration<String> attributeNames() {
+ // Create a new list, so that the references are copied
+ return Collections.enumeration(new LinkedList<String>(values.keySet()));
+ }
+
+ /**
+ * <p>
+ * Sets the short description.
+ * </p>
+ *
+ * @param text
+ * The description to set.
+ */
+ public void setShortDescription(String text) {
+ this.shortDescription = text;
+ }
+
+ /**
+ * <p>
+ * Sets the name.
+ * </p>
+ *
+ * @param name
+ * The name to set.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * <p>
+ * Sets the display name.
+ * </p>
+ *
+ * @param displayName
+ * The display name to set.
+ */
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ /**
+ * <p>
+ * Gets the short description or {@link #getDisplayName()} if not set.
+ * </p>
+ *
+ * @return The description.
+ */
+ public String getShortDescription() {
+ return shortDescription == null ? getDisplayName() : shortDescription;
+ }
+
+ /**
+ * <p>
+ * Gets the name.
+ * </p>
+ *
+ * @return The name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * <p>
+ * Gets the display name or {@link #getName()} if not set.
+ * </p>
+ *
+ * @return The display name.
+ */
+ public String getDisplayName() {
+ return displayName == null ? getName() : displayName;
+ }
+
+ /**
+ * <p>
+ * Sets the preferred indicator.
+ * </p>
+ *
+ * @param preferred
+ * <code>true</code> if preferred, <code>false</code>
+ * otherwise.
+ */
+ public void setPreferred(boolean preferred) {
+ this.preferred = preferred;
+ }
+
+ /**
+ * <p>
+ * Sets the hidden indicator.
+ * </p>
+ *
+ * @param hidden
+ * <code>true</code> if hidden, <code>false</code> otherwise.
+ */
+ public void setHidden(boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ /**
+ * <p>
+ * Sets the expert indicator.
+ * </p>
+ *
+ * @param expert
+ * <code>true</code> if expert, <code>false</code> otherwise.
+ */
+ public void setExpert(boolean expert) {
+ this.expert = expert;
+ }
+
+ /**
+ * <p>
+ * Indicates if this feature is preferred.
+ * </p>
+ *
+ * @return <code>true</code> if preferred, <code>false</code> otherwise.
+ */
+ public boolean isPreferred() {
+ return preferred;
+ }
+
+ /**
+ * <p>
+ * Indicates if this feature is hidden.
+ * </p>
+ *
+ * @return <code>true</code> if hidden, <code>false</code> otherwise.
+ */
+ public boolean isHidden() {
+ return hidden;
+ }
+
+ /**
+ * <p>
+ * Indicates if this feature is an expert feature.
+ * </p>
+ *
+ * @return <code>true</code> if hidden, <code>false</code> otherwise.
+ */
+ public boolean isExpert() {
+ return expert;
+ }
+}
diff --git a/awt/java/beans/IndexedPropertyChangeEvent.java b/awt/java/beans/IndexedPropertyChangeEvent.java
new file mode 100644
index 0000000..c9084c6
--- /dev/null
+++ b/awt/java/beans/IndexedPropertyChangeEvent.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.beans;
+
+/**
+ * A type of {@link PropertyChangeEvent} that indicates that an indexed property
+ * has changed.
+ *
+ * @since 1.5
+ */
+public class IndexedPropertyChangeEvent extends PropertyChangeEvent {
+
+ private static final long serialVersionUID = -320227448495806870L;
+
+ private final int index;
+
+ /**
+ * Creates a new property changed event with an indication of the property
+ * index.
+ *
+ * @param source
+ * the changed bean.
+ * @param propertyName
+ * the changed property, or <code>null</code> to indicate an
+ * unspecified set of the properties have changed.
+ * @param oldValue
+ * the previous value of the property, or <code>null</code> if
+ * the <code>propertyName</code> is <code>null</code> or the
+ * previous value is unknown.
+ * @param newValue
+ * the new value of the property, or <code>null</code> if the
+ * <code>propertyName</code> is <code>null</code> or the new
+ * value is unknown..
+ * @param index
+ * the index of the property.
+ */
+ public IndexedPropertyChangeEvent(Object source, String propertyName,
+ Object oldValue, Object newValue, int index) {
+ super(source, propertyName, oldValue, newValue);
+ this.index = index;
+ }
+
+ /**
+ * Answer the index of the property that was changed in this event.
+ *
+ * @return The property element index.
+ */
+ public int getIndex() {
+ return index;
+ }
+}
diff --git a/awt/java/beans/IndexedPropertyDescriptor.java b/awt/java/beans/IndexedPropertyDescriptor.java
new file mode 100644
index 0000000..25667d9
--- /dev/null
+++ b/awt/java/beans/IndexedPropertyDescriptor.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class IndexedPropertyDescriptor extends PropertyDescriptor {
+ private Method indexedGetter;
+
+ private Method indexedSetter;
+
+ public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,
+ String getterName, String setterName, String indexedGetterName,
+ String indexedSetterName) throws IntrospectionException {
+ super(propertyName, beanClass, getterName, setterName);
+
+ // RI behaves like this
+ if (indexedGetterName == null && indexedSetterName == null &&
+ (getterName != null || setterName != null)) {
+ throw new IntrospectionException(Messages.getString("beans.50"));
+ }
+ setIndexedReadMethod(beanClass, indexedGetterName);
+ setIndexedWriteMethod(beanClass, indexedSetterName);
+ }
+
+ public IndexedPropertyDescriptor(String propertyName, Method getter, Method setter,
+ Method indexedGetter, Method indexedSetter) throws IntrospectionException {
+ super(propertyName, getter, setter);
+
+ // we need this in order to be compatible with RI
+ if (indexedGetter == null && indexedSetter == null &&
+ (getter != null || setter != null)) {
+ throw new IntrospectionException(Messages.getString("beans.50"));
+ }
+ setIndexedReadMethod(indexedGetter);
+ setIndexedWriteMethod(indexedSetter);
+ }
+
+ public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)
+ throws IntrospectionException {
+ super(propertyName, beanClass, null, null);
+ String getterName;
+ String setterName;
+ String indexedGetterName;
+ String indexedSetterName;
+
+ // array getter
+ getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ }
+ // array setter
+ setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+ if (hasMethod(beanClass, setterName)) {
+ setWriteMethod(beanClass, setterName);
+ }
+ // indexed getter
+ indexedGetterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+ if (hasMethod(beanClass, indexedGetterName)) {
+ setIndexedReadMethod(beanClass, indexedGetterName);
+ }
+ // indexed setter
+ indexedSetterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+ if (hasMethod(beanClass, indexedSetterName)) {
+ setIndexedWriteMethod(beanClass, indexedSetterName);
+ }
+ // RI seems to behave a bit differently
+ if (indexedGetter == null && indexedSetter == null &&
+ getReadMethod() == null && getWriteMethod() == null) {
+ throw new IntrospectionException(
+ Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
+ }
+ if (indexedGetter == null && indexedSetter == null) {
+ // not an indexed property indeed
+ throw new IntrospectionException(Messages.getString("beans.50"));
+ }
+ }
+
+ public void setIndexedReadMethod(Method indexedGetter) throws IntrospectionException {
+ if (indexedGetter != null) {
+ int modifiers = indexedGetter.getModifiers();
+ Class<?>[] parameterTypes;
+ Class<?> returnType;
+ Class<?> indexedPropertyType;
+
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.21")); //$NON-NLS-1$
+ }
+ parameterTypes = indexedGetter.getParameterTypes();
+ if (parameterTypes.length != 1) {
+ throw new IntrospectionException(Messages.getString("beans.22")); //$NON-NLS-1$
+ }
+ if (!parameterTypes[0].equals(int.class)) {
+ throw new IntrospectionException(Messages.getString("beans.23")); //$NON-NLS-1$
+ }
+ returnType = indexedGetter.getReturnType();
+ indexedPropertyType = getIndexedPropertyType();
+ if ((indexedPropertyType != null) && !returnType.equals(indexedPropertyType)) {
+ throw new IntrospectionException(Messages.getString("beans.24")); //$NON-NLS-1$
+ }
+ }
+ this.indexedGetter = indexedGetter;
+ }
+
+ public void setIndexedWriteMethod(Method indexedSetter) throws IntrospectionException {
+ if (indexedSetter != null) {
+ int modifiers = indexedSetter.getModifiers();
+ Class<?>[] parameterTypes;
+ Class<?> firstParameterType;
+ Class<?> secondParameterType;
+ Class<?> propType;
+
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.25")); //$NON-NLS-1$
+ }
+ parameterTypes = indexedSetter.getParameterTypes();
+ if (parameterTypes.length != 2) {
+ throw new IntrospectionException(Messages.getString("beans.26")); //$NON-NLS-1$
+ }
+ firstParameterType = parameterTypes[0];
+ if (!firstParameterType.equals(int.class)) {
+ throw new IntrospectionException(Messages.getString("beans.27")); //$NON-NLS-1$
+ }
+ secondParameterType = parameterTypes[1];
+ propType = getIndexedPropertyType();
+ if (propType != null && !secondParameterType.equals(propType)) {
+ throw new IntrospectionException(Messages.getString("beans.28")); //$NON-NLS-1$
+ }
+ }
+ this.indexedSetter = indexedSetter;
+ }
+
+ public Method getIndexedWriteMethod() {
+ return indexedSetter;
+ }
+
+ public Method getIndexedReadMethod() {
+ return indexedGetter;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ boolean result = super.equals(obj);
+
+ if (result) {
+ IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) obj;
+
+ if (indexedGetter != null) {
+ result = indexedGetter.equals(pd.getIndexedReadMethod());
+ } else if (result && indexedGetter == null) {
+ result = pd.getIndexedReadMethod() == null;
+ }
+
+ if (result) {
+ if (indexedSetter != null) {
+ result = indexedSetter.equals(pd.getIndexedWriteMethod());
+ } else if (indexedSetter == null) {
+ result = pd.getIndexedWriteMethod() == null;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public Class<?> getIndexedPropertyType() {
+ Class<?> result = null;
+
+ if (indexedGetter != null) {
+ result = indexedGetter.getReturnType();
+ } else if (indexedSetter != null) {
+ Class<?>[] parameterTypes = indexedSetter.getParameterTypes();
+
+ result = parameterTypes[1];
+ }
+ return result;
+ }
+
+ private void setIndexedReadMethod(Class<?> beanClass, String indexedGetterName) {
+ Method[] getters = findMethods(beanClass, indexedGetterName);
+ boolean result = false;
+
+ for (Method element : getters) {
+ try {
+ setIndexedReadMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {}
+
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ private void setIndexedWriteMethod(Class<?> beanClass, String indexedSetterName) {
+ Method[] setters = findMethods(beanClass, indexedSetterName);
+ boolean result = false;
+
+ for (Method element : setters) {
+ try {
+ setIndexedWriteMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {}
+
+ if (result) {
+ break;
+ }
+ }
+ }
+}
diff --git a/awt/java/beans/IntrospectionException.java b/awt/java/beans/IntrospectionException.java
new file mode 100644
index 0000000..c895afe
--- /dev/null
+++ b/awt/java/beans/IntrospectionException.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+public class IntrospectionException extends Exception {
+
+ static final long serialVersionUID = -3728150539969542619L;
+
+ public IntrospectionException(String message) {
+ super(message);
+ }
+}
diff --git a/awt/java/beans/PropertyChangeEvent.java b/awt/java/beans/PropertyChangeEvent.java
new file mode 100644
index 0000000..97c703a
--- /dev/null
+++ b/awt/java/beans/PropertyChangeEvent.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.EventObject;
+
+public class PropertyChangeEvent extends EventObject {
+
+ private static final long serialVersionUID = 7042693688939648123L;
+
+ String propertyName;
+
+ Object oldValue;
+
+ Object newValue;
+
+ Object propagationId;
+
+ public PropertyChangeEvent(Object source, String propertyName,
+ Object oldValue, Object newValue) {
+ super(source);
+
+ this.propertyName = propertyName;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void setPropagationId(Object propagationId) {
+ this.propagationId = propagationId;
+ }
+
+ public Object getPropagationId() {
+ return propagationId;
+ }
+
+ public Object getOldValue() {
+ return oldValue;
+ }
+
+ public Object getNewValue() {
+ return newValue;
+ }
+}
diff --git a/awt/java/beans/PropertyChangeListener.java b/awt/java/beans/PropertyChangeListener.java
new file mode 100644
index 0000000..94422c0
--- /dev/null
+++ b/awt/java/beans/PropertyChangeListener.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.EventListener;
+
+public interface PropertyChangeListener extends EventListener {
+
+ public void propertyChange(PropertyChangeEvent event);
+}
diff --git a/awt/java/beans/PropertyChangeListenerProxy.java b/awt/java/beans/PropertyChangeListenerProxy.java
new file mode 100644
index 0000000..f4f3aec
--- /dev/null
+++ b/awt/java/beans/PropertyChangeListenerProxy.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+public class PropertyChangeListenerProxy extends EventListenerProxy implements
+ PropertyChangeListener {
+
+ String propertyName;
+
+ public PropertyChangeListenerProxy(String propertyName,
+ PropertyChangeListener listener) {
+ super(listener);
+ this.propertyName = propertyName;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ PropertyChangeListener listener = (PropertyChangeListener) getListener();
+ listener.propertyChange(event);
+ }
+}
diff --git a/awt/java/beans/PropertyChangeSupport.java b/awt/java/beans/PropertyChangeSupport.java
new file mode 100644
index 0000000..d56e63a
--- /dev/null
+++ b/awt/java/beans/PropertyChangeSupport.java
@@ -0,0 +1,351 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class PropertyChangeSupport implements Serializable {
+
+ private static final long serialVersionUID = 6401253773779951803l;
+
+ private transient Object sourceBean;
+
+ private transient List<PropertyChangeListener> allPropertiesChangeListeners =
+ new ArrayList<PropertyChangeListener>();
+
+ private transient Map<String, List<PropertyChangeListener>>
+ selectedPropertiesChangeListeners =
+ new HashMap<String, List<PropertyChangeListener>>();
+
+ // fields for serialization compatibility
+ private Hashtable<String, List<PropertyChangeListener>> children;
+
+ private Object source;
+
+ private int propertyChangeSupportSerializedDataVersion = 1;
+
+ public PropertyChangeSupport(Object sourceBean) {
+ if (sourceBean == null) {
+ throw new NullPointerException();
+ }
+ this.sourceBean = sourceBean;
+ }
+
+ public void firePropertyChange(String propertyName, Object oldValue,
+ Object newValue) {
+ PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
+ oldValue, newValue);
+ doFirePropertyChange(event);
+ }
+
+ public void fireIndexedPropertyChange(String propertyName, int index,
+ Object oldValue, Object newValue) {
+
+ // nulls and equals check done in doFire...
+ doFirePropertyChange(new IndexedPropertyChangeEvent(sourceBean,
+ propertyName, oldValue, newValue, index));
+ }
+
+ public synchronized void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ if ((propertyName != null) && (listener != null)) {
+ List<PropertyChangeListener> listeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+ }
+
+ public synchronized void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ if ((listener != null) && (propertyName != null)) {
+ List<PropertyChangeListener> listeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (listeners == null) {
+ listeners = new ArrayList<PropertyChangeListener>();
+ selectedPropertiesChangeListeners.put(propertyName, listeners);
+ }
+
+ // RI compatibility
+ if (listener instanceof PropertyChangeListenerProxy) {
+ PropertyChangeListenerProxy proxy =
+ (PropertyChangeListenerProxy) listener;
+
+ listeners.add(new PropertyChangeListenerProxy(
+ proxy.getPropertyName(),
+ (PropertyChangeListener) proxy.getListener()));
+ } else {
+ listeners.add(listener);
+ }
+ }
+ }
+
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners(
+ String propertyName) {
+ List<PropertyChangeListener> listeners = null;
+
+ if (propertyName != null) {
+ listeners = selectedPropertiesChangeListeners.get(propertyName);
+ }
+
+ return (listeners == null) ? new PropertyChangeListener[] {}
+ : listeners.toArray(
+ new PropertyChangeListener[listeners.size()]);
+ }
+
+ public void firePropertyChange(String propertyName, boolean oldValue,
+ boolean newValue) {
+ PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
+ oldValue, newValue);
+ doFirePropertyChange(event);
+ }
+
+ public void fireIndexedPropertyChange(String propertyName, int index,
+ boolean oldValue, boolean newValue) {
+
+ if (oldValue != newValue) {
+ fireIndexedPropertyChange(propertyName, index, Boolean
+ .valueOf(oldValue), Boolean.valueOf(newValue));
+ }
+ }
+
+ public void firePropertyChange(String propertyName, int oldValue,
+ int newValue) {
+ PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
+ oldValue, newValue);
+ doFirePropertyChange(event);
+ }
+
+ public void fireIndexedPropertyChange(String propertyName, int index,
+ int oldValue, int newValue) {
+
+ if (oldValue != newValue) {
+ fireIndexedPropertyChange(propertyName, index,
+ new Integer(oldValue), new Integer(newValue));
+ }
+ }
+
+ public synchronized boolean hasListeners(String propertyName) {
+ boolean result = allPropertiesChangeListeners.size() > 0;
+ if (!result && (propertyName != null)) {
+ List<PropertyChangeListener> listeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+ if (listeners != null) {
+ result = listeners.size() > 0;
+ }
+ }
+ return result;
+ }
+
+ public synchronized void removePropertyChangeListener(
+ PropertyChangeListener listener) {
+ if (listener != null) {
+ if (listener instanceof PropertyChangeListenerProxy) {
+ String name = ((PropertyChangeListenerProxy) listener)
+ .getPropertyName();
+ PropertyChangeListener lst = (PropertyChangeListener)
+ ((PropertyChangeListenerProxy) listener).getListener();
+
+ removePropertyChangeListener(name, lst);
+ } else {
+ allPropertiesChangeListeners.remove(listener);
+ }
+ }
+ }
+
+ public synchronized void addPropertyChangeListener(
+ PropertyChangeListener listener) {
+ if (listener != null) {
+ if (listener instanceof PropertyChangeListenerProxy) {
+ String name = ((PropertyChangeListenerProxy) listener)
+ .getPropertyName();
+ PropertyChangeListener lst = (PropertyChangeListener)
+ ((PropertyChangeListenerProxy) listener).getListener();
+ addPropertyChangeListener(name, lst);
+ } else {
+ allPropertiesChangeListeners.add(listener);
+ }
+ }
+ }
+
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
+ ArrayList<PropertyChangeListener> result =
+ new ArrayList<PropertyChangeListener>(
+ allPropertiesChangeListeners);
+
+ for (String propertyName : selectedPropertiesChangeListeners.keySet()) {
+ List<PropertyChangeListener> selectedListeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (selectedListeners != null) {
+
+ for (PropertyChangeListener listener : selectedListeners) {
+ result.add(new PropertyChangeListenerProxy(propertyName,
+ listener));
+ }
+ }
+ }
+
+ return result.toArray(new PropertyChangeListener[result.size()]);
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ List<PropertyChangeListener> allSerializedPropertiesChangeListeners =
+ new ArrayList<PropertyChangeListener>();
+
+ for (PropertyChangeListener pcl : allPropertiesChangeListeners) {
+ if (pcl instanceof Serializable) {
+ allSerializedPropertiesChangeListeners.add(pcl);
+ }
+ }
+
+ Map<String, List<PropertyChangeListener>>
+ selectedSerializedPropertiesChangeListeners =
+ new HashMap<String, List<PropertyChangeListener>>();
+
+ for (String propertyName : selectedPropertiesChangeListeners.keySet()) {
+ List<PropertyChangeListener> keyValues =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (keyValues != null) {
+ List<PropertyChangeListener> serializedPropertiesChangeListeners
+ = new ArrayList<PropertyChangeListener>();
+
+ for (PropertyChangeListener pcl : keyValues) {
+ if (pcl instanceof Serializable) {
+ serializedPropertiesChangeListeners.add(pcl);
+ }
+ }
+
+ if (!serializedPropertiesChangeListeners.isEmpty()) {
+ selectedSerializedPropertiesChangeListeners.put(
+ propertyName, serializedPropertiesChangeListeners);
+ }
+ }
+ }
+
+ children = new Hashtable<String, List<PropertyChangeListener>>(
+ selectedSerializedPropertiesChangeListeners);
+ children.put("", allSerializedPropertiesChangeListeners); //$NON-NLS-1$
+ oos.writeObject(children);
+
+ Object source = null;
+ if (sourceBean instanceof Serializable) {
+ source = sourceBean;
+ }
+ oos.writeObject(source);
+
+ oos.writeInt(propertyChangeSupportSerializedDataVersion);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream ois) throws IOException,
+ ClassNotFoundException {
+ children = (Hashtable<String, List<PropertyChangeListener>>) ois
+ .readObject();
+
+ selectedPropertiesChangeListeners = new HashMap<String, List<PropertyChangeListener>>(
+ children);
+ allPropertiesChangeListeners = selectedPropertiesChangeListeners
+ .remove(""); //$NON-NLS-1$
+ if (allPropertiesChangeListeners == null) {
+ allPropertiesChangeListeners = new ArrayList<PropertyChangeListener>();
+ }
+
+ sourceBean = ois.readObject();
+ propertyChangeSupportSerializedDataVersion = ois.readInt();
+ }
+
+ public void firePropertyChange(PropertyChangeEvent event) {
+ doFirePropertyChange(event);
+ }
+
+ private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
+ Object oldValue, Object newValue) {
+ return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
+ newValue);
+ }
+
+ private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
+ boolean oldValue, boolean newValue) {
+ return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
+ newValue);
+ }
+
+ private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
+ int oldValue, int newValue) {
+ return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
+ newValue);
+ }
+
+ private void doFirePropertyChange(PropertyChangeEvent event) {
+ String propertyName = event.getPropertyName();
+ Object oldValue = event.getOldValue();
+ Object newValue = event.getNewValue();
+
+ if ((newValue != null) && (oldValue != null)
+ && newValue.equals(oldValue)) {
+ return;
+ }
+
+ /*
+ * Copy the listeners collections so they can be modified while we fire
+ * events.
+ */
+
+ // Listeners to all property change events
+ PropertyChangeListener[] listensToAll;
+ // Listens to a given property change
+ PropertyChangeListener[] listensToOne = null;
+ synchronized (this) {
+ listensToAll = allPropertiesChangeListeners
+ .toArray(new PropertyChangeListener[allPropertiesChangeListeners
+ .size()]);
+
+ List<PropertyChangeListener> listeners = selectedPropertiesChangeListeners
+ .get(propertyName);
+ if (listeners != null) {
+ listensToOne = listeners
+ .toArray(new PropertyChangeListener[listeners.size()]);
+ }
+ }
+
+ // Fire the listeners
+ for (PropertyChangeListener listener : listensToAll) {
+ listener.propertyChange(event);
+ }
+ if (listensToOne != null) {
+ for (PropertyChangeListener listener : listensToOne) {
+ listener.propertyChange(event);
+ }
+ }
+ }
+
+}
diff --git a/awt/java/beans/PropertyDescriptor.java b/awt/java/beans/PropertyDescriptor.java
new file mode 100644
index 0000000..9389152
--- /dev/null
+++ b/awt/java/beans/PropertyDescriptor.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Vector;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyDescriptor extends FeatureDescriptor {
+ private Method getter;
+
+ private Method setter;
+
+ private Class<?> propertyEditorClass;
+
+ private boolean constrained;
+
+ private boolean bound;
+
+ public PropertyDescriptor(String propertyName, Class<?> beanClass, String getterName,
+ String setterName) throws IntrospectionException {
+ super();
+ if (beanClass == null) {
+ throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$
+ }
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ this.setDisplayName(propertyName);
+ if (setterName != null) {
+ if (hasMethod(beanClass, setterName)) {
+ setWriteMethod(beanClass, setterName);
+ } else {
+ throw new IntrospectionException(Messages.getString("beans.20")); //$NON-NLS-1$
+ }
+ }
+ if (getterName != null) {
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ } else {
+ throw new IntrospectionException(Messages.getString("beans.1F")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public PropertyDescriptor(String propertyName, Method getter, Method setter)
+ throws IntrospectionException {
+ super();
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ this.setDisplayName(propertyName);
+ setWriteMethod(setter);
+ setReadMethod(getter);
+ }
+
+ public PropertyDescriptor(String propertyName, Class<?> beanClass)
+ throws IntrospectionException {
+ String getterName;
+ String setterName;
+ if (beanClass == null) {
+ throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$
+ }
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ this.setDisplayName(propertyName);
+ getterName = createDefaultMethodName(propertyName, "is"); //$NON-NLS-1$
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ } else {
+ getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ }
+ }
+ setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+ if (hasMethod(beanClass, setterName)) {
+ setWriteMethod(beanClass, setterName);
+ }
+ if (getter == null && setter == null) {
+ throw new IntrospectionException(Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
+ }
+ }
+
+ public void setWriteMethod(Method setter) throws IntrospectionException {
+ if (setter != null) {
+ int modifiers = setter.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.05")); //$NON-NLS-1$
+ }
+ Class<?>[] parameterTypes = setter.getParameterTypes();
+ if (parameterTypes.length != 1) {
+ throw new IntrospectionException(Messages.getString("beans.06")); //$NON-NLS-1$
+ }
+ Class<?> parameterType = parameterTypes[0];
+ Class<?> propertyType = getPropertyType();
+ if (propertyType != null && !propertyType.equals(parameterType)) {
+ throw new IntrospectionException(Messages.getString("beans.07")); //$NON-NLS-1$
+ }
+ }
+ this.setter = setter;
+ }
+
+ public void setReadMethod(Method getter) throws IntrospectionException {
+ if (getter != null) {
+ int modifiers = getter.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.0A")); //$NON-NLS-1$
+ }
+ Class<?>[] parameterTypes = getter.getParameterTypes();
+ if (parameterTypes.length != 0) {
+ throw new IntrospectionException(Messages.getString("beans.08")); //$NON-NLS-1$
+ }
+ Class<?> returnType = getter.getReturnType();
+ if (returnType.equals(Void.TYPE)) {
+ throw new IntrospectionException(Messages.getString("beans.33")); //$NON-NLS-1$
+ }
+ Class<?> propertyType = getPropertyType();
+ if ((propertyType != null) && !returnType.equals(propertyType)) {
+ throw new IntrospectionException(Messages.getString("beans.09")); //$NON-NLS-1$
+ }
+ }
+ this.getter = getter;
+ }
+
+ public Method getWriteMethod() {
+ return setter;
+ }
+
+ public Method getReadMethod() {
+ return getter;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean result = (object != null && object instanceof PropertyDescriptor);
+ if (result) {
+ PropertyDescriptor pd = (PropertyDescriptor) object;
+ boolean gettersAreEqual = (this.getter == null) && (pd.getReadMethod() == null)
+ || (this.getter != null) && (this.getter.equals(pd.getReadMethod()));
+ boolean settersAreEqual = (this.setter == null) && (pd.getWriteMethod() == null)
+ || (this.setter != null) && (this.setter.equals(pd.getWriteMethod()));
+ boolean propertyTypesAreEqual = this.getPropertyType() == pd.getPropertyType();
+ boolean propertyEditorClassesAreEqual = this.getPropertyEditorClass() == pd
+ .getPropertyEditorClass();
+ boolean boundPropertyAreEqual = this.isBound() == pd.isBound();
+ boolean constrainedPropertyAreEqual = this.isConstrained() == pd.isConstrained();
+ result = gettersAreEqual && settersAreEqual && propertyTypesAreEqual
+ && propertyEditorClassesAreEqual && boundPropertyAreEqual
+ && constrainedPropertyAreEqual;
+ }
+ return result;
+ }
+
+ public void setPropertyEditorClass(Class<?> propertyEditorClass) {
+ this.propertyEditorClass = propertyEditorClass;
+ }
+
+ public Class<?> getPropertyType() {
+ Class<?> result = null;
+ if (getter != null) {
+ result = getter.getReturnType();
+ } else if (setter != null) {
+ Class<?>[] parameterTypes = setter.getParameterTypes();
+ result = parameterTypes[0];
+ }
+ return result;
+ }
+
+ public Class<?> getPropertyEditorClass() {
+ return propertyEditorClass;
+ }
+
+ public void setConstrained(boolean constrained) {
+ this.constrained = constrained;
+ }
+
+ public void setBound(boolean bound) {
+ this.bound = bound;
+ }
+
+ public boolean isConstrained() {
+ return constrained;
+ }
+
+ public boolean isBound() {
+ return bound;
+ }
+
+ boolean hasMethod(Class<?> beanClass, String methodName) {
+ Method[] methods = findMethods(beanClass, methodName);
+ return (methods.length > 0);
+ }
+
+ String createDefaultMethodName(String propertyName, String prefix) {
+ String result = null;
+ if (propertyName != null) {
+ String bos = propertyName.substring(0, 1).toUpperCase();
+ String eos = propertyName.substring(1, propertyName.length());
+ result = prefix + bos + eos;
+ }
+ return result;
+ }
+
+ Method[] findMethods(Class<?> aClass, String methodName) {
+ Method[] allMethods = aClass.getMethods();
+ Vector<Method> matchedMethods = new Vector<Method>();
+ Method[] result;
+ for (Method method : allMethods) {
+ if (method.getName().equals(methodName)) {
+ matchedMethods.add(method);
+ }
+ }
+ result = new Method[matchedMethods.size()];
+ for (int j = 0; j < matchedMethods.size(); ++j) {
+ result[j] = matchedMethods.elementAt(j);
+ }
+ return result;
+ }
+
+ void setReadMethod(Class<?> beanClass, String getterName) {
+ boolean result = false;
+ Method[] getters = findMethods(beanClass, getterName);
+ for (Method element : getters) {
+ try {
+ setReadMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {
+ }
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ void setWriteMethod(Class<?> beanClass, String setterName) throws IntrospectionException {
+ boolean result = false;
+ Method[] setters = findMethods(beanClass, setterName);
+ for (Method element : setters) {
+ try {
+ setWriteMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {
+ }
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ public PropertyEditor createPropertyEditor(Object bean) {
+ PropertyEditor editor;
+ if (propertyEditorClass == null) {
+ return null;
+ }
+ if (!PropertyEditor.class.isAssignableFrom(propertyEditorClass)) {
+ // beans.48=Property editor is not assignable from the
+ // PropertyEditor interface
+ throw new ClassCastException(Messages.getString("beans.48")); //$NON-NLS-1$
+ }
+ try {
+ Constructor<?> constr;
+ try {
+ // try to look for the constructor with single Object argument
+ constr = propertyEditorClass.getConstructor(Object.class);
+ editor = (PropertyEditor) constr.newInstance(bean);
+ } catch (NoSuchMethodException e) {
+ // try no-argument constructor
+ constr = propertyEditorClass.getConstructor();
+ editor = (PropertyEditor) constr.newInstance();
+ }
+ } catch (Exception e) {
+ // beans.47=Unable to instantiate property editor
+ RuntimeException re = new RuntimeException(Messages.getString("beans.47"), e); //$NON-NLS-1$
+ throw re;
+ }
+ return editor;
+ }
+}
diff --git a/awt/java/beans/PropertyEditor.java b/awt/java/beans/PropertyEditor.java
new file mode 100644
index 0000000..65bedea
--- /dev/null
+++ b/awt/java/beans/PropertyEditor.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+public interface PropertyEditor {
+
+ public void paintValue(Graphics gfx, Rectangle box);
+
+ public void setAsText(String text) throws IllegalArgumentException;
+
+ public String[] getTags();
+
+ public String getJavaInitializationString();
+
+ public String getAsText();
+
+ public void setValue(Object value);
+
+ public Object getValue();
+
+ public void removePropertyChangeListener(PropertyChangeListener listener);
+
+ public void addPropertyChangeListener(PropertyChangeListener listener);
+
+ public Component getCustomEditor();
+
+ public boolean supportsCustomEditor();
+
+ public boolean isPaintable();
+}
diff --git a/awt/java/beans/PropertyEditorManager.java b/awt/java/beans/PropertyEditorManager.java
new file mode 100644
index 0000000..ed55829
--- /dev/null
+++ b/awt/java/beans/PropertyEditorManager.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class PropertyEditorManager {
+
+ private static String[] path = { "org.apache.harmony.beans.editors" }; //$NON-NLS-1$
+
+ private static final Map<Class<?>, Class<?>> registeredEditors = new HashMap<Class<?>, Class<?>>();
+
+ public PropertyEditorManager() {
+ }
+
+ public static void registerEditor(Class<?> targetType, Class<?> editorClass) {
+ if (targetType == null) {
+ throw new NullPointerException();
+ }
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPropertiesAccess();
+ }
+ if (editorClass != null) {
+ registeredEditors.put(targetType, editorClass);
+ } else {
+ registeredEditors.remove(targetType);
+ }
+ }
+
+ public static synchronized PropertyEditor findEditor(Class<?> targetType) {
+ if (targetType == null) {
+ throw new NullPointerException();
+ }
+
+ Class<?> editorClass = null;
+ PropertyEditor editor = null;
+
+ editorClass = registeredEditors.get(targetType);
+
+ if (editorClass == null) {
+ String editorClassName = targetType.getName() + "Editor"; //$NON-NLS-1$
+ ClassLoader loader = targetType.getClassLoader();
+
+ if (loader == null) {
+ loader = Thread.currentThread().getContextClassLoader();
+ }
+
+ try {
+ editorClass = Class.forName(editorClassName, true, loader);
+ } catch (ClassNotFoundException cnfe) {
+ String shortEditorClassName = editorClassName
+ .substring(editorClassName.lastIndexOf(".") + 1); //$NON-NLS-1$
+
+ if (targetType.isPrimitive()) {
+ shortEditorClassName = shortEditorClassName.substring(0, 1)
+ .toUpperCase()
+ + shortEditorClassName.substring(1);
+ }
+
+ for (String element : path) {
+ editorClassName = element + "." + shortEditorClassName; //$NON-NLS-1$
+
+ try {
+ editorClass = Class.forName(editorClassName, true,
+ loader);
+ break;
+ } catch (Exception e) {
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ if (editorClass != null) {
+ try {
+ editor = (PropertyEditor) editorClass.newInstance();
+ } catch (Exception e) {
+ }
+ }
+
+ return editor;
+ }
+
+ public static synchronized void setEditorSearchPath(String[] apath) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPropertiesAccess();
+ }
+
+ path = apath;
+ }
+
+ public static synchronized String[] getEditorSearchPath() {
+ return path;
+ }
+}
diff --git a/awt/java/beans/PropertyEditorSupport.java b/awt/java/beans/PropertyEditorSupport.java
new file mode 100644
index 0000000..c3929a1
--- /dev/null
+++ b/awt/java/beans/PropertyEditorSupport.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyEditorSupport implements PropertyEditor {
+
+ Object source = null;
+
+ List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
+
+ Object oldValue = null;
+
+ Object newValue = null;
+
+ public PropertyEditorSupport(Object source) {
+ if (source == null) {
+ throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$
+ }
+ this.source = source;
+ }
+
+ public PropertyEditorSupport() {
+ source = this;
+ }
+
+ public void paintValue(Graphics gfx, Rectangle box) {
+ }
+
+ public void setAsText(String text) throws IllegalArgumentException {
+ if (newValue instanceof String) {
+ setValue(text);
+ } else {
+ throw new IllegalArgumentException(text);
+ }
+ }
+
+ public String[] getTags() {
+ return null;
+ }
+
+ public String getJavaInitializationString() {
+ return "???"; //$NON-NLS-1$
+ }
+
+ public String getAsText() {
+ return newValue == null ? "null" : newValue.toString(); //$NON-NLS-1$
+ }
+
+ public void setValue(Object value) {
+ this.oldValue = this.newValue;
+ this.newValue = value;
+ firePropertyChange();
+ }
+
+ public Object getValue() {
+ return newValue;
+ }
+
+ public void setSource(Object source) {
+ if (source == null) {
+ throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$
+ }
+ this.source = source;
+ }
+
+ public Object getSource() {
+ return source;
+ }
+
+ public synchronized void removePropertyChangeListener(
+ PropertyChangeListener listener) {
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+
+ public synchronized void addPropertyChangeListener(
+ PropertyChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ public Component getCustomEditor() {
+ return null;
+ }
+
+ public boolean supportsCustomEditor() {
+ return false;
+ }
+
+ public boolean isPaintable() {
+ return false;
+ }
+
+ public void firePropertyChange() {
+ if (listeners.size() > 0) {
+ PropertyChangeEvent event = new PropertyChangeEvent(source, null,
+ oldValue, newValue);
+ Iterator<PropertyChangeListener> iterator = listeners.iterator();
+
+ while (iterator.hasNext()) {
+ PropertyChangeListener listener = iterator.next();
+ listener.propertyChange(event);
+ }
+ }
+ }
+}
diff --git a/awt/java/beans/PropertyVetoException.java b/awt/java/beans/PropertyVetoException.java
new file mode 100644
index 0000000..c7f092a
--- /dev/null
+++ b/awt/java/beans/PropertyVetoException.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+/**
+ * Indicates that a proposed property change is unacceptable.
+ */
+public class PropertyVetoException extends Exception {
+
+ private static final long serialVersionUID = 129596057694162164L;
+
+ private final PropertyChangeEvent evt;
+
+ /**
+ * <p>
+ * Constructs an instance with a message and the change event.
+ * </p>
+ *
+ * @param message
+ * A description of the veto.
+ * @param event
+ * The event that was vetoed.
+ */
+ public PropertyVetoException(String message, PropertyChangeEvent event) {
+ super(message);
+ this.evt = event;
+ }
+
+ /**
+ * <p>
+ * Gets the property change event.
+ * </p>
+ *
+ * @return An instance of {@link PropertyChangeEvent}
+ */
+ public PropertyChangeEvent getPropertyChangeEvent() {
+ return evt;
+ }
+}
diff --git a/awt/javax/imageio/IIOException.java b/awt/javax/imageio/IIOException.java
new file mode 100644
index 0000000..fbfeb42
--- /dev/null
+++ b/awt/javax/imageio/IIOException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.io.IOException;
+
+/**
+ * The IIOException class indicates errors in reading/writing operations.
+ */
+public class IIOException extends IOException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -3216210718638985251L;
+
+ /**
+ * Instantiates a new IIOException.
+ *
+ * @param message the detailed message.
+ */
+ public IIOException(String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new IIOException.
+ *
+ * @param message the detailed message.
+ * @param cause the cause of this exception.
+ */
+ public IIOException(String message, Throwable cause) {
+ super(message);
+ initCause(cause);
+ }
+}
diff --git a/awt/javax/imageio/IIOImage.java b/awt/javax/imageio/IIOImage.java
new file mode 100644
index 0000000..e17a9fc
--- /dev/null
+++ b/awt/javax/imageio/IIOImage.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.metadata.IIOMetadata;
+import java.awt.image.RenderedImage;
+import java.awt.image.Raster;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+/**
+ * The IIOImage class combines the image, image's thumbnail and image's metadata.
+ * The image can be presented as RenderedImage or Raster object.
+ */
+public class IIOImage {
+
+ /** The image of this IIOImage. */
+ protected RenderedImage image;
+
+ /** The raster of this IIOImage. */
+ protected Raster raster;
+
+ /** The list with thumbnails associated with the image. */
+ protected List<? extends BufferedImage> thumbnails;
+
+ /** The metadata associated with the image. */
+ protected IIOMetadata metadata;
+
+ /**
+ * Instantiates a new IIOImage with the specified RenderedImage,
+ * list of thumbnails and metadata.
+ *
+ * @param image the image specified by RenderedImage.
+ * @param thumbnails the list of BufferedImage objects which
+ * represent the thumbnails of the image.
+ * @param metadata the metadata of the image.
+ */
+ public IIOImage(RenderedImage image, List<? extends BufferedImage> thumbnails, IIOMetadata metadata) {
+ if (image == null) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ this.raster = null;
+ this.image = image;
+ this.thumbnails = thumbnails;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Instantiates a new IIOImage with the specified Raster, list of
+ * thumbnails and metadata.
+ *
+ * @param raster the Raster.
+ * @param thumbnails the list of BufferedImage objects which
+ * represent the thumbnails of Raster data.
+ * @param metadata the metadata.
+ */
+ public IIOImage(Raster raster, List<? extends BufferedImage> thumbnails, IIOMetadata metadata) {
+ if (raster == null) {
+ throw new IllegalArgumentException("raster should not be NULL");
+ }
+ this.image = null;
+ this.raster = raster;
+ this.thumbnails = thumbnails;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Gets the RenderedImage object or returns null if this IIOImage
+ * object is associated with a Raster.
+ *
+ * @return the RenderedImage object or null if this IIOImage
+ * object is associated with a Raster.
+ */
+ public RenderedImage getRenderedImage() {
+ return image;
+ }
+
+ /**
+ * Sets the RenderedImage to this IIOImage object.
+ *
+ * @param image the RenderedImage to be set to this IIOImage.
+ */
+ public void setRenderedImage(RenderedImage image) {
+ if (image == null) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ raster = null;
+ this.image = image;
+ }
+
+ /**
+ * Returns true if the IIOImage object associated with a Raster, or
+ * false if it's associated with a RenderedImage.
+ *
+ * @return true if the IIOImage object associated with a Raster, or
+ * false if it's associated with a RenderedImage.
+ */
+ public boolean hasRaster() {
+ return raster != null;
+ }
+
+ /**
+ * Gets the Raster object or returns null if this IIOImage object is
+ * associated with a RenderedImage.
+ *
+ * @return the Raster or null if this IIOImage object
+ * is associated with a RenderedImage.
+ */
+ public Raster getRaster() {
+ return raster;
+ }
+
+ /**
+ * Sets the Raster to the IIOImage.
+ *
+ * @param raster the new Raster to the IIOImage.
+ */
+ public void setRaster(Raster raster) {
+ if (raster == null) {
+ throw new IllegalArgumentException("raster should not be NULL");
+ }
+ image = null;
+ this.raster = raster;
+ }
+
+ /**
+ * Gets the number of thumbnails for this IIOImage.
+ *
+ * @return the number of thumbnails for this IIOImage.
+ */
+ public int getNumThumbnails() {
+ return thumbnails != null ? thumbnails.size() : 0;
+ }
+
+ /**
+ * Gets the thumbnail with the specified index in the list.
+ *
+ * @param index the index of the thumbnail in the list.
+ *
+ * @return the thumbnail with the specified index in the list.
+ */
+ public BufferedImage getThumbnail(int index) {
+ if (thumbnails != null) {
+ return thumbnails.get(index);
+ }
+ throw new IndexOutOfBoundsException("no thumbnails were set");
+ }
+
+ /**
+ * Gets the list of thumbnails.
+ *
+ * @return the list of thumbnails.
+ */
+ public List<? extends BufferedImage> getThumbnails() {
+ return thumbnails;
+ }
+
+ /**
+ * Sets the list of thumbnails images to this IIOImage object.
+ *
+ * @param thumbnails the list of BufferedImage which represent
+ * thumbnails.
+ */
+ public void setThumbnails(List<? extends BufferedImage> thumbnails) {
+ this.thumbnails = thumbnails;
+ }
+
+ /**
+ * Gets the metadata of this IIOImage.
+ *
+ * @return the metadata of this IIOImage.
+ */
+ public IIOMetadata getMetadata() {
+ return metadata;
+ }
+
+ /**
+ * Sets the metadata to this IIOImage object.
+ *
+ * @param metadata the IIOMetadata, or null.
+ */
+ public void setMetadata(IIOMetadata metadata) {
+ this.metadata = metadata;
+ }
+}
diff --git a/awt/javax/imageio/IIOParam.java b/awt/javax/imageio/IIOParam.java
new file mode 100644
index 0000000..d998b6e
--- /dev/null
+++ b/awt/javax/imageio/IIOParam.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.awt.*;
+
+/**
+ * The IIOParam abstract class is superclass for
+ * ImageReadParam and ImageWriteParam classes and provides
+ * methods and variables which they share.
+ */
+public abstract class IIOParam {
+
+ /** The source region. */
+ protected Rectangle sourceRegion;
+
+ /** The source x subsampling. */
+ protected int sourceXSubsampling = 1;
+
+ /** The source y subsampling. */
+ protected int sourceYSubsampling = 1;
+
+ /** The subsampling x offset. */
+ protected int subsamplingXOffset;
+
+ /** The subsampling y offset. */
+ protected int subsamplingYOffset;
+
+ /** The source bands. */
+ protected int[] sourceBands;
+
+ /** The destination type. */
+ protected ImageTypeSpecifier destinationType;
+
+ /** The destination offset. */
+ protected Point destinationOffset = new Point(0, 0);
+
+ /** The default controller. */
+ protected IIOParamController defaultController;
+
+ /** The controller. */
+ protected IIOParamController controller;
+
+ /**
+ * Instantiates a new IIOParam.
+ */
+ protected IIOParam() {}
+
+ /**
+ * Sets the source region as a Rectangle object.
+ *
+ * @param sourceRegion the Rectangle which specifies the source region.
+ */
+ public void setSourceRegion(Rectangle sourceRegion) {
+ if (sourceRegion != null) {
+ if (sourceRegion.x < 0) {
+ throw new IllegalArgumentException("x < 0");
+ }
+ if (sourceRegion.y < 0) {
+ throw new IllegalArgumentException("y < 0");
+ }
+ if (sourceRegion.width <= 0) {
+ throw new IllegalArgumentException("width <= 0");
+ }
+ if (sourceRegion.height <= 0) {
+ throw new IllegalArgumentException("height <= 0");
+ }
+
+ if (sourceRegion.width <= subsamplingXOffset) {
+ throw new IllegalArgumentException("width <= subsamplingXOffset");
+ }
+
+ if (sourceRegion.height <= subsamplingYOffset) {
+ throw new IllegalArgumentException("height <= subsamplingXOffset");
+ }
+ //-- clone it to avoid unexpected modifications
+ this.sourceRegion = (Rectangle) sourceRegion.clone();
+ } else {
+ this.sourceRegion = null;
+ }
+ }
+
+ /**
+ * Gets the source region.
+ *
+ * @return the source region as Rectangle.
+ */
+ public Rectangle getSourceRegion() {
+ if (sourceRegion == null) {
+ return null;
+ }
+ //-- clone it to avoid unexpected modifications
+ return (Rectangle) sourceRegion.clone();
+ }
+
+ /**
+ * Sets the source subsampling. The sourceXSubsampling and
+ * sourceYSubsampling parameters specify the number of rows
+ * and columns to advance after every source pixel.
+ *
+ * @param sourceXSubsampling the source X subsampling.
+ * @param sourceYSubsampling the source Y subsampling.
+ * @param subsamplingXOffset the subsampling X offset.
+ * @param subsamplingYOffset the subsampling Y offset.
+ */
+ public void setSourceSubsampling(int sourceXSubsampling,
+ int sourceYSubsampling,
+ int subsamplingXOffset,
+ int subsamplingYOffset) {
+
+ if (sourceXSubsampling <= 0) {
+ throw new IllegalArgumentException("sourceXSubsampling <= 0");
+ }
+ if (sourceYSubsampling <= 0) {
+ throw new IllegalArgumentException("sourceYSubsampling <= 0");
+ }
+
+ if (subsamplingXOffset <= 0 || subsamplingXOffset >= sourceXSubsampling) {
+ throw new IllegalArgumentException("subsamplingXOffset is wrong");
+ }
+
+ if (subsamplingYOffset <= 0 || subsamplingYOffset >= sourceYSubsampling) {
+ throw new IllegalArgumentException("subsamplingYOffset is wrong");
+ }
+
+ //-- does region contain pixels
+ if (sourceRegion != null) {
+ if (sourceRegion.width <= subsamplingXOffset ||
+ sourceRegion.height <= subsamplingYOffset) {
+ throw new IllegalArgumentException("there are no pixels in region");
+ }
+ }
+
+ this.sourceXSubsampling = sourceXSubsampling;
+ this.sourceYSubsampling = sourceYSubsampling;
+ this.subsamplingXOffset = subsamplingXOffset;
+ this.subsamplingYOffset = subsamplingYOffset;
+ }
+
+ /**
+ * Gets the source X subsampling - the number of source
+ * columns to advance for each pixel.
+ *
+ * @return the source X subsampling.
+ */
+ public int getSourceXSubsampling() {
+ return sourceXSubsampling;
+ }
+
+ /**
+ * Gets the source Y subsampling - the number of source
+ * rows to advance for each pixel.
+ *
+ * @return the source Y subsampling.
+ */
+ public int getSourceYSubsampling() {
+ return sourceYSubsampling;
+ }
+
+ /**
+ * Gets the horizontal offset of the subsampling grid.
+ *
+ * @return the horizontal offset of the subsampling grid.
+ */
+ public int getSubsamplingXOffset() {
+ return subsamplingXOffset;
+ }
+
+ /**
+ * Gets the vertical offset of the subsampling grid.
+ *
+ * @return the vertical offset of the subsampling grid.
+ */
+ public int getSubsamplingYOffset() {
+ return subsamplingYOffset;
+ }
+
+ /**
+ * Sets the indices of the source bands.
+ *
+ * @param sourceBands the indices of the source bands.
+ */
+ public void setSourceBands(int[] sourceBands) {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the array of source bands.
+ *
+ * @return the array of source bands.
+ */
+ public int[] getSourceBands() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Sets the specified ImageTypeSpecifier for the destination image.
+ *
+ * @param destinationType the ImageTypeSpecifier.
+ */
+ public void setDestinationType(ImageTypeSpecifier destinationType) {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the type of the destination image as an ImageTypeSpecifier. .
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public ImageTypeSpecifier getDestinationType() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Sets the offset in the destination image where
+ * the decoded pixels are placed as a result of reading,
+ * or specified an area to be written while writing operation.
+ *
+ * @param destinationOffset the destination offset.
+ */
+ public void setDestinationOffset(Point destinationOffset) {
+ if (destinationOffset == null) {
+ throw new IllegalArgumentException("destinationOffset == null!");
+ }
+
+ this.destinationOffset = (Point) destinationOffset.clone();
+ }
+
+ /**
+ * Gets the offset in the destination image for placing pixels.
+ *
+ * @return the offset in the destination image.
+ */
+ public Point getDestinationOffset() {
+ return (Point) destinationOffset.clone();
+ }
+
+ /**
+ * Sets the IIOParamController to this IIOParam object for
+ * providing settings to this IIOParam.
+ *
+ * @param controller the new IIOParamController.
+ */
+ public void setController(IIOParamController controller) {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the current IIOParamController controller
+ * for this IIOParam.
+ *
+ * @return the current IIOParamController controller
+ * for this IIOParam.
+ */
+ public IIOParamController getController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the default IIOParamController controller
+ * for this IIOParam.
+ *
+ * @return the default IIOParamController controller
+ * for this IIOParam, or null.
+ */
+ public IIOParamController getDefaultController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Returns true if IIOParamController is installed for
+ * this IIOParam.
+ *
+ * @return true if IIOParamController is installed for
+ * this IIOParam, false otherwise.
+ */
+ public boolean hasController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Activates the controller.
+ *
+ * @return true, if successful, false otherwise.
+ */
+ public boolean activateController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+}
diff --git a/awt/javax/imageio/IIOParamController.java b/awt/javax/imageio/IIOParamController.java
new file mode 100644
index 0000000..31522c1
--- /dev/null
+++ b/awt/javax/imageio/IIOParamController.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOParamController specifies an activate method that invokes the
+ * controller.
+ */
+public interface IIOParamController {
+
+ /**
+ * Activates the controller.
+ *
+ * @param param the IIOParam.
+ *
+ * @return true if the IIOParam has been modified, false otherwise.
+ */
+ boolean activate(IIOParam param);
+}
+
diff --git a/awt/javax/imageio/ImageIO.java b/awt/javax/imageio/ImageIO.java
new file mode 100644
index 0000000..d4cd1dd
--- /dev/null
+++ b/awt/javax/imageio/ImageIO.java
@@ -0,0 +1,777 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.net.URL;
+
+/**
+ * The ImageIO class provides static methods to perfom
+ * reading and writing operations using registered
+ * ImageReader and ImageWriter objects.
+ */
+public final class ImageIO {
+
+ /** The Constant registry. */
+ private static final IIORegistry registry = IIORegistry.getDefaultInstance();
+
+ /**
+ * Instantiates a new image io.
+ */
+ private ImageIO() {}
+
+
+ /**
+ * Scans for plug-ins in the class path,
+ * loads spi classes, and registers them with the IIORegistry.
+ */
+ public static void scanForPlugins() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Sets flag which indicates whether a cache file is used when
+ * creating ImageInputStreams and ImageOutputStreams or not.
+ *
+ * @param useCache the use cache flag.
+ */
+ public static void setUseCache(boolean useCache) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the flag which indicates whether a cache file is used when
+ * creating ImageInputStreams and ImageOutputStreams or not.
+ * This method returns the current value which is set by setUseCache
+ * method.
+ *
+ * @return the use cache flag.
+ */
+ public static boolean getUseCache() {
+ // TODO implement
+ return false;
+ }
+
+ /**
+ * Sets the cache directory.
+ *
+ * @param cacheDirectory the File which specifies a cache directory.
+ */
+ public static void setCacheDirectory(File cacheDirectory) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the directory where cache files are created, returned
+ * the file which is set by setCacheDirectory method, or null.
+ *
+ * @return the File object which is set by setCacheDirectory method,
+ * or null.
+ */
+ public static File getCacheDirectory() {
+ // TODO implement
+ //-- null indicates system-dep default temporary directory
+ return null;
+ }
+
+ /**
+ * Creates an ImageInputStream from the specified Object.
+ * The specified Object should obtain the input source
+ * such as File, or InputStream.
+ *
+ * @param input the input Object such as File, or InputStream.
+ *
+ * @return the ImageInputStream object, or null.
+ *
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static ImageInputStream createImageInputStream(Object input)
+ throws IOException {
+
+ if (input == null) {
+ throw new IllegalArgumentException("input source cannot be NULL");
+ }
+
+ Iterator<ImageInputStreamSpi> it = registry.getServiceProviders(ImageInputStreamSpi.class, true);
+
+ while (it.hasNext()) {
+ ImageInputStreamSpi spi = it.next();
+ if (spi.getInputClass().isInstance(input)) {
+ return spi.createInputStreamInstance(input);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates an ImageOutputStream using the specified Object.
+ * The specified Object should obtain the output source
+ * such as File, or OutputStream.
+ *
+ * @param output the output Object such as File, or OutputStream.
+ *
+ * @return the ImageOutputStream object, or null.
+ *
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static ImageOutputStream createImageOutputStream(Object output)
+ throws IOException {
+ if (output == null) {
+ throw new IllegalArgumentException("output destination cannot be NULL");
+ }
+
+ Iterator<ImageOutputStreamSpi> it = registry.getServiceProviders(ImageOutputStreamSpi.class, true);
+
+ while (it.hasNext()) {
+ ImageOutputStreamSpi spi = it.next();
+ if (spi.getOutputClass().isInstance(output)) {
+ // todo - use getUseCache and getCacheDir here
+ return spi.createOutputStreamInstance(output);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the array of format names as String which can be
+ * decoded by registered ImageReader objects.
+ *
+ * @return the array of format names.
+ */
+ public static String[] getReaderFormatNames() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the array of MIME types as String which can be
+ * decoded by registered ImageReader objects.
+ *
+ * @return the array of MIME types.
+ */
+ public static String[] getReaderMIMETypes() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the Iterator of registered ImageReader which are able to
+ * decode an imput data specified by input Object.
+ *
+ * @param input the input Object with encoded data such as
+ * ImageInputStream object.
+ *
+ * @return the Iterator of registered ImageReader.
+ */
+ public static Iterator<ImageReader> getImageReaders(Object input) {
+ if (input == null) {
+ throw new NullPointerException("input cannot be NULL");
+ }
+
+ Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+ new CanReadFilter(input), true);
+
+ return new SpiIteratorToReadersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator of registered ImageReader which are able to
+ * decode the specified format.
+ *
+ * @param formatName the format name such as "jpeg", or "gif".
+ *
+ * @return the Iterator of registered ImageReader.
+ */
+ public static Iterator<ImageReader> getImageReadersByFormatName(String formatName) {
+ if (formatName == null) {
+ throw new NullPointerException("format name cannot be NULL");
+ }
+
+ Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+ new FormatFilter(formatName), true);
+
+ return new SpiIteratorToReadersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to decode files with the specified suffix.
+ *
+ * @param fileSuffix the file suffix such as "jpg".
+ *
+ * @return the Iterator of registered ImageReaders.
+ */
+ public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix) {
+ if (fileSuffix == null) {
+ throw new NullPointerException("suffix cannot be NULL");
+ }
+ Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+ new SuffixFilter(fileSuffix), true);
+
+ return new SpiIteratorToReadersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator of registered ImageReader objects that
+ * are able to decode files with the specified MIME type.
+ *
+ * @param MIMEType the MIME type such as "image/jpeg".
+ *
+ * @return the Iterator of registered ImageReaders.
+ */
+ public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of Strings giving the names of the formats supported
+ * by registered ImageWriter objects.
+ *
+ * @return the array of format names.
+ */
+ public static String[] getWriterFormatNames() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of Strings giving the MIME types of the formats supported
+ * by registered ImageWriter objects.
+ *
+ * @return the array of MIME types.
+ */
+ public static String[] getWriterMIMETypes() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to encode the specified image format.
+ *
+ * @param formatName the image format name such as "jpeg".
+ *
+ * @return the Iterator of registered ImageWriter.
+ */
+ public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName) {
+ if (formatName == null) {
+ throw new NullPointerException("format name cannot be NULL");
+ }
+
+ Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+ new FormatFilter(formatName), true);
+
+ return new SpiIteratorToWritersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to encode the specified suffix.
+ *
+ * @param fileSuffix the file suffix such as "jpg".
+ *
+ * @return the Iterator of registered ImageWriter.
+ */
+ public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix) {
+ if (fileSuffix == null) {
+ throw new NullPointerException("suffix cannot be NULL");
+ }
+ Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+ new SuffixFilter(fileSuffix), true);
+ return new SpiIteratorToWritersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to encode the specified MIME type.
+ *
+ * @param MIMEType the MIME type such as "image/jpeg".
+ *
+ * @return the Iterator of registered ImageWriter.
+ */
+ public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an ImageWriter object which corresponds to the
+ * specified ImageReader, or returns null if the specified
+ * ImageReader is not registered.
+ *
+ * @param reader the specified ImageReader.
+ *
+ * @return the ImageWriter, or null.
+ */
+ public static ImageWriter getImageWriter(ImageReader reader) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an ImageReader object which corresponds to the
+ * specified ImageWriter, or returns null if the specified
+ * ImageWriter is not registered.
+ *
+ * @param writer the registered ImageWriter object.
+ *
+ * @return the ImageReader.
+ */
+ public static ImageReader getImageReader(ImageWriter writer) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the Iterator of ImageWriter objects which are able to
+ * encode images with the specified ImageTypeSpecifier and
+ * format.
+ *
+ * @param type the ImageTypeSpecifier, which defines layout.
+ * @param formatName the format name.
+ *
+ * @return the Iterator of ImageWriter objects.
+ */
+ public static Iterator<ImageWriter> getImageWriters(ImageTypeSpecifier type,
+ String formatName) {
+ if (type == null) {
+ throw new NullPointerException("type cannot be NULL");
+ }
+
+ if (formatName == null) {
+ throw new NullPointerException("format name cannot be NULL");
+ }
+
+ Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+ new FormatAndEncodeFilter(type, formatName), true);
+
+ return new SpiIteratorToWritersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator of registered ImageTranscoders which
+ * are able to transcode the metadata of the specified
+ * ImageReader object to a suitable object for encoding
+ * by the specified ImageWriter.
+ *
+ * @param reader the specified ImageReader.
+ * @param writer the specified ImageWriter.
+ *
+ * @return the Iterator of registered ImageTranscoders.
+ */
+ public static Iterator<ImageTranscoder> getImageTranscoders(ImageReader reader,
+ ImageWriter writer) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Reads image data from the specified File and decodes it using
+ * the appropriate registered ImageReader object.
+ * The File is wrapped in an ImageInputStream.
+ *
+ * @param input the File to be read.
+ *
+ * @return the BufferedImage decoded from the specified File, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(File input) throws IOException {
+ if (input == null) {
+ throw new IllegalArgumentException("input == null!");
+ }
+
+ ImageInputStream stream = createImageInputStream(input);
+ return read(stream);
+ }
+
+ /**
+ * Reads image data from the specified InputStream and decodes it
+ * using an appropriate registered an ImageReader object.
+ *
+ * @param input the InputStream.
+ *
+ * @return the BufferedImage decoded from the specified InputStream,
+ * or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(InputStream input) throws IOException {
+ if (input == null) {
+ throw new IllegalArgumentException("input == null!");
+ }
+
+ ImageInputStream stream = createImageInputStream(input);
+ return read(stream);
+ }
+
+ /**
+ * Reads image data from the specified URL and decodes it using
+ * the appropriate registered ImageReader object.
+ *
+ * @param input the URL to be read.
+ *
+ * @return the BufferedImage decoded from the specified URL, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(URL input) throws IOException {
+ if (input == null) {
+ throw new IllegalArgumentException("input == null!");
+ }
+
+ InputStream stream = input.openStream();
+ BufferedImage res = read(stream);
+ stream.close();
+
+ return res;
+ }
+
+ /**
+ * Reads image data from the specified ImageInputStream and decodes it
+ * using appropriate registered an ImageReader object.
+ *
+ * @param stream the ImageInputStream.
+ *
+ * @return the BufferedImage decoded from the specified ImageInputStream,
+ * or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(ImageInputStream stream) throws IOException {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+
+ Iterator<ImageReader> imageReaders = getImageReaders(stream);
+ if (!imageReaders.hasNext()) {
+ return null;
+ }
+
+ ImageReader reader = imageReaders.next();
+ reader.setInput(stream, false, true);
+ BufferedImage res = reader.read(0);
+ reader.dispose();
+
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // Stream could be already closed, proceed silently in this case
+ }
+
+ return res;
+ }
+
+ /**
+ * Writes the specified image in the specified format (using an
+ * appropriate ImageWriter) to the specified ImageOutputStream.
+ *
+ * @param im the RenderedImage.
+ * @param formatName the format name.
+ * @param output the ImageOutputStream where Image to be written.
+ *
+ * @return true, if Image is written successfully, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static boolean write(RenderedImage im,
+ String formatName,
+ ImageOutputStream output)
+ throws IOException {
+
+ if (im == null) {
+ throw new IllegalArgumentException("image cannot be NULL");
+ }
+ if (formatName == null) {
+ throw new IllegalArgumentException("format name cannot be NULL");
+ }
+ if (output == null) {
+ throw new IllegalArgumentException("output cannot be NULL");
+ }
+
+ Iterator<ImageWriter> it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), formatName);
+ if (it.hasNext()) {
+ ImageWriter writer = it.next();
+ writer.setOutput(output);
+ writer.write(im);
+ output.flush();
+ writer.dispose();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Writes the specified image in the specified format (using an
+ * appropriate ImageWriter) to the specified File.
+ *
+ * @param im the RenderedImage.
+ * @param formatName the format name.
+ * @param output the output File where Image to be written.
+ *
+ * @return true, if Image is written successfully, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static boolean write(RenderedImage im,
+ String formatName,
+ File output)
+ throws IOException {
+
+ if (output == null) {
+ throw new IllegalArgumentException("output cannot be NULL");
+ }
+
+ if (output.exists()) {
+ output.delete();
+ }
+
+ ImageOutputStream ios = createImageOutputStream(output);
+ boolean rt = write(im, formatName, ios);
+ ios.close();
+ return rt;
+ }
+
+ /**
+ * Writes the specified image in the specified format (using an
+ * appropriate ImageWriter) to the specified OutputStream.
+ *
+ * @param im the RenderedImage.
+ * @param formatName the format name.
+ * @param output the OutputStream where Image is to be written.
+ *
+ * @return true, if Image is written successfully, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static boolean write(RenderedImage im,
+ String formatName,
+ OutputStream output)
+ throws IOException {
+
+ if (output == null) {
+ throw new IllegalArgumentException("output cannot be NULL");
+ }
+
+ ImageOutputStream ios = createImageOutputStream(output);
+ boolean rt = write(im, formatName, ios);
+ ios.close();
+ return rt;
+ }
+
+
+ /**
+ * Filter to match spi by format name.
+ */
+ static class FormatFilter implements ServiceRegistry.Filter {
+
+ /** The name. */
+ private String name;
+
+ /**
+ * Instantiates a new format filter.
+ *
+ * @param name the name
+ */
+ public FormatFilter(String name) {
+ this.name = name;
+ }
+
+ public boolean filter(Object provider) {
+ ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider;
+ return Arrays.asList(spi.getFormatNames()).contains(name);
+ }
+ }
+
+ /**
+ * Filter to match spi by format name and encoding possibility.
+ */
+ static class FormatAndEncodeFilter extends FormatFilter {
+
+ /** The type. */
+ private ImageTypeSpecifier type;
+
+ /**
+ * Instantiates a new format and encode filter.
+ *
+ * @param type the type
+ * @param name the name
+ */
+ public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) {
+ super(name);
+ this.type = type;
+ }
+
+ @Override
+ public boolean filter(Object provider) {
+ ImageWriterSpi spi = (ImageWriterSpi) provider;
+ return super.filter(provider) && spi.canEncodeImage(type);
+ }
+ }
+
+ /**
+ * Filter to match spi by suffix.
+ */
+ static class SuffixFilter implements ServiceRegistry.Filter {
+
+ /** The suf. */
+ private String suf;
+
+ /**
+ * Instantiates a new suffix filter.
+ *
+ * @param suf the suf
+ */
+ public SuffixFilter(String suf) {
+ this.suf = suf;
+ }
+
+ public boolean filter(Object provider) {
+ ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider;
+ return Arrays.asList(spi.getFileSuffixes()).contains(suf);
+ }
+ }
+
+ /**
+ * Filter to match spi by decoding possibility.
+ */
+ static class CanReadFilter implements ServiceRegistry.Filter {
+
+ /** The input. */
+ private Object input;
+
+ /**
+ * Instantiates a new can read filter.
+ *
+ * @param input the input
+ */
+ public CanReadFilter(Object input) {
+ this.input = input;
+ }
+
+ public boolean filter(Object provider) {
+ ImageReaderSpi spi = (ImageReaderSpi) provider;
+ try {
+ return spi.canDecodeInput(input);
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Wraps Spi's iterator to ImageWriter iterator.
+ */
+ static class SpiIteratorToWritersIteratorWrapper implements Iterator<ImageWriter> {
+
+ /** The backend. */
+ private Iterator<ImageWriterSpi> backend;
+
+ /**
+ * Instantiates a new spi iterator to writers iterator wrapper.
+ *
+ * @param backend the backend
+ */
+ public SpiIteratorToWritersIteratorWrapper(Iterator<ImageWriterSpi> backend) {
+ this.backend = backend;
+ }
+
+ /**
+ * Next.
+ *
+ * @return the image writer
+ */
+ public ImageWriter next() {
+ try {
+ return backend.next().createWriterInstance();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Checks for next.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNext() {
+ return backend.hasNext();
+ }
+
+ /**
+ * Removes the.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()");
+ }
+ }
+
+ /**
+ * Wraps spi's iterator to ImageReader iterator.
+ */
+ static class SpiIteratorToReadersIteratorWrapper implements Iterator<ImageReader> {
+
+ /** The backend. */
+ private Iterator<ImageReaderSpi> backend;
+
+ /**
+ * Instantiates a new spi iterator to readers iterator wrapper.
+ *
+ * @param backend the backend
+ */
+ public SpiIteratorToReadersIteratorWrapper(Iterator<ImageReaderSpi> backend) {
+ this.backend = backend;
+ }
+
+ /**
+ * Next.
+ *
+ * @return the image reader
+ */
+ public ImageReader next() {
+ try {
+ return backend.next().createReaderInstance();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Checks for next.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNext() {
+ return backend.hasNext();
+ }
+
+ /**
+ * Removes the.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()");
+ }
+ }
+}
diff --git a/awt/javax/imageio/ImageReadParam.java b/awt/javax/imageio/ImageReadParam.java
new file mode 100644
index 0000000..e67ed7d
--- /dev/null
+++ b/awt/javax/imageio/ImageReadParam.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The ImageReadParam class provides information to the ImageReader about
+ * how an image is to be decoded.
+ */
+
+public class ImageReadParam extends IIOParam {
+
+ /**
+ * This flag indicates if this ImageReadParam supports setting the source
+ * rendering size.
+ */
+ protected boolean canSetSourceRenderSize;
+
+ /**
+ * The destination BufferedImage.
+ */
+ protected BufferedImage destination;
+
+ /** The destination bands. */
+ protected int[] destinationBands;
+
+ /**
+ * The minimum progressive pass.
+ */
+ protected int minProgressivePass;
+
+ /**
+ * The number of progressive passes.
+ */
+ protected int numProgressivePasses;
+
+ /** The source render size. */
+ protected Dimension sourceRenderSize;
+
+ /**
+ * Returns true if this ImageReaderParam supports rendering a
+ * source image at an arbitrary size.
+ *
+ * @return true if this ImageReaderParam supports rendering a
+ * source image at an arbitrary size, false otherwise.
+ */
+ public boolean canSetSourceRenderSize() {
+ return canSetSourceRenderSize;
+ }
+
+ /**
+ * Gets the current destination image as BufferedImage.
+ *
+ * @return the BufferedImage which represents the destination.
+ */
+ public BufferedImage getDestination() {
+ return destination;
+ }
+
+ /**
+ * Gets the indices of destination bands.
+ *
+ * @return the array of destination bands.
+ */
+ public int[] getDestinationBands() {
+ return destinationBands;
+ }
+
+ /**
+ * Gets the index of the maximum pass to be decoded.
+ * This method returns Integer.MAX_VALUE, if
+ * getSourceNumProgressivePasses() method returns value
+ * that is equal to Integer.MAX_VALUE. Otherwise
+ * this method returns
+ * getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1.
+ *
+ * @return the index of the maximum pass to be decoded.
+ */
+ public int getSourceMaxProgressivePass() {
+ if (getSourceNumProgressivePasses() == Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
+ return getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1;
+ }
+
+ /**
+ * Gets the index of the minimum progressive pass that is decoded,
+ * default is 0.
+ *
+ * @return the index of the minimum progressive pass that is decoded,
+ * default is 0.
+ */
+ public int getSourceMinProgressivePass() {
+ return minProgressivePass;
+ }
+
+ /**
+ * Gets the number of progressive passes.
+ * The default value is Integer.MAX_VALUE.
+ *
+ * @return the number of progressive passes.
+ */
+ public int getSourceNumProgressivePasses() {
+ return numProgressivePasses;
+ }
+
+ /**
+ * Gets the dimension of source image which will be rendered
+ * during decoding process.
+ *
+ * @return the source render size.
+ */
+ public Dimension getSourceRenderSize() {
+ return sourceRenderSize;
+ }
+
+ /**
+ * Sets the specified destination image.
+ * This image will be used by read, readAll, and readRaster methods,
+ * and a reference to it will be returned by those methods.
+ *
+ * @param destination the destination image.
+ */
+ public void setDestination(BufferedImage destination) {
+ this.destination = destination;
+ }
+
+ /**
+ * Sets the indices of the destination bands.
+ *
+ * @param destinationBands the indices of the destination bands.
+ */
+ public void setDestinationBands(int[] destinationBands) {
+ this.destinationBands = destinationBands;
+ }
+
+ @Override
+ public void setDestinationType(ImageTypeSpecifier destinationType) {
+ this.destinationType = destinationType;
+ }
+
+ /**
+ * Sets the source progressive passes.
+ *
+ * @param minPass the index of the minimum pass to be decoded.
+ * @param numPasses the number of passes to be decoded.
+ */
+ public void setSourceProgressivePasses(int minPass, int numPasses) {
+ minProgressivePass = minPass;
+ numProgressivePasses = numPasses;
+ }
+
+ /**
+ * Sets the dimension size of source image if an
+ * image can be rendered at an arbitrary size.
+ *
+ * @param size the size of rendered image.
+ *
+ * @throws UnsupportedOperationException the unsupported operation exception
+ */
+ public void setSourceRenderSize(Dimension size) throws UnsupportedOperationException {
+ if (!canSetSourceRenderSize) {
+ throw new UnsupportedOperationException("can't set source renderer size");
+ }
+ sourceRenderSize = size;
+ }
+}
+
diff --git a/awt/javax/imageio/ImageReader.java b/awt/javax/imageio/ImageReader.java
new file mode 100644
index 0000000..780de26
--- /dev/null
+++ b/awt/javax/imageio/ImageReader.java
@@ -0,0 +1,1100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.event.IIOReadWarningListener;
+import javax.imageio.event.IIOReadProgressListener;
+import javax.imageio.event.IIOReadUpdateListener;
+import java.util.Locale;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Set;
+import java.io.IOException;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.*;
+
+/**
+ * The ImageReader class is an abstract class for decoding images.
+ * ImageReader objects are instantiated by the service provider
+ * interface, ImageReaderSpi class, for the specific format.
+ * ImageReaderSpi class should be registered with the IIORegistry,
+ * which uses them for format recognition and presentation of available
+ * format readers and writers.
+ */
+public abstract class ImageReader {
+
+ /** The originating provider. */
+ protected ImageReaderSpi originatingProvider;
+
+ /** The input object such as ImageInputStream. */
+ protected Object input;
+
+ /** The seek forward only. */
+ protected boolean seekForwardOnly;
+
+ /**
+ * The ignore metadata flag indicates whether current input source
+ * has been marked as metadata is allowed to be ignored by setInput.
+ */
+ protected boolean ignoreMetadata;
+
+ /** The minimum index. */
+ protected int minIndex;
+
+ /** The available locales. */
+ protected Locale[] availableLocales;
+
+ /** The locale. */
+ protected Locale locale;
+
+ /** The list of warning listeners. */
+ protected List<IIOReadWarningListener> warningListeners;
+
+ /** The list of warning locales. */
+ protected List<Locale> warningLocales;
+
+ /** The list of progress listeners. */
+ protected List<IIOReadProgressListener> progressListeners;
+
+ /** The list of update listeners. */
+ protected List<IIOReadUpdateListener> updateListeners;
+
+ /**
+ * Instantiates a new ImageReader.
+ *
+ * @param originatingProvider the ImageReaderSpi which
+ * instanties this ImageReader.
+ */
+ protected ImageReader(ImageReaderSpi originatingProvider) {
+ this.originatingProvider = originatingProvider;
+ }
+
+ /**
+ * Gets the format name of this input source.
+ *
+ * @return the format name of this input source.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public String getFormatName() throws IOException {
+ return originatingProvider.getFormatNames()[0];
+ }
+
+ /**
+ * Gets the ImageReaderSpi which instantiated this ImageReader.
+ *
+ * @return the ImageReaderSpi.
+ */
+ public ImageReaderSpi getOriginatingProvider() {
+ return originatingProvider;
+ }
+
+ /**
+ * Sets the specified Object as the input source of this ImageReader.
+ *
+ * @param input the input source, it can
+ * be an ImageInputStream or other supported objects.
+ * @param seekForwardOnly indicates whether the stream must
+ * be read sequentially from its current starting point.
+ * @param ignoreMetadata parameter which indicates
+ * if metadata may be ignored during reads or not.
+ */
+ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+ if (input != null) {
+ if (!isSupported(input) && !(input instanceof ImageInputStream)) {
+ throw new IllegalArgumentException("input " + input + " is not supported");
+ }
+ }
+ this.minIndex = 0;
+ this.seekForwardOnly = seekForwardOnly;
+ this.ignoreMetadata = ignoreMetadata;
+ this.input = input;
+ }
+
+ /**
+ * Checks if is supported.
+ *
+ * @param input the input
+ *
+ * @return true, if is supported
+ */
+ private boolean isSupported(Object input) {
+ ImageReaderSpi spi = getOriginatingProvider();
+ if (null != spi) {
+ Class[] outTypes = spi.getInputTypes();
+ for (Class<?> element : outTypes) {
+ if (element.isInstance(input)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sets the specified Object as the input source of this ImageReader.
+ * Metadata is not ignored.
+ *
+ * @param input the input source, it can
+ * be an ImageInputStream or other supported objects.
+ * @param seekForwardOnly indicates whether the stream must
+ * be read sequentially from its current starting point.
+ */
+ public void setInput(Object input, boolean seekForwardOnly) {
+ setInput(input, seekForwardOnly, false);
+ }
+
+ /**
+ * Sets the specified Object as the input source of this ImageReader.
+ * Metadata is not ignored and forward seeking is not required.
+ *
+ * @param input the input source, it can
+ * be ImageInputStream or other objects.
+ */
+ public void setInput(Object input) {
+ setInput(input, false, false);
+ }
+
+ /**
+ * Gets the input source object of this ImageReader, or returns null.
+ *
+ * @return the the input source object such as ImageInputStream,
+ * or null.
+ */
+ public Object getInput() {
+ return input;
+ }
+
+ /**
+ * Checks if the input source supports only forward reading, or not.
+ *
+ * @return true, if the input source supports only forward reading,
+ * false otherwise.
+ */
+ public boolean isSeekForwardOnly() {
+ return seekForwardOnly;
+ }
+
+ /**
+ * Returns true if the current input source allows
+ * to metadata to be ignored by passing true as
+ * the ignoreMetadata argument to the setInput method.
+ *
+ * @return true, if true if the current input source allows
+ * to metadata to be ignored by passing true as
+ * the ignoreMetadata argument to the setInput method.
+ */
+ public boolean isIgnoringMetadata() {
+ return ignoreMetadata;
+ }
+
+ /**
+ * Gets the minimum valid index for reading an image, thumbnail,
+ * or image metadata.
+ *
+ * @return the minimum valid index for reading an image, thumbnail,
+ * or image metadata.
+ */
+ public int getMinIndex() {
+ return minIndex;
+ }
+
+ /**
+ * Gets the available locales.
+ *
+ * @return an array of the available locales.
+ */
+ public Locale[] getAvailableLocales() {
+ return availableLocales;
+ }
+
+ /**
+ * Sets the locale to this ImageReader.
+ *
+ * @param locale the Locale.
+ */
+ public void setLocale(Locale locale) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets the locale of this ImageReader.
+ *
+ * @return the locale of this ImageReader.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Gets the number of images available in the current input source.
+ *
+ * @param allowSearch the parameter which indicates what
+ * a search is required; if false, the reader may return -1
+ * without searching.
+ *
+ * @return the number of images.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract int getNumImages(boolean allowSearch) throws IOException;
+
+ /**
+ * Gets the width of the specified image in input source.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the width in pixels.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract int getWidth(int imageIndex) throws IOException;
+
+ /**
+ * Gets the height of the specified image in input source.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the height in pixels.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract int getHeight(int imageIndex) throws IOException;
+
+ /**
+ * Checks if the storage format of the specified image places
+ * an impediment on random pixels access or not.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true, if the storage format of the specified image places
+ * an impediment on random pixels access, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean isRandomAccessEasy(int imageIndex) throws IOException {
+ return false; //def
+ }
+
+ /**
+ * Gets the aspect ratio (width devided by height) of the image.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the aspect ratio of the image.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public float getAspectRatio(int imageIndex) throws IOException {
+ return (float) getWidth(imageIndex) / getHeight(imageIndex);
+ }
+
+ /**
+ * Gets an ImageTypeSpecifier which indicates the type of the
+ * specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the ImageTypeSpecifier.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets an Iterator of ImageTypeSpecifier objects which are associated
+ * with image types that may be used when decoding specified image.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return an Iterator of ImageTypeSpecifier objects.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException;
+
+ /**
+ * Gets the default ImageReadParam object.
+ *
+ * @return the ImageReadParam object.
+ */
+ public ImageReadParam getDefaultReadParam() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets an IIOMetadata object for this input source.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract IIOMetadata getStreamMetadata() throws IOException;
+
+ /**
+ * Gets an IIOMetadata object for this input source.
+ *
+ * @param formatName the desired metadata format to be used in the
+ * returned IIOMetadata object.
+ * @param nodeNames the node names of the document.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public IIOMetadata getStreamMetadata(String formatName, Set<String> nodeNames)
+ throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets the image metadata of the specified image in input source.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException;
+
+ /**
+ * Gets the image metadata of the specified image input source.
+ *
+ * @param imageIndex the image index.
+ * @param formatName the desired metadata format to be used in the
+ * returned IIOMetadata object.
+ * @param nodeNames the node names which can be contained in
+ * the document.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public IIOMetadata getImageMetadata(int imageIndex, String formatName,
+ Set<String> nodeNames) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Reads the specified image and returns it as a BufferedImage
+ * using the default ImageReadParam.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public BufferedImage read(int imageIndex) throws IOException {
+ return read(imageIndex, null);
+ }
+
+ /**
+ * Reads the specified image and returns it as a BufferedImage
+ * using the specified ImageReadParam.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException;
+
+ /**
+ * Reads the specified image and returns an IIOImage with this image,
+ * thumbnails, and metadata for this image, using
+ * the specified ImageReadParam.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the IIOImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Returns an Iterator of IIOImages from the input source.
+ *
+ * @param params the Iterator of ImageReadParam objects.
+ *
+ * @return the iterator of IIOImages.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public Iterator<IIOImage> readAll(Iterator<? extends ImageReadParam> params) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Checks whether or not this plug-in supports reading a Raster.
+ *
+ * @return true, if this plug-in supports reading a Raster,
+ * false otherwise.
+ */
+ public boolean canReadRaster() {
+ return false; //def
+ }
+
+ /**
+ * Reads a new Raster object which contains the raw pixel data from
+ * the image.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the Raster.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ /**
+ * Checks if the specified image has tiles or not.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true, if the specified image has tiles,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean isImageTiled(int imageIndex) throws IOException {
+ return false; //def
+ }
+
+ /**
+ * Gets the tile width in the specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the tile width.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileWidth(int imageIndex) throws IOException {
+ return getWidth(imageIndex); //def
+ }
+
+ /**
+ * Gets the tile height in the specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the tile height.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileHeight(int imageIndex) throws IOException {
+ return getHeight(imageIndex); //def
+ }
+
+ /**
+ * Gets the X coordinate of the upper left corner of the tile grid in the
+ * specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the X coordinate of the upper left corner of the tile grid.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileGridXOffset(int imageIndex) throws IOException {
+ return 0; //def
+ }
+
+ /**
+ * Gets the Y coordinate of the upper left corner of the tile grid in the
+ * specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the Y coordinate of the upper left corner of the tile grid.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileGridYOffset(int imageIndex) throws IOException {
+ return 0; //def
+ }
+
+ /**
+ * Reads the tile specified by the tileX and tileY parameters
+ * of the specified image and returns it as a BufferedImage.
+ *
+ * @param imageIndex the image index.
+ * @param tileX the X index of tile.
+ * @param tileY the Y index of tile.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Reads the tile specified by the tileX and tileY parameters
+ * of the specified image and returns it as a Raster.
+ *
+ * @param imageIndex the image index.
+ * @param tileX the X index of tile.
+ * @param tileY the Y index of tile.
+ *
+ * @return the Raster.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public Raster readTileRaster(int imageIndex, int tileX, int tileY) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Reads the specified image using the specified
+ * ImageReadParam and returns it as a RenderedImage.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the RenderedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) throws IOException {
+ return read(imageIndex, param);
+ }
+
+ /**
+ * Returns true if the image format supported by this reader
+ * supports thumbnail preview images.
+ *
+ * @return true if the image format supported by this reader
+ * supports thumbnail preview images, false otherwise.
+ */
+ public boolean readerSupportsThumbnails() {
+ return false; //def
+ }
+
+ /**
+ * Checks if the specified image has thumbnails or not.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true, if the specified image has thumbnails,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean hasThumbnails(int imageIndex) throws IOException {
+ return getNumThumbnails(imageIndex) > 0; //def
+ }
+
+ /**
+ * Gets the number of thumbnails for the specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the number of thumbnails.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getNumThumbnails(int imageIndex) throws IOException {
+ return 0; //def
+ }
+
+ /**
+ * Gets the width of the specified thumbnail for the specified image.
+ *
+ * @param imageIndex the image's index.
+ * @param thumbnailIndex the thumbnail's index.
+ *
+ * @return the thumbnail width.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException {
+ return readThumbnail(imageIndex, thumbnailIndex).getWidth(); //def
+ }
+
+ /**
+ * Gets the height of the specified thumbnail for the specified image.
+ *
+ * @param imageIndex the image's index.
+ * @param thumbnailIndex the thumbnail's index.
+ *
+ * @return the thumbnail height.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException {
+ return readThumbnail(imageIndex, thumbnailIndex).getHeight(); //def
+ }
+
+ /**
+ * Reads the thumbnail image for the specified image
+ * as a BufferedImage.
+ *
+ * @param imageIndex the image index.
+ * @param thumbnailIndex the thumbnail index.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
+ throw new UnsupportedOperationException("Unsupported"); //def
+ }
+
+ /**
+ * Requests an abort operation for current reading operation.
+ */
+ public void abort() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Checks whether or not a request to abort the current read operation
+ * has been made successfully.
+ *
+ * @return true, if the request to abort the current read operation
+ * has been made successfully, false otherwise.
+ */
+ protected boolean abortRequested() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Clears all previous abort request, and abortRequested returns false
+ * after calling this method.
+ */
+ protected void clearAbortRequest() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Adds the IIOReadWarningListener.
+ *
+ * @param listener the IIOReadWarningListener.
+ */
+ public void addIIOReadWarningListener(IIOReadWarningListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes the specified IIOReadWarningListener.
+ *
+ * @param listener the IIOReadWarningListener to be removed.
+ */
+ public void removeIIOReadWarningListener(IIOReadWarningListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes all registered IIOReadWarningListeners.
+ */
+ public void removeAllIIOReadWarningListeners() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Adds the IIOReadProgressListener.
+ *
+ * @param listener the IIOReadProgressListener.
+ */
+ public void addIIOReadProgressListener(IIOReadProgressListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes the specified IIOReadProgressListener.
+ *
+ * @param listener the IIOReadProgressListener to be removed.
+ */
+ public void removeIIOReadProgressListener(IIOReadProgressListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes registered IIOReadProgressListeners.
+ */
+ public void removeAllIIOReadProgressListeners() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Adds the IIOReadUpdateListener.
+ *
+ * @param listener the IIOReadUpdateListener.
+ */
+ public void addIIOReadUpdateListener(IIOReadUpdateListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes the specified IIOReadUpdateListener.
+ *
+ * @param listener the IIOReadUpdateListener to be removed.
+ */
+ public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes registered IIOReadUpdateListeners.
+ */
+ public void removeAllIIOReadUpdateListeners() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the start of an sequence of image reads
+ * by calling the sequenceStarted method on all registered
+ * IIOReadProgressListeners.
+ *
+ * @param minIndex the minimum index.
+ */
+ protected void processSequenceStarted(int minIndex) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the completion of an sequence of image reads
+ * by calling sequenceComplete method on all registered
+ * IIOReadProgressListeners.
+ */
+ protected void processSequenceComplete() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the start of an image read by calling the imageStarted
+ * method on all registered IIOReadProgressListeners.
+ *
+ * @param imageIndex the image index.
+ */
+ protected void processImageStarted(int imageIndex) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the current percentage of image completion by calling
+ * the imageProgress method on all registered IIOReadProgressListeners.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processImageProgress(float percentageDone) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes image completion by calling the imageComplete method
+ * on all registered IIOReadProgressListeners.
+ */
+ protected void processImageComplete() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the start of a thumbnail read by calling the
+ * thumbnailStarted method on all registered IIOReadProgressListeners.
+ *
+ * @param imageIndex the image index.
+ * @param thumbnailIndex the thumbnail index.
+ */
+ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the current percentage of thumbnail completion
+ * by calling the thumbnailProgress method on all registered
+ * IIOReadProgressListeners.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processThumbnailProgress(float percentageDone) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the completion of a thumbnail read
+ * by calling the thumbnailComplete method
+ * on all registered IIOReadProgressListeners.
+ */
+ protected void processThumbnailComplete() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes a read aborted event by calling the readAborted
+ * method on all registered IIOReadProgressListeners.
+ */
+ protected void processReadAborted() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the beginning of a progressive pass by calling
+ * the passStarted method on all registered IIOReadUpdateListeners.
+ *
+ * @param theImage the image to be updated.
+ * @param pass the current pass index.
+ * @param minPass the minimum pass index.
+ * @param maxPass the maximum pass index.
+ * @param minX the X coordinate of of the upper left pixel.
+ * @param minY the Y coordinate of of the upper left pixel.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processPassStarted(BufferedImage theImage,
+ int pass,
+ int minPass,
+ int maxPass,
+ int minX,
+ int minY,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the update of a set of samples by calling
+ * the imageUpdate method on all registered IIOReadUpdateListeners.
+ *
+ * @param theImage the image to be updated.
+ * @param minX the X coordinate of the upper left pixel.
+ * @param minY the Y coordinate of the upper left pixel.
+ * @param width the width of updated area.
+ * @param height the height of updated area.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processImageUpdate(BufferedImage theImage,
+ int minX,
+ int minY,
+ int width,
+ int height,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the end of a progressive pass by calling passComplete
+ * method of registered IIOReadUpdateListeners.
+ *
+ * @param theImage the image to be updated.
+ */
+ protected void processPassComplete(BufferedImage theImage) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the beginning of a thumbnail progressive pass
+ * by calling the thumbnailPassStarted method on all
+ * registered IIOReadUpdateListeners.
+ *
+ * @param theThumbnail the the thumbnail to be updated.
+ * @param pass the current pass index.
+ * @param minPass the minimum pass index.
+ * @param maxPass the maximum pass index.
+ * @param minX the X coordinate of the upper left pixel.
+ * @param minY the Y coordinate of the upper left pixel.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processThumbnailPassStarted(BufferedImage theThumbnail,
+ int pass,
+ int minPass,
+ int maxPass,
+ int minX,
+ int minY,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the update of a set of samples in a thumbnail
+ * image by calling the thumbnailUpdate method on all
+ * registered IIOReadUpdateListeners.
+ *
+ * @param theThumbnail the the thumbnail to be updated.
+ * @param minX the X coordinate of the upper left pixel.
+ * @param minY the Y coordinate of the upper left pixel.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processThumbnailUpdate(BufferedImage theThumbnail,
+ int minX,
+ int minY,
+ int width,
+ int height,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the end of a thumbnail progressive pass
+ * by calling the thumbnailPassComplete method
+ * on all registered IIOReadUpdateListeners.
+ *
+ * @param theThumbnail the thumbnail to be updated.
+ */
+ protected void processThumbnailPassComplete(BufferedImage theThumbnail) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes a warning message by calling warningOccurred method
+ * of registered IIOReadWarningListeners.
+ *
+ * @param warning the warning.
+ */
+ protected void processWarningOccurred(String warning) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes a warning by calling the warningOccurred method
+ * of on all registered IIOReadWarningListeners.
+ *
+ * @param baseName the base name of ResourceBundles.
+ * @param keyword the keyword to index the warning among ResourceBundles.
+ */
+ protected void processWarningOccurred(String baseName, String keyword) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Resets this ImageReader.
+ */
+ public void reset() {
+ // def
+ setInput(null, false);
+ setLocale(null);
+ removeAllIIOReadUpdateListeners();
+ removeAllIIOReadWarningListeners();
+ removeAllIIOReadProgressListeners();
+ clearAbortRequest();
+ }
+
+ /**
+ * Disposes of any resources.
+ */
+ public void dispose() {
+ // do nothing by def
+ }
+
+ /**
+ * Gets the region of source image that should be read with the
+ * specified width, height and ImageReadParam.
+ *
+ * @param param the ImageReadParam object, or null.
+ * @param srcWidth the source image's width.
+ * @param srcHeight the source image's height.
+ *
+ * @return the Rectangle of source region.
+ */
+ protected static Rectangle getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Computes the specified source region and the specified destination
+ * region with the specified the width and height of the source image,
+ * an optional destination image, and an ImageReadParam.
+ *
+ * @param param the an ImageReadParam object, or null.
+ * @param srcWidth the source image's width.
+ * @param srcHeight the source image's height.
+ * @param image the destination image.
+ * @param srcRegion the source region.
+ * @param destRegion the destination region.
+ */
+ protected static void computeRegions(ImageReadParam param,
+ int srcWidth,
+ int srcHeight,
+ BufferedImage image,
+ Rectangle srcRegion,
+ Rectangle destRegion) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Checks the validity of the source and destination band and is called
+ * when the reader knows the number of bands of the source image and
+ * the number of bands of the destination image.
+ *
+ * @param param the ImageReadParam for reading the Image.
+ * @param numSrcBands the number of bands in the source.
+ * @param numDstBands the number of bands in the destination.
+ */
+ protected static void checkReadParamBandSettings(ImageReadParam param,
+ int numSrcBands,
+ int numDstBands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets the destination image where the decoded data is written.
+ *
+ * @param param the ImageReadParam.
+ * @param imageTypes the iterator of ImageTypeSpecifier objects.
+ * @param width the width of the image being decoded.
+ * @param height the height of the image being decoded.
+ *
+ * @return the BufferedImage where decoded pixels should be written.
+ *
+ * @throws IIOException the IIOException is thrown if
+ * there is no suitable ImageTypeSpecifier.
+ */
+ protected static BufferedImage getDestination(ImageReadParam param, Iterator<ImageTypeSpecifier> imageTypes,
+ int width,
+ int height)
+ throws IIOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+}
diff --git a/awt/javax/imageio/ImageTranscoder.java b/awt/javax/imageio/ImageTranscoder.java
new file mode 100644
index 0000000..1a0de76
--- /dev/null
+++ b/awt/javax/imageio/ImageTranscoder.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.ImageTypeSpecifier;
+
+/**
+ * The ImageTranscoder interface is to be implemented by classes that
+ * perform image transcoding operations, that is, take images written
+ * in one format and write them in another format using
+ * read/write operations. Some image data can be lost in such processes.
+ * The ImageTranscoder interface converts metadata objects (IIOMetadata)
+ * of ImageReader to apropriate metadata object for ImageWriter.
+ */
+public interface ImageTranscoder {
+
+ /**
+ * Converts the specified IIOMetadata object using the specified
+ * ImageWriteParam for obtaining writer's metadata structure.
+ *
+ * @param inData the IIOMetadata.
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata, or null.
+ */
+ IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param);
+
+ /**
+ * Converts the specified IIOMetadata object using the specified
+ * ImageWriteParam for obtaining writer's metadata structure
+ * and ImageTypeSpecifier object for obtaining the layout and
+ * color information of the image for this metadata.
+ *
+ * @param inData the IIOMetadata.
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata, or null.
+ */
+ IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param);
+}
diff --git a/awt/javax/imageio/ImageTypeSpecifier.java b/awt/javax/imageio/ImageTypeSpecifier.java
new file mode 100644
index 0000000..c93f269
--- /dev/null
+++ b/awt/javax/imageio/ImageTypeSpecifier.java
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.awt.image.ColorModel;
+import java.awt.image.SampleModel;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.awt.color.ColorSpace;
+
+/**
+ * The ImageTypeSpecifier class performs conversion operations
+ * on the SampleModel and the ColorModel of an image.
+ */
+public class ImageTypeSpecifier {
+
+ /**
+ * The ColorModel of this ImageTypeSpecifier.
+ */
+ protected ColorModel colorModel;
+
+ /**
+ * The SampleModel of this ImageTypeSpecifier.
+ */
+ protected SampleModel sampleModel;
+
+ /**
+ * Instantiates a new ImageTypeSpecifier with the specified
+ * ColorModel and SampleModel objects.
+ *
+ * @param colorModel the ColorModel.
+ * @param sampleModel the SampleModel.
+ */
+ public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
+ if (colorModel == null) {
+ throw new IllegalArgumentException("color model should not be NULL");
+ }
+ if (sampleModel == null) {
+ throw new IllegalArgumentException("sample model should not be NULL");
+ }
+ if (!colorModel.isCompatibleSampleModel(sampleModel)) {
+ throw new IllegalArgumentException("color and sample models are not compatible");
+ }
+
+ this.colorModel = colorModel;
+ this.sampleModel = sampleModel;
+ }
+
+ /**
+ * Instantiates a new ImageTypeSpecifier using the specified
+ * RenderedImage.
+ *
+ * @param renderedImage the RenderedImage.
+ */
+ public ImageTypeSpecifier(RenderedImage renderedImage) {
+ if (renderedImage == null) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ this.colorModel = renderedImage.getColorModel();
+ this.sampleModel = renderedImage.getSampleModel();
+ }
+
+ /**
+ * Creates an ImageTypeSpecifier with the specified
+ * DirectColorModel and a packed SampleModel.
+ *
+ * @param colorSpace the ColorSpace.
+ * @param redMask the red mask.
+ * @param greenMask the green mask.
+ * @param blueMask the blue mask.
+ * @param alphaMask the alpha mask.
+ * @param transferType the transfer type.
+ * @param isAlphaPremultiplied the parameter indicates
+ * if the color channel is premultiplied by alpha.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createPacked(ColorSpace colorSpace,
+ int redMask,
+ int greenMask,
+ int blueMask,
+ int alphaMask,
+ int transferType,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates an ImageTypeSpecifier with specified
+ * ComponentColorModel and a PixelInterleavedSampleModel.
+ *
+ * @param colorSpace the ColorSpace.
+ * @param bandOffsets the band offsets.
+ * @param dataType the data type.
+ * @param hasAlpha the parameter indicates if alpha channel
+ * is needed.
+ * @param isAlphaPremultiplied the parameter indicates
+ * if the color channel is premultiplied by alpha.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createInterleaved(ColorSpace colorSpace,
+ int[] bandOffsets,
+ int dataType,
+ boolean hasAlpha,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+
+ /**
+ * Creates a ImageTypeSpecifier for a image with a
+ * BandedSampleModel and a ComponentColorModel.
+ *
+ * @param colorSpace the ColorSpace.
+ * @param bankIndices the bank indices.
+ * @param bandOffsets the band offsets.
+ * @param dataType the data type.
+ * @param hasAlpha the parameter indicates a presence of alpha channel.
+ * @param isAlphaPremultiplied the parameter indicates whether
+ * or not color channel is alpha premultiplied.
+ *
+ * @return the image type specifier
+ */
+ public static ImageTypeSpecifier createBanded(ColorSpace colorSpace,
+ int[] bankIndices,
+ int[] bandOffsets,
+ int dataType,
+ boolean hasAlpha,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates a ImageTypeSpecifier for a grayscale image.
+ *
+ * @param bits the number of bits per gray value.
+ * @param dataType the data type.
+ * @param isSigned a signed flag.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createGrayscale(int bits,
+ int dataType,
+ boolean isSigned) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates a ImageTypeSpecifier for a grayscale image.
+ *
+ * @param bits the number of bits per gray value.
+ * @param dataType the data type.
+ * @param isSigned a signed flag.
+ * @param isAlphaPremultiplied the parameter indicates
+ * if color channel is premultiplied by alpha, or not.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createGrayscale(int bits,
+ int dataType,
+ boolean isSigned,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates a ImageTypeSpecifier with the indexed image format.
+ *
+ * @param redLUT the red values of indecies.
+ * @param greenLUT the green values of indecies.
+ * @param blueLUT the blue values of indecies.
+ * @param alphaLUT the alpha values of indecies.
+ * @param bits the bits number for each index.
+ * @param dataType the data type.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createIndexed(byte[] redLUT,
+ byte[] greenLUT,
+ byte[] blueLUT,
+ byte[] alphaLUT,
+ int bits,
+ int dataType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates the ImageTypeSpecifier from
+ * the specified buffered image type.
+ *
+ * @param bufferedImageType the buffered image type.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates the ImageTypeSpecifier from
+ * the specified RenderedImage.
+ *
+ * @param image the RenderedImage.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
+ if (null == image) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ return new ImageTypeSpecifier(image);
+ }
+
+ /**
+ * Gets the BufferedImage type.
+ *
+ * @return the BufferedImage type.
+ */
+ public int getBufferedImageType() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the number of components.
+ *
+ * @return the number of components
+ */
+ public int getNumComponents() {
+ return colorModel.getNumComponents();
+ }
+
+ /**
+ * Gets the number of bands.
+ *
+ * @return the number of bands
+ */
+ public int getNumBands() {
+ return sampleModel.getNumBands();
+ }
+
+ /**
+ * Gets the number of bits per the specified band.
+ *
+ * @param band the index of band.
+ *
+ * @return the number of bits per the specified band.
+ */
+ public int getBitsPerBand(int band) {
+ if (band < 0 || band >= getNumBands()) {
+ throw new IllegalArgumentException();
+ }
+ return sampleModel.getSampleSize(band);
+ }
+
+ /**
+ * Gets the SampleModel associated with this ImageTypeSpecifier.
+ *
+ * @return the SampleModel associated with this ImageTypeSpecifier.
+ */
+ public SampleModel getSampleModel() {
+ return sampleModel;
+ }
+
+ /**
+ * Gets a compatible SampleModel with the specified width and height.
+ *
+ * @param width the width.
+ * @param height the height.
+ *
+ * @return the SampleModel.
+ */
+ public SampleModel getSampleModel(int width, int height) {
+ if ((long)width*height > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("width * height > Integer.MAX_VALUE");
+ }
+ return sampleModel.createCompatibleSampleModel(width, height);
+ }
+
+ /**
+ * Gets the ColorModel associated with this ImageTypeSpecifier.
+ *
+ * @return the ColorModel associated with this ImageTypeSpecifier.
+ */
+ public ColorModel getColorModel() {
+ return colorModel;
+ }
+
+ /**
+ * Creates the BufferedImage with the specified width and height
+ * and the ColorMadel and SampleModel which are specified by this
+ * ImageTypeSpecifier.
+ *
+ * @param width the width of the BufferedImage.
+ * @param height the height of the BufferedImage.
+ *
+ * @return the BufferedImage.
+ */
+ public BufferedImage createBufferedImage(int width, int height) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Compares this ImageTypeSpecifier object with the specified
+ * object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if the object is an ImageTypeSpecifier with the same
+ * data as this ImageTypeSpecifier, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ boolean rt = false;
+ if (o instanceof ImageTypeSpecifier) {
+ ImageTypeSpecifier ts = (ImageTypeSpecifier) o;
+ rt = colorModel.equals(ts.colorModel) && sampleModel.equals(ts.sampleModel);
+ }
+ return rt;
+ }
+} \ No newline at end of file
diff --git a/awt/javax/imageio/ImageWriteParam.java b/awt/javax/imageio/ImageWriteParam.java
new file mode 100644
index 0000000..d32fa59
--- /dev/null
+++ b/awt/javax/imageio/ImageWriteParam.java
@@ -0,0 +1,633 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.util.Locale;
+import java.awt.*;
+
+/**
+ * The ImageWriteParam class provides information to an ImageWriter
+ * about how an image is to be encoded.
+ */
+public class ImageWriteParam extends IIOParam {
+
+ /**
+ * The Constant MODE_DISABLED indicates that
+ * stream is not tiled, progressive, or compressed.
+ */
+ public static final int MODE_DISABLED = 0;
+
+ /**
+ * The Constant MODE_DEFAULT indicates that the stream will be tiled,
+ * progressive, or compressed according to the plug-in's default.
+ */
+ public static final int MODE_DEFAULT = 1;
+
+ /**
+ * The Constant MODE_EXPLICIT indicates that the stream will be tiled,
+ * progressive, or compressed according to current settings
+ * which are defined by set methods.
+ */
+ public static final int MODE_EXPLICIT = 2;
+
+ /**
+ * The Constant MODE_COPY_FROM_METADATA indicates that the stream
+ * will be tiled, progressive, or compressed according to
+ * stream or image metadata.
+ */
+ public static final int MODE_COPY_FROM_METADATA = 3;
+
+ /** Whether the ImageWriter can write tiles. */
+ protected boolean canWriteTiles = false;
+
+ /** The tiling mode. */
+ protected int tilingMode = MODE_COPY_FROM_METADATA;
+
+ /** The preferred tile sizes. */
+ protected Dimension[] preferredTileSizes = null;
+
+ /** The tiling set. */
+ protected boolean tilingSet = false;
+
+ /** The tile width. */
+ protected int tileWidth = 0;
+
+ /** The tile height. */
+ protected int tileHeight = 0;
+
+ /** Whether the ImageWriter can offset tiles. */
+ protected boolean canOffsetTiles = false;
+
+ /** The tile grid x offset. */
+ protected int tileGridXOffset = 0;
+
+ /** The tile grid y offset. */
+ protected int tileGridYOffset = 0;
+
+ /** Whether the ImageWriter can write in progressive mode. */
+ protected boolean canWriteProgressive = false;
+
+ /** The progressive mode. */
+ protected int progressiveMode = MODE_COPY_FROM_METADATA;
+
+ /** Whether the ImageWriter can write in compressed mode. */
+ protected boolean canWriteCompressed = false;
+
+ /** The compression mode. */
+ protected int compressionMode = MODE_COPY_FROM_METADATA;
+
+ /** The compression types. */
+ protected String[] compressionTypes = null;
+
+ /** The compression type. */
+ protected String compressionType = null;
+
+ /** The compression quality. */
+ protected float compressionQuality = 1.0f;
+
+ /** The locale. */
+ protected Locale locale = null;
+
+ /**
+ * Instantiates a new ImageWriteParam.
+ */
+ protected ImageWriteParam() {}
+
+ /**
+ * Instantiates a new ImageWriteParam with the specified Locale.
+ *
+ * @param locale the Locale.
+ */
+ public ImageWriteParam(Locale locale) {
+ this.locale = locale;
+
+ }
+
+ /**
+ * Gets the mode for writing the stream in a progressive sequence.
+ *
+ * @return the current progressive mode.
+ */
+ public int getProgressiveMode() {
+ if (canWriteProgressive()) {
+ return progressiveMode;
+ }
+ throw new UnsupportedOperationException("progressive mode is not supported");
+ }
+
+ /**
+ * Returns true if images can be written using
+ * increasing quality passes by progressive.
+ *
+ * @return true if images can be written using
+ * increasing quality passes by progressive, false otherwise.
+ */
+ public boolean canWriteProgressive() {
+ return canWriteProgressive;
+ }
+
+ /**
+ * Sets the progressive mode which defines whether the stream
+ * contains a progressive sequence of increasing quality
+ * during writing. The progressive mode should be one of
+ * the following values: MODE_DISABLED, MODE_DEFAULT, or
+ * MODE_COPY_FROM_METADATA.
+ *
+ * @param mode the new progressive mode.
+ */
+ public void setProgressiveMode(int mode) {
+ if (canWriteProgressive()) {
+ if (mode < MODE_DISABLED || mode > MODE_COPY_FROM_METADATA || mode == MODE_EXPLICIT) {
+ throw new IllegalArgumentException("mode is not supported");
+ }
+ this.progressiveMode = mode;
+ }
+ throw new UnsupportedOperationException("progressive mode is not supported");
+ }
+
+ /**
+ * Returns true if the writer can use tiles with non zero
+ * grid offsets while writing.
+ *
+ * @return true if the writer can use tiles with non zero
+ * grid offsets while writing, false otherwise.
+ */
+ public boolean canOffsetTiles() {
+ return canOffsetTiles;
+ }
+
+ /**
+ * Returns true if this writer can write images with
+ * compression.
+ *
+ * @return true, true if this writer can write images with
+ * compression, false otherwise.
+ */
+ public boolean canWriteCompressed() {
+ return canWriteCompressed;
+ }
+
+ /**
+ * Returns true if the writer can write tiles.
+ *
+ * @return true if the writer can write tiles, false otherwise.
+ */
+ public boolean canWriteTiles() {
+ return canWriteTiles;
+ }
+
+ /**
+ * Check write compressed.
+ */
+ private final void checkWriteCompressed() {
+ if (!canWriteCompressed()) {
+ throw new UnsupportedOperationException("Compression not supported.");
+ }
+ }
+
+ /**
+ * Check compression mode.
+ */
+ private final void checkCompressionMode() {
+ if (getCompressionMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+ }
+ }
+
+ /**
+ * Check compression type.
+ */
+ private final void checkCompressionType() {
+ if (getCompressionTypes() != null && getCompressionType() == null) {
+ throw new IllegalStateException("No compression type set!");
+ }
+ }
+
+ /**
+ * Gets the compression mode.
+ *
+ * @return the compression mode if it's supported.
+ */
+ public int getCompressionMode() {
+ checkWriteCompressed();
+ return compressionMode;
+ }
+
+ /**
+ * Gets the an array of supported compression types.
+ *
+ * @return the an array of supported compression types.
+ */
+ public String[] getCompressionTypes() {
+ checkWriteCompressed();
+ if (compressionTypes != null) {
+ return compressionTypes.clone();
+ }
+ return null;
+ }
+
+ /**
+ * Gets the current compression type, or returns null.
+ *
+ * @return the current compression type, or returns null
+ * if it is not set.
+ */
+ public String getCompressionType() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ return compressionType;
+ }
+
+ /**
+ * Gets a bit rate which represents an estimate of the number of bits
+ * of output data for each bit of input image data with the specified
+ * quality.
+ *
+ * @param quality the quality.
+ *
+ * @return an estimate of the bit rate, or -1.0F if there is no
+ * estimate.
+ */
+ public float getBitRate(float quality) {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ if (quality < 0 || quality > 1) {
+ throw new IllegalArgumentException("Quality out-of-bounds!");
+ }
+ return -1.0f;
+ }
+
+ /**
+ * Gets the compression quality.
+ *
+ * @return the compression quality.
+ */
+ public float getCompressionQuality() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return compressionQuality;
+ }
+
+ /**
+ * Gets the array of compression quality descriptions.
+ *
+ * @return the string array of compression quality descriptions.
+ */
+ public String[] getCompressionQualityDescriptions() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return null;
+ }
+
+ /**
+ * Gets an array of floats which decribe
+ * compression quality levels.
+ *
+ * @return the array of compression quality values.
+ */
+ public float[] getCompressionQualityValues() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return null;
+ }
+
+ /**
+ * Gets the locale of this ImageWriteParam.
+ *
+ * @return the locale of this ImageWriteParam.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Gets the current compression type using the current Locale.
+ *
+ * @return the current compression type using the current Locale.
+ */
+ public String getLocalizedCompressionTypeName() {
+ checkWriteCompressed();
+ checkCompressionMode();
+
+ String compressionType = getCompressionType();
+ if (compressionType == null) {
+ throw new IllegalStateException("No compression type set!");
+ }
+ return compressionType;
+
+ }
+
+ /**
+ * Check tiling.
+ */
+ private final void checkTiling() {
+ if (!canWriteTiles()) {
+ throw new UnsupportedOperationException("Tiling not supported!");
+ }
+ }
+
+ /**
+ * Check tiling mode.
+ */
+ private final void checkTilingMode() {
+ if (getTilingMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
+ }
+ }
+
+ /**
+ * Check tiling params.
+ */
+ private final void checkTilingParams() {
+ if (!tilingSet) {
+ throw new IllegalStateException("Tiling parameters not set!");
+ }
+ }
+
+ /**
+ * Gets the tiling mode if tiling is supported.
+ *
+ * @return the tiling mode if tiling is supported.
+ */
+ public int getTilingMode() {
+ checkTiling();
+ return tilingMode;
+ }
+
+ /**
+ * Gets an array of Dimensions giving the sizes of the tiles as
+ * they are encoded in the output file or stream.
+ *
+ * @return the preferred tile sizes.
+ */
+ public Dimension[] getPreferredTileSizes() {
+ checkTiling();
+ if (preferredTileSizes == null) {
+ return null;
+ }
+
+ Dimension[] retval = new Dimension[preferredTileSizes.length];
+ for (int i = 0; i < preferredTileSizes.length; i++) {
+ retval[i] = new Dimension(retval[i]);
+ }
+ return retval;
+ }
+
+ /**
+ * Gets the tile grid X offset for encoding.
+ *
+ * @return the tile grid X offset for encoding.
+ */
+ public int getTileGridXOffset() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileGridXOffset;
+ }
+
+ /**
+ * Gets the tile grid Y offset for encoding.
+ *
+ * @return the tile grid Y offset for encoding.
+ */
+ public int getTileGridYOffset() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileGridYOffset;
+ }
+
+ /**
+ * Gets the tile height in an image as it is written to the
+ * output stream.
+ *
+ * @return the tile height in an image as it is written to the
+ * output stream.
+ */
+ public int getTileHeight() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileHeight;
+ }
+
+ /**
+ * Gets the tile width in an image as it is written to the
+ * output stream.
+ *
+ * @return the tile width in an image as it is written to the
+ * output stream.
+ */
+ public int getTileWidth() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileWidth;
+ }
+
+ /**
+ * Checks if the current compression type has lossless
+ * compression or not.
+ *
+ * @return true, if the current compression type has lossless
+ * compression, false otherwise.
+ */
+ public boolean isCompressionLossless() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return true;
+ }
+
+ /**
+ * Removes current compression type.
+ */
+ public void unsetCompression() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ compressionType = null;
+ compressionQuality = 1;
+ }
+
+ /**
+ * Sets the compression mode to the specified value.
+ * The specified mode can be one of the predefined
+ * constants: MODE_DEFAULT, MODE_DISABLED, MODE_EXPLICIT,
+ * or MODE_COPY_FROM_METADATA.
+ *
+ * @param mode the new compression mode to be set.
+ */
+ public void setCompressionMode(int mode) {
+ checkWriteCompressed();
+ switch (mode) {
+ case MODE_EXPLICIT: {
+ compressionMode = mode;
+ unsetCompression();
+ break;
+ }
+ case MODE_COPY_FROM_METADATA:
+ case MODE_DISABLED:
+ case MODE_DEFAULT: {
+ compressionMode = mode;
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Illegal value for mode!");
+ }
+ }
+ }
+
+ /**
+ * Sets the compression quality. The value should be between 0 and 1.
+ *
+ * @param quality the new compression quality,
+ * float value between 0 and 1.
+ */
+ public void setCompressionQuality(float quality) {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ if (quality < 0 || quality > 1) {
+ throw new IllegalArgumentException("Quality out-of-bounds!");
+ }
+ compressionQuality = quality;
+ }
+
+ /**
+ * Sets the compression type. The specified string
+ * should be one of the values returned
+ * by getCompressionTypes method.
+ *
+ * @param compressionType the new compression type.
+ */
+ public void setCompressionType(String compressionType) {
+ checkWriteCompressed();
+ checkCompressionMode();
+
+ if (compressionType == null) { // Don't check anything
+ this.compressionType = null;
+ } else {
+ String[] compressionTypes = getCompressionTypes();
+ if (compressionTypes == null) {
+ throw new UnsupportedOperationException("No settable compression types");
+ }
+
+ for (int i = 0; i < compressionTypes.length; i++) {
+ if (compressionTypes[i].equals(compressionType)) {
+ this.compressionType = compressionType;
+ return;
+ }
+ }
+
+ // Compression type is not in the list.
+ throw new IllegalArgumentException("Unknown compression type!");
+ }
+ }
+
+ /**
+ * Sets the instruction that tiling should be performed for
+ * the image in the output stream with the specified parameters.
+ *
+ * @param tileWidth the tile's width.
+ * @param tileHeight the tile's height.
+ * @param tileGridXOffset the tile grid's x offset.
+ * @param tileGridYOffset the tile grid's y offset.
+ */
+ public void setTiling(int tileWidth, int tileHeight, int tileGridXOffset, int tileGridYOffset) {
+ checkTiling();
+ checkTilingMode();
+
+ if (!canOffsetTiles() && (tileGridXOffset != 0 || tileGridYOffset != 0)) {
+ throw new UnsupportedOperationException("Can't offset tiles!");
+ }
+
+ if (tileWidth <=0 || tileHeight <= 0) {
+ throw new IllegalArgumentException("tile dimensions are non-positive!");
+ }
+
+ Dimension preferredTileSizes[] = getPreferredTileSizes();
+ if (preferredTileSizes != null) {
+ for (int i = 0; i < preferredTileSizes.length; i+=2) {
+ Dimension minSize = preferredTileSizes[i];
+ Dimension maxSize = preferredTileSizes[i+1];
+ if (
+ tileWidth < minSize.width || tileWidth > maxSize.width ||
+ tileHeight < minSize.height || tileHeight > maxSize.height
+ ) {
+ throw new IllegalArgumentException("Illegal tile size!");
+ }
+ }
+ }
+
+ tilingSet = true;
+ this.tileWidth = tileWidth;
+ this.tileHeight = tileHeight;
+ this.tileGridXOffset = tileGridXOffset;
+ this.tileGridYOffset = tileGridYOffset;
+ }
+
+ /**
+ * Clears all tiling settings.
+ */
+ public void unsetTiling() {
+ checkTiling();
+ checkTilingMode();
+
+ tilingSet = false;
+ tileWidth = 0;
+ tileHeight = 0;
+ tileGridXOffset = 0;
+ tileGridYOffset = 0;
+ }
+
+ /**
+ * Sets the tiling mode. The specified mode should be one of the
+ * following values: MODE_DISABLED, MODE_DEFAULT, MODE_EXPLICIT,
+ * or MODE_COPY_FROM_METADATA.
+ *
+ * @param mode the new tiling mode.
+ */
+ public void setTilingMode(int mode) {
+ checkTiling();
+
+ switch (mode) {
+ case MODE_EXPLICIT: {
+ tilingMode = mode;
+ unsetTiling();
+ break;
+ }
+ case MODE_COPY_FROM_METADATA:
+ case MODE_DISABLED:
+ case MODE_DEFAULT: {
+ tilingMode = mode;
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Illegal value for mode!");
+ }
+ }
+ }
+}
+
diff --git a/awt/javax/imageio/ImageWriter.java b/awt/javax/imageio/ImageWriter.java
new file mode 100644
index 0000000..d6119b0
--- /dev/null
+++ b/awt/javax/imageio/ImageWriter.java
@@ -0,0 +1,951 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.imageio.event.IIOWriteProgressListener;
+import javax.imageio.event.IIOWriteWarningListener;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+
+/**
+ * The ImageWriter class is an abstract class for encoding images.
+ * ImageWriter objects are instantiated by the service provider
+ * interface, ImageWriterSpi class, for the specific format.
+ * ImageWriterSpi class should be registered with the IIORegistry,
+ * which uses them for format recognition and presentation of available
+ * format readers and writers.
+ */
+public abstract class ImageWriter implements ImageTranscoder {
+
+ /** The available locales. */
+ protected Locale[] availableLocales;
+
+ /** The locale. */
+ protected Locale locale;
+
+ /** The originating provider. */
+ protected ImageWriterSpi originatingProvider;
+
+ /** The output. */
+ protected Object output;
+
+ /** The progress listeners. */
+ protected List<IIOWriteProgressListener> progressListeners;
+
+ /** The warning listeners. */
+ protected List<IIOWriteWarningListener> warningListeners;
+
+ /** The warning locales. */
+ protected List<Locale> warningLocales;
+
+ // Indicates that abort operation is requested
+ // Abort mechanism should be thread-safe
+ /** The aborted. */
+ private boolean aborted;
+
+ /**
+ * Instantiates a new ImageWriter.
+ *
+ * @param originatingProvider the ImageWriterSpi which
+ * instanties this ImageWriter.
+ */
+ protected ImageWriter(ImageWriterSpi originatingProvider) {
+ this.originatingProvider = originatingProvider;
+ }
+
+ public abstract IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata,
+ ImageWriteParam imageWriteParam);
+
+ public abstract IIOMetadata convertImageMetadata(IIOMetadata iioMetadata,
+ ImageTypeSpecifier imageTypeSpecifier,
+ ImageWriteParam imageWriteParam);
+
+ /**
+ * Gets the ImageWriterSpi which instantiated this ImageWriter.
+ *
+ * @return the ImageWriterSpi.
+ */
+ public ImageWriterSpi getOriginatingProvider() {
+ return originatingProvider;
+ }
+
+ /**
+ * Processes the start of an image read by calling their imageStarted
+ * method of registered IIOWriteProgressListeners.
+ *
+ * @param imageIndex the image index.
+ */
+ protected void processImageStarted(int imageIndex) {
+ if (null != progressListeners) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.imageStarted(this, imageIndex);
+ }
+ }
+ }
+
+ /**
+ * Processes the current percentage of image completion by calling
+ * imageProgress method of registered IIOWriteProgressListener.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processImageProgress(float percentageDone) {
+ if (null != progressListeners) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.imageProgress(this, percentageDone);
+ }
+ }
+ }
+
+ /**
+ * Processes image completion by calling imageComplete method
+ * of registered IIOWriteProgressListeners.
+ */
+ protected void processImageComplete() {
+ if (null != progressListeners) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.imageComplete(this);
+ }
+ }
+ }
+
+ /**
+ * Processes a warning message by calling warningOccurred method
+ * of registered IIOWriteWarningListeners.
+ *
+ * @param imageIndex the image index.
+ * @param warning the warning.
+ */
+ protected void processWarningOccurred(int imageIndex, String warning) {
+ if (null == warning) {
+ throw new NullPointerException("warning message should not be NULL");
+ }
+ if (null != warningListeners) {
+ for (IIOWriteWarningListener listener : warningListeners) {
+ listener.warningOccurred(this, imageIndex, warning);
+ }
+ }
+ }
+
+ /**
+ * Processes a warning message by calling warningOccurred method
+ * of registered IIOWriteWarningListeners with string from
+ * ResourceBundle.
+ *
+ * @param imageIndex the image index.
+ * @param bundle the name of ResourceBundle.
+ * @param key the keyword.
+ */
+ protected void processWarningOccurred(int imageIndex, String bundle, String key) {
+ if (warningListeners != null) { // Don't check the parameters
+ return;
+ }
+
+ if (bundle == null) {
+ throw new IllegalArgumentException("baseName == null!");
+ }
+ if (key == null) {
+ throw new IllegalArgumentException("keyword == null!");
+ }
+
+ // Get the context class loader and try to locate the bundle with it first
+ ClassLoader contextClassloader = AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+
+ // Iterate through both listeners and locales
+ int n = warningListeners.size();
+ for (int i=0; i < n; i++) {
+ IIOWriteWarningListener listener = warningListeners.get(i);
+ Locale locale = warningLocales.get(i);
+
+ // Now try to get the resource bundle
+ ResourceBundle rb;
+ try {
+ rb = ResourceBundle.getBundle(bundle, locale, contextClassloader);
+ } catch (MissingResourceException e) {
+ try {
+ rb = ResourceBundle.getBundle(bundle, locale);
+ } catch (MissingResourceException e1) {
+ throw new IllegalArgumentException("Bundle not found!");
+ }
+ }
+
+ try {
+ String warning = rb.getString(key);
+ listener.warningOccurred(this, imageIndex, warning);
+ } catch (MissingResourceException e) {
+ throw new IllegalArgumentException("Resource is missing!");
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Resource is not a String!");
+ }
+ }
+ }
+
+ /**
+ * Sets the specified Object to the output of this ImageWriter.
+ *
+ * @param output the Object which represents destination, it can
+ * be ImageOutputStream or other objects.
+ */
+ public void setOutput(Object output) {
+ if (output != null) {
+ ImageWriterSpi spi = getOriginatingProvider();
+ if (null != spi) {
+ Class[] outTypes = spi.getOutputTypes();
+ boolean supported = false;
+ for (Class<?> element : outTypes) {
+ if (element.isInstance(output)) {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported) {
+ throw new IllegalArgumentException("output " + output + " is not supported");
+ }
+ }
+ }
+ this.output = output;
+ }
+
+ /**
+ * Writes a completed image stream that contains the specified image,
+ * default metadata, and thumbnails to the output.
+ *
+ * @param image the specified image to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred
+ * during writting.
+ */
+ public void write(IIOImage image) throws IOException {
+ write(null, image, null);
+ }
+
+ /**
+ * Writes a completed image stream that contains the specified
+ * rendered image, default metadata, and thumbnails to the output.
+ *
+ * @param image the specified RenderedImage to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred
+ * during writting.
+ */
+ public void write(RenderedImage image) throws IOException {
+ write(null, new IIOImage(image, null, null), null);
+ }
+
+ /**
+ * Writes a completed image stream that contains the specified image,
+ * metadata and thumbnails to the output.
+ *
+ * @param streamMetadata the stream metadata, or null.
+ * @param image the specified image to be written, if
+ * canWriteRaster() method returns false, then Image must contain
+ * only RenderedImage.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException - if an error occurs during writing.
+ */
+ public abstract void write(IIOMetadata streamMetadata,
+ IIOImage image, ImageWriteParam param) throws IOException;
+
+ /**
+ * Disposes of any resources.
+ */
+ public void dispose() {
+ // def impl. does nothing according to the spec.
+ }
+
+ /**
+ * Requests an abort operation for current writing operation.
+ */
+ public synchronized void abort() {
+ aborted = true;
+ }
+
+ /**
+ * Checks whether or not a request to abort the current write operation
+ * has been made successfully.
+ *
+ * @return true, if the request to abort the current write operation
+ * has been made successfully, false otherwise.
+ */
+ protected synchronized boolean abortRequested() {
+ return aborted;
+ }
+
+ /**
+ * Clears all previous abort request, and abortRequested returns false
+ * after calling this method.
+ */
+ protected synchronized void clearAbortRequest() {
+ aborted = false;
+ }
+
+ /**
+ * Adds the IIOWriteProgressListener listener.
+ *
+ * @param listener the IIOWriteProgressListener listener.
+ */
+ public void addIIOWriteProgressListener(IIOWriteProgressListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ if (progressListeners == null) {
+ progressListeners = new ArrayList<IIOWriteProgressListener>();
+ }
+
+ progressListeners.add(listener);
+ }
+
+ /**
+ * Adds the IIOWriteWarningListener.
+ *
+ * @param listener the IIOWriteWarningListener listener.
+ */
+ public void addIIOWriteWarningListener(IIOWriteWarningListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ if (warningListeners == null) {
+ warningListeners = new ArrayList<IIOWriteWarningListener>();
+ warningLocales = new ArrayList<Locale>();
+ }
+
+ warningListeners.add(listener);
+ warningLocales.add(getLocale());
+ }
+
+ /**
+ * Gets the output object that was set by setOutput method.
+ *
+ * @return the output object such as ImageOutputStream, or null if
+ * it is not set.
+ */
+ public Object getOutput() {
+ return output;
+ }
+
+ /**
+ * Check output return false.
+ *
+ * @return true, if successful
+ */
+ private final boolean checkOutputReturnFalse() {
+ if (getOutput() == null) {
+ throw new IllegalStateException("getOutput() == null!");
+ }
+ return false;
+ }
+
+ /**
+ * Unsupported operation.
+ */
+ private final void unsupportedOperation() {
+ if (getOutput() == null) {
+ throw new IllegalStateException("getOutput() == null!");
+ }
+ throw new UnsupportedOperationException("Unsupported write variant!");
+ }
+
+
+ /**
+ * Returns true if a new empty image can be inserted at
+ * the specified index.
+ *
+ * @param imageIndex the specified index of image.
+ *
+ * @return true if a new empty image can be inserted at
+ * the specified index, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canInsertEmpty(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if a new image can be inserted at the specified index.
+ *
+ * @param imageIndex the specified index of image.
+ *
+ * @return true if a new image can be inserted at the specified index,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canInsertImage(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returnes true if the image with the specified index can be removed.
+ *
+ * @param imageIndex the specified index of image.
+ *
+ * @return true if the image with the specified index can be removed,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canRemoveImage(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if metadata of the image with the specified index
+ * can be replaced.
+ *
+ * @param imageIndex the specified image index.
+ *
+ * @return true if metadata of the image with the specified index
+ * can be replaced, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canReplaceImageMetadata(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if pixels of the image with the specified index
+ * can be replaced by the replacePixels methods.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true if pixels of the image with the specified index
+ * can be replaced by the replacePixels methods, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canReplacePixels(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if the stream metadata presented in the output
+ * can be removed.
+ *
+ * @return true if the stream metadata presented in the output
+ * can be removed, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canReplaceStreamMetadata() throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if the writing of a complete image stream which
+ * contains a single image is supported with undefined pixel
+ * values and associated metadata and thumbnails to the output.
+ *
+ * @return true if the writing of a complete image stream which
+ * contains a single image is supported, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canWriteEmpty() throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if the methods which taken an IIOImageParameter
+ * can deal with a Raster source image.
+ *
+ * @return true if the methods which taken an IIOImageParameter
+ * can deal with a Raster source image, false otherwise.
+ */
+ public boolean canWriteRasters() {
+ return false;
+ }
+
+ /**
+ * Returns true if the writer can add an image to stream that
+ * already contains header information.
+ *
+ * @return if the writer can add an image to stream that
+ * already contains header information, false otherwise.
+ */
+ public boolean canWriteSequence() {
+ return false;
+ }
+
+ /**
+ * Ends the insertion of a new image.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endInsertEmpty() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Ends the repalce pixels operation.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endReplacePixels() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Ends an empty write operation.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endWriteEmpty() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Ends the sequence of write operations.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endWriteSequence() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Gets an array of available locales.
+ *
+ * @return an of array available locales.
+ */
+ public Locale[] getAvailableLocales() {
+ if (availableLocales == null) {
+ return null;
+ }
+
+ return availableLocales.clone();
+ }
+
+ /**
+ * Gets an IIOMetadata object that contains default values
+ * for encoding an image with the specified type.
+ *
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata object.
+ */
+ public abstract IIOMetadata getDefaultImageMetadata(
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param
+ );
+
+ /**
+ * Gets an IIOMetadata object that contains default values
+ * for encoding a stream of images.
+ *
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata object.
+ */
+ public abstract IIOMetadata getDefaultStreamMetadata(ImageWriteParam param);
+
+ /**
+ * Gets the current locale of this ImageWriter.
+ *
+ * @return the current locale of this ImageWriter.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Gets the default write param.
+ * Gets a new ImageWriteParam object for this ImageWriter with the
+ * current Locale.
+ *
+ * @return a new ImageWriteParam object for this ImageWriter.
+ */
+ public ImageWriteParam getDefaultWriteParam() {
+ return new ImageWriteParam(getLocale());
+ }
+
+ /**
+ * Gets the number of thumbnails suported by the format
+ * being written with supported image type, image write
+ * parameters, stream, and image metadata objects.
+ *
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the image's parameters.
+ * @param streamMetadata the stream metadata.
+ * @param imageMetadata the image metadata.
+ *
+ * @return the number of thumbnails supported
+ */
+ public int getNumThumbnailsSupported(
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param,
+ IIOMetadata streamMetadata,
+ IIOMetadata imageMetadata
+ ) {
+ return 0;
+ }
+
+ /**
+ * Gets the preferred thumbnail sizes.
+ * Gets an array of Dimensions with the sizes for thumbnail images
+ * as they are encoded in the output file or stream.
+ *
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the ImageWriteParam.
+ * @param streamMetadata the stream metadata.
+ * @param imageMetadata the image metadata.
+ *
+ * @return the preferred thumbnail sizes
+ */
+ public Dimension[] getPreferredThumbnailSizes(
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param,
+ IIOMetadata streamMetadata,
+ IIOMetadata imageMetadata
+ ) {
+ return null;
+ }
+
+ /**
+ * Prepares insertion of an empty image by requesting the insertion of
+ * a new image into an existing image stream.
+ *
+ * @param imageIndex the image index.
+ * @param imageType the image type.
+ * @param width the width of the image.
+ * @param height the height of the image.
+ * @param imageMetadata the image metadata, or null.
+ * @param thumbnails the array thumbnails for this image, or null.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareInsertEmpty(
+ int imageIndex, ImageTypeSpecifier imageType,
+ int width, int height,
+ IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails,
+ ImageWriteParam param
+ ) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Prepares the writer to call the replacePixels method for the
+ * specified region.
+ *
+ * @param imageIndex the image's index.
+ * @param region the specified region.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Prepares the writer for writing an empty image by beginning the
+ * process of writing a complete image stream that contains a single image
+ * with undefined pixel values, metadata and thumbnails,
+ * to the output.
+ *
+ * @param streamMetadata the stream metadata.
+ * @param imageType the image type.
+ * @param width the width of the image.
+ * @param height the height of the image.
+ * @param imageMetadata the image's metadata, or null.
+ * @param thumbnails the image's thumbnails, or null.
+ * @param param the image's parameters, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareWriteEmpty(
+ IIOMetadata streamMetadata, ImageTypeSpecifier imageType,
+ int width, int height,
+ IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails,
+ ImageWriteParam param
+ ) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Prepares a stream to accept calls of writeToSequence method
+ * using the metadata object.
+ *
+ * @param streamMetadata the stream metadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Processes the completion of a thumbnail read
+ * by calling their thumbnailComplete method
+ * of registered IIOWriteProgressListeners.
+ */
+ protected void processThumbnailComplete() {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.thumbnailComplete(this);
+ }
+ }
+ }
+
+ /**
+ * Processes the current percentage of thumbnail completion
+ * by calling their thumbnailProgress method of registered
+ * IIOWriteProgressListeners.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processThumbnailProgress(float percentageDone) {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.thumbnailProgress(this, percentageDone);
+ }
+ }
+ }
+
+ /**
+ * Processes the start of a thumbnail read by calling
+ * thumbnailStarted method of registered IIOWriteProgressListeners.
+ *
+ * @param imageIndex the image index.
+ * @param thumbnailIndex the thumbnail index.
+ */
+ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.thumbnailStarted(this, imageIndex, thumbnailIndex);
+ }
+ }
+ }
+
+ /**
+ * Processes that the writing has been aborted by calling writeAborted
+ * method of registered IIOWriteProgressListeners.
+ */
+ protected void processWriteAborted() {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.writeAborted(this);
+ }
+ }
+ }
+
+ /**
+ * Removes the all IIOWriteProgressListener listeners.
+ */
+ public void removeAllIIOWriteProgressListeners() {
+ progressListeners = null;
+ }
+
+ /**
+ * Removes the all IIOWriteWarningListener listeners.
+ */
+ public void removeAllIIOWriteWarningListeners() {
+ warningListeners = null;
+ warningLocales = null;
+ }
+
+ /**
+ * Removes the specified IIOWriteProgressListener listener.
+ *
+ * @param listener the registered IIOWriteProgressListener
+ * to be removed.
+ */
+ public void removeIIOWriteProgressListener(IIOWriteProgressListener listener) {
+ if (progressListeners != null && listener != null) {
+ if (progressListeners.remove(listener) && progressListeners.isEmpty()) {
+ progressListeners = null;
+ }
+ }
+ }
+
+ /**
+ * Removes the specified IIOWriteWarningListener listener.
+ *
+ * @param listener the registered IIOWriteWarningListener listener
+ * to be removed.
+ */
+ public void removeIIOWriteWarningListener(IIOWriteWarningListener listener) {
+ if (warningListeners == null || listener == null) {
+ return;
+ }
+
+ int idx = warningListeners.indexOf(listener);
+ if (idx > -1) {
+ warningListeners.remove(idx);
+ warningLocales.remove(idx);
+
+ if (warningListeners.isEmpty()) {
+ warningListeners = null;
+ warningLocales = null;
+ }
+ }
+ }
+
+ /**
+ * Removes the image with the specified index from the stream.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void removeImage(int imageIndex) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces image metadata of the image with specified index.
+ *
+ * @param imageIndex the image's index.
+ * @param imageMetadata the image metadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces a part of an image presented in the output
+ * with the specified RenderedImage.
+ *
+ * @param image the RenderedImage.
+ * @param param the ImageWriteParam.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces a part of an image presented in the output
+ * with the specified Raster.
+ *
+ * @param raster the Raster.
+ * @param param the ImageWriteParam.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replacePixels(Raster raster, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces the stream metadata of the output with new IIOMetadata.
+ *
+ * @param streamMetadata the new stream metadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Sets the locale of this ImageWriter.
+ *
+ * @param locale the new locale.
+ */
+ public void setLocale(Locale locale) {
+ if (locale == null) {
+ this.locale = null;
+ return;
+ }
+
+ Locale[] locales = getAvailableLocales();
+ boolean validLocale = false;
+ if (locales != null) {
+ for (int i = 0; i < locales.length; i++) {
+ if (locale.equals(locales[i])) {
+ validLocale = true;
+ break;
+ }
+ }
+ }
+
+ if (validLocale) {
+ this.locale = locale;
+ } else {
+ throw new IllegalArgumentException("Invalid locale!");
+ }
+ }
+
+ /**
+ * Resets this ImageWriter.
+ */
+ public void reset() {
+ setOutput(null);
+ setLocale(null);
+ removeAllIIOWriteWarningListeners();
+ removeAllIIOWriteProgressListeners();
+ clearAbortRequest();
+ }
+
+ /**
+ * Inserts image into existing output stream.
+ *
+ * @param imageIndex the image index where an image will be written.
+ * @param image the specified image to be written.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Writes the specified image to the sequence.
+ *
+ * @param image the image to be written.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred
+ * during writting.
+ */
+ public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+}
diff --git a/awt/javax/imageio/event/IIOReadProgressListener.java b/awt/javax/imageio/event/IIOReadProgressListener.java
new file mode 100644
index 0000000..3d65807
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadProgressListener.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.event;
+
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/**
+ * The IIOReadProgressListener interface notifies callers
+ * about the progress of the image and thumbnail reading methods.
+ */
+public interface IIOReadProgressListener extends EventListener {
+
+ /**
+ * Notifies this listener that the image reading has been completed.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void imageComplete(ImageReader source);
+
+ /**
+ * Notifies this listener about the degree of completion of the read call.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param percentageDone the percentage of decoding done.
+ */
+ void imageProgress(ImageReader source, float percentageDone);
+
+ /**
+ * Notifies this listener that an image read operation has been started.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param imageIndex the index of the image in an input file or
+ * stream to be read.
+ */
+ void imageStarted(ImageReader source, int imageIndex);
+
+ /**
+ * Notifies this listener that a read operation has been aborted.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void readAborted(ImageReader source);
+
+ /**
+ * Notifies this listener that a sequence of read operations has been completed.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void sequenceComplete(ImageReader source);
+
+ /**
+ * Notifies this listener that a sequence of read operation has been started.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param minIndex the index of the first image to be read.
+ */
+ void sequenceStarted(ImageReader source, int minIndex);
+
+ /**
+ * Notifies that a thumbnail read operation has been completed.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void thumbnailComplete(ImageReader source);
+
+ /**
+ * Notifies this listener about the degree of completion of the read call.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param percentageDone the percentage of decoding done.
+ */
+ void thumbnailProgress(ImageReader source, float percentageDone);
+
+ /**
+ * Notifies this listener that a thumbnail reading operation has been started.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param imageIndex the index of the image in an input file or
+ * stream to be read.
+ * @param thumbnailIndex the index of the thumbnail to be read.
+ */
+ void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex);
+}
+
diff --git a/awt/javax/imageio/event/IIOReadUpdateListener.java b/awt/javax/imageio/event/IIOReadUpdateListener.java
new file mode 100644
index 0000000..ce5e2f1
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadUpdateListener.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.event;
+
+import java.awt.image.BufferedImage;
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOReadUpdateListener interface provides functionality
+ * to receive notification of pixel updates during image and thumbnail
+ * reading operations.
+ */
+public interface IIOReadUpdateListener extends EventListener {
+
+ /**
+ * Notifies this listener that the specified area of the image has been updated.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the image to be updated.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param width the width of updated area.
+ * @param height the height of updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void imageUpdate(ImageReader source, BufferedImage theImage, int minX,
+ int minY, int width, int height, int periodX, int periodY,
+ int[] bands);
+
+ /**
+ * Notifies this listener that the current read operation has completed a
+ * progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the image to be updated.
+ */
+ void passComplete(ImageReader source, BufferedImage theImage);
+
+ /**
+ * Notifies this listener that the current read operation has begun
+ * a progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the image to be updated.
+ * @param pass the numer of the pass.
+ * @param minPass the index of the first pass that will be decoded.
+ * @param maxPass the index of the last pass that will be decoded.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void passStarted(ImageReader source, BufferedImage theImage, int pass,
+ int minPass, int maxPass, int minX, int minY, int periodX,
+ int periodY, int[] bands);
+
+ /**
+ * Notifies this listener that the current thumbnail read operation has
+ * completed a progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the thumbnail to be updated.
+ */
+ void thumbnailPassComplete(ImageReader source, BufferedImage theImage);
+
+ /**
+ * Notifies this listener that the current thumbnail read operation has
+ * begun a progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theThumbnail the thumbnail to be updated.
+ * @param pass the numer of the pass.
+ * @param minPass the index of the first pass that will be decoded.
+ * @param maxPass the index of the last pass that will be decoded.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void thumbnailPassStarted(ImageReader source, BufferedImage theThumbnail,
+ int pass, int minPass, int maxPass, int minX, int minY,
+ int periodX, int periodY, int[] bands);
+
+ /**
+ * Notifies this listener that a specified area of a thumbnail image has been
+ * updated.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theThumbnail the thumbnail to be updated.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param width the width of updated area.
+ * @param height the height of updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void thumbnailUpdate(ImageReader source, BufferedImage theThumbnail,
+ int minX, int minY, int width, int height, int periodX,
+ int periodY, int[] bands);
+}
+
diff --git a/awt/javax/imageio/event/IIOReadWarningListener.java b/awt/javax/imageio/event/IIOReadWarningListener.java
new file mode 100644
index 0000000..92fa275
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadWarningListener.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.event;
+
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOReadWarningListener provides methods to receive notification
+ * of warning messages generated by image
+ * and thumbnail reading methods.
+ */
+public interface IIOReadWarningListener extends EventListener {
+
+ /**
+ * Notifies this listener about a warning (non-fatal error) during decoding.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param warning the string describing the warning.
+ */
+ public void warningOccurred(ImageReader source, String warning);
+}
+
diff --git a/awt/javax/imageio/event/IIOWriteProgressListener.java b/awt/javax/imageio/event/IIOWriteProgressListener.java
new file mode 100644
index 0000000..19ae495
--- /dev/null
+++ b/awt/javax/imageio/event/IIOWriteProgressListener.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.event;
+
+import javax.imageio.ImageWriter;
+import java.util.EventListener;
+
+/**
+ * The IIOWriteProgressListener interface provides methods to
+ * receive notification about the progress of the image and
+ * thumbnail writing methods.
+ */
+public interface IIOWriteProgressListener extends EventListener {
+
+ /**
+ * Notifies this listener that an image write operation has been started.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param imageIndex the index of the image being written.
+ */
+ void imageStarted(ImageWriter source, int imageIndex);
+
+ /**
+ * Notifies this listener about the degree of completion of the write call.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param percentageDone the percentage of encoding done.
+ */
+ void imageProgress(ImageWriter source, float percentageDone);
+
+ /**
+ * Notifies this listener that the image writing has been completed.
+ *
+ * @param source the ImageWriter object which calls this method.
+ */
+ void imageComplete(ImageWriter source);
+
+ /**
+ * Notifies this listener that a thumbnail write operation has been started.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param imageIndex the index of the image being written.
+ * @param thumbnailIndex the index of the thumbnail being written.
+ */
+ void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex);
+
+ /**
+ * Notifies this listener about the degree of completion of the write call.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param percentageDone the percentage of encoding done.
+ */
+ void thumbnailProgress(ImageWriter source, float percentageDone);
+
+ /**
+ * Notifies this listener that a thumbnail write operation has been completed.
+ *
+ * @param source the ImageWriter object which calls this method.
+ */
+ void thumbnailComplete(ImageWriter source);
+
+ /**
+ * Notifies this listener that writing operation has been aborted.
+ *
+ * @param source the ImageWriter object which calls this method.
+ */
+ void writeAborted(ImageWriter source);
+}
diff --git a/awt/javax/imageio/event/IIOWriteWarningListener.java b/awt/javax/imageio/event/IIOWriteWarningListener.java
new file mode 100644
index 0000000..f530d25
--- /dev/null
+++ b/awt/javax/imageio/event/IIOWriteWarningListener.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.event;
+
+import javax.imageio.ImageWriter;
+import java.util.EventListener;
+
+/**
+ * The IIOWriteWarningListener provides methods to receive notification
+ * of warnings generated by image and thumbnail writing methods.
+ */
+public interface IIOWriteWarningListener extends EventListener {
+
+ /**
+ * Notifies this listener about a warning (non-fatal error) during encoding.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param imageIndex the index of the image generating the warning.
+ * @param warning the string describing the warning.
+ */
+ void warningOccurred(ImageWriter source, int imageIndex, String warning);
+}
diff --git a/awt/javax/imageio/metadata/IIOInvalidTreeException.java b/awt/javax/imageio/metadata/IIOInvalidTreeException.java
new file mode 100644
index 0000000..8690b2b
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOInvalidTreeException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import org.w3c.dom.Node;
+import javax.imageio.IIOException;
+
+/**
+ * The IIOInvalidTreeException provides notification about
+ * fails of IIOMetadataNodes tree parsing by IIOMetadata object.
+ */
+public class IIOInvalidTreeException extends IIOException {
+
+ /** The offending node. */
+ protected Node offendingNode = null;
+
+ /**
+ * Instantiates an IIOInvalidTreeException with the
+ * specified detailed message and specified offending
+ * Node.
+ *
+ * @param message the detailed message.
+ * @param offendingNode the offending node.
+ */
+ public IIOInvalidTreeException(String message, Node offendingNode) {
+ super(message);
+ this.offendingNode = offendingNode;
+ }
+
+ /**
+ * Instantiates a new IIOInvalidTreeException with the
+ * specified detailed message and specified offending
+ * Node.
+ *
+ * @param message the detailed message.
+ * @param cause the cause of this exception.
+ * @param offendingNode the offending node
+ */
+ public IIOInvalidTreeException(String message, Throwable cause, Node offendingNode) {
+ super(message, cause);
+ this.offendingNode = offendingNode;
+ }
+
+ /**
+ * Gets the offending node.
+ *
+ * @return the offending node.
+ */
+ public Node getOffendingNode() {
+ return offendingNode;
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadata.java b/awt/javax/imageio/metadata/IIOMetadata.java
new file mode 100644
index 0000000..f2387cc
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadata.java
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package javax.imageio.metadata;
+
+import java.util.ArrayList;
+
+import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils;
+import org.w3c.dom.Node;
+
+/**
+ * The Class IIOMetadata represents the metadata (bundled with an image)
+ * as a Dom-type tree.
+ */
+public abstract class IIOMetadata {
+
+ /** Whether the standard metadata format is supported. */
+ protected boolean standardFormatSupported;
+
+ /** The native metadata format name. */
+ protected String nativeMetadataFormatName;
+
+ /** The native metadata format class name. */
+ protected String nativeMetadataFormatClassName;
+
+ /** The extra metadata format names. */
+ protected String[] extraMetadataFormatNames;
+
+ /** The extra metadata format class names. */
+ protected String[] extraMetadataFormatClassNames;
+
+ /** The default controller. */
+ protected IIOMetadataController defaultController;
+
+ /** The controller. */
+ protected IIOMetadataController controller;
+
+ /**
+ * Instantiates a new IIOMetadata with no data set.
+ */
+ protected IIOMetadata() {}
+
+ /**
+ * Instantiates a new IIOMetadata with the specified data parameters.
+ *
+ * @param standardMetadataFormatSupported whether the standard metadata format is supported
+ * @param nativeMetadataFormatName the native metadata format name
+ * @param nativeMetadataFormatClassName the native metadata format class name
+ * @param extraMetadataFormatNames the extra metadata format names
+ * @param extraMetadataFormatClassNames the extra metadata format class names
+ */
+ protected IIOMetadata(boolean standardMetadataFormatSupported,
+ String nativeMetadataFormatName,
+ String nativeMetadataFormatClassName,
+ String[] extraMetadataFormatNames,
+ String[] extraMetadataFormatClassNames) {
+ standardFormatSupported = standardMetadataFormatSupported;
+ this.nativeMetadataFormatName = nativeMetadataFormatName;
+ this.nativeMetadataFormatClassName = nativeMetadataFormatClassName;
+ if (extraMetadataFormatNames == null) {
+ if (extraMetadataFormatClassNames != null) {
+ throw new IllegalArgumentException(
+ "extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!"
+ );
+ }
+ } else {
+ if (extraMetadataFormatClassNames == null) {
+ throw new IllegalArgumentException(
+ "extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!"
+ );
+ }
+ if (extraMetadataFormatNames.length == 0) {
+ throw new IllegalArgumentException("extraMetadataFormatNames.length == 0!");
+ }
+ if (extraMetadataFormatClassNames.length != extraMetadataFormatNames.length) {
+ throw new IllegalArgumentException(
+ "extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!"
+ );
+ }
+ this.extraMetadataFormatNames = extraMetadataFormatNames.clone();
+ this.extraMetadataFormatClassNames = extraMetadataFormatClassNames.clone();
+ }
+ }
+
+ /**
+ * Gets the metadata as tree-type document.
+ *
+ * @param formatName the format name
+ *
+ * @return the node in tree format
+ */
+ public abstract Node getAsTree(String formatName);
+
+ /**
+ * Checks if the metadata is read only.
+ *
+ * @return true, if the metadata is read only.
+ */
+ public abstract boolean isReadOnly();
+
+ /**
+ * Merges the specified tree with this metadata tree.
+ *
+ * @param formatName the format of the specified tree
+ * @param root the root node of the metadata tree
+ *
+ * @throws IIOInvalidTreeException if the specified tree
+ * is incompatible with the this metadata tree.
+ */
+ public abstract void mergeTree(String formatName, Node root) throws IIOInvalidTreeException;
+
+ /**
+ * Resets the controller.
+ */
+ public abstract void reset();
+
+ /**
+ * Gets the controller associated with this metadata document.
+ *
+ * @return the controller
+ */
+ public IIOMetadataController getController() {
+ return controller;
+ }
+
+ /**
+ * Checks whether this metadata has a controller.
+ *
+ * @return true, if this metadata has a controller
+ */
+ public boolean hasController() {
+ return getController() != null;
+ }
+
+ /**
+ * Activate the controller.
+ *
+ * @return true, if successful
+ */
+ public boolean activateController() {
+ if (!hasController()) {
+ throw new IllegalStateException("hasController() == false!");
+ }
+ return getController().activate(this);
+ }
+
+ /**
+ * Gets the default controller.
+ *
+ * @return the default controller
+ */
+ public IIOMetadataController getDefaultController() {
+ return defaultController;
+ }
+
+ /**
+ * Gets the extra metadata format names.
+ *
+ * @return the extra metadata format names
+ */
+ public String[] getExtraMetadataFormatNames() {
+ return extraMetadataFormatNames == null ? null : extraMetadataFormatNames.clone();
+ }
+
+ /**
+ * Gets the metadata format.
+ *
+ * @param formatName the format name
+ *
+ * @return the metadata format
+ */
+ public IIOMetadataFormat getMetadataFormat(String formatName) {
+ return IIOMetadataUtils.instantiateMetadataFormat(
+ formatName,
+ standardFormatSupported,
+ nativeMetadataFormatName, nativeMetadataFormatClassName,
+ extraMetadataFormatNames, extraMetadataFormatClassNames
+ );
+ }
+
+ /**
+ * Gets the native metadata format name.
+ *
+ * @return the native metadata format name
+ */
+ public String getNativeMetadataFormatName() {
+ return nativeMetadataFormatName;
+ }
+
+ /**
+ * Checks if the standard metadata format is supported.
+ *
+ * @return true, if the standard metadata format is supported
+ */
+ public boolean isStandardMetadataFormatSupported() {
+ return standardFormatSupported;
+ }
+
+ /**
+ * Gets the metadata format names.
+ *
+ * @return the metadata format names
+ */
+ public String[] getMetadataFormatNames() {
+ ArrayList<String> res = new ArrayList<String>();
+
+ String nativeMetadataFormatName = getNativeMetadataFormatName();
+ boolean standardFormatSupported = isStandardMetadataFormatSupported();
+ String extraMetadataFormatNames[] = getExtraMetadataFormatNames();
+
+ if (standardFormatSupported) {
+ res.add(IIOMetadataFormatImpl.standardMetadataFormatName);
+ }
+ if (nativeMetadataFormatName != null) {
+ res.add(nativeMetadataFormatName);
+ }
+ if (extraMetadataFormatNames != null) {
+ for (String extraMetadataFormatName : extraMetadataFormatNames) {
+ res.add(extraMetadataFormatName);
+ }
+ }
+
+ return res.size() > 0 ? res.toArray(new String[0]) : null;
+ }
+
+ /**
+ * Gets the standard chroma node.
+ *
+ * @return the standard chroma node
+ */
+ protected IIOMetadataNode getStandardChromaNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard compression node.
+ *
+ * @return the standard compression node
+ */
+ protected IIOMetadataNode getStandardCompressionNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard data node.
+ *
+ * @return the standard data node
+ */
+ protected IIOMetadataNode getStandardDataNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard dimension node.
+ *
+ * @return the standard dimension node
+ */
+ protected IIOMetadataNode getStandardDimensionNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard document node.
+ *
+ * @return the standard document node
+ */
+ protected IIOMetadataNode getStandardDocumentNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard text node.
+ *
+ * @return the standard text node
+ */
+ protected IIOMetadataNode getStandardTextNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard tile node.
+ *
+ * @return the standard tile node
+ */
+ protected IIOMetadataNode getStandardTileNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard transparency node.
+ *
+ * @return the standard transparency node
+ */
+ protected IIOMetadataNode getStandardTransparencyNode() {
+ return null;
+ }
+
+ /**
+ * Gets the metadata as a tree in standard format.
+ *
+ * @return the metadata as a tree in standard format
+ */
+ protected final IIOMetadataNode getStandardTree() {
+ // Create root node
+ IIOMetadataNode root = new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName);
+
+ Node node;
+ if ((node = getStandardChromaNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardCompressionNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardDataNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardDimensionNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardDocumentNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardTextNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardTileNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardTransparencyNode()) != null) {
+ root.appendChild(node);
+ }
+
+ return root;
+ }
+
+ /**
+ * Sets the controller.
+ *
+ * @param controller the new controller
+ */
+ public void setController(IIOMetadataController controller) {
+ this.controller = controller;
+ }
+
+ /**
+ * Sets the from tree.
+ *
+ * @param formatName the name of the metatdata format of the from tree
+ * @param root the root node of the from tree
+ *
+ * @throws IIOInvalidTreeException if the tree or its format is not compatible with
+ * this metadata.
+ */
+ public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException {
+ reset();
+ mergeTree(formatName, root);
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataController.java b/awt/javax/imageio/metadata/IIOMetadataController.java
new file mode 100644
index 0000000..dfd4e5c
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataController.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.metadata;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOMetadataController interface provides a method for
+ * implementing objects to activate the controller without
+ * defining how the controller obtains values.
+ */
+public interface IIOMetadataController {
+
+ /**
+ * Activates a controller.
+ *
+ * @param metadata the metadata to be modified.
+ *
+ * @return true if the IIOMetadata has been modified,
+ * false otherwise.
+ */
+ public boolean activate(IIOMetadata metadata);
+}
+
diff --git a/awt/javax/imageio/metadata/IIOMetadataFormat.java b/awt/javax/imageio/metadata/IIOMetadataFormat.java
new file mode 100644
index 0000000..9e246b4
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataFormat.java
@@ -0,0 +1,347 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.Locale;
+
+/**
+ * The Interface IIOMetadataFormat is implemented by classes that
+ * describe the rules and allowed elements for a metadata document
+ * tree.
+ */
+public interface IIOMetadataFormat {
+
+ /** The CHILD_POLICY_EMPTY. */
+ int CHILD_POLICY_EMPTY = 0;
+
+ /** The CHILD_POLICY_ALL. */
+ int CHILD_POLICY_ALL = 1;
+
+ /** The CHILD_POLICY_SOME. */
+ int CHILD_POLICY_SOME = 2;
+
+ /** The CHILD_POLICY_CHOICE. */
+ int CHILD_POLICY_CHOICE = 3;
+
+ /** The CHILD_POLICY_SEQUENCE. */
+ int CHILD_POLICY_SEQUENCE = 4;
+
+ /** The CHILD_POLICY_REPEAT. */
+ int CHILD_POLICY_REPEAT = 5;
+
+ /** The maximum value for the child policy. */
+ int CHILD_POLICY_MAX = CHILD_POLICY_REPEAT;
+
+ /** The DATATYPE_STRING. */
+ int DATATYPE_STRING = 0;
+
+ /** The DATATYPE_BOOLEAN. */
+ int DATATYPE_BOOLEAN = 1;
+
+ /** The DATATYPE_INTEGER. */
+ int DATATYPE_INTEGER = 2;
+
+ /** The DATATYPE_FLOAT. */
+ int DATATYPE_FLOAT = 3;
+
+ /** The DATATYPE_DOUBLE. */
+ int DATATYPE_DOUBLE = 4;
+
+ /** The VALUE_NONE. */
+ int VALUE_NONE = 0;
+
+ /** The VALUE_ARBITRARY. */
+ int VALUE_ARBITRARY = 1;
+
+ /** The VALUE_RANGE. */
+ int VALUE_RANGE = 2;
+
+ /** The VALUE_RANGE_MIN_INCLUSIVE_MASK. */
+ int VALUE_RANGE_MIN_INCLUSIVE_MASK = 4;
+
+ /** The VALUE_RANGE_MAX_INCLUSIVE_MASK. */
+ int VALUE_RANGE_MAX_INCLUSIVE_MASK = 8;
+
+ /** The VALUE_ENUMERATION. */
+ int VALUE_ENUMERATION = 16;
+
+ /** The VALUE_LIST. */
+ int VALUE_LIST = 32;
+
+ /** The VALUE_RANGE_MIN_INCLUSIVE. */
+ int VALUE_RANGE_MIN_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK;
+
+ /** The VALUE_RANGE_MAX_INCLUSIVE. */
+ int VALUE_RANGE_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MAX_INCLUSIVE_MASK;
+
+ /** The VALUE_RANGE_MIN_MAX_INCLUSIVE. */
+ int VALUE_RANGE_MIN_MAX_INCLUSIVE =
+ VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK | VALUE_RANGE_MAX_INCLUSIVE_MASK;
+
+ /**
+ * Tells whether the specified element is allowed for the specified
+ * image type.
+ *
+ * @param elementName the element name
+ * @param imageType the image type
+ *
+ * @return true, if the specified element is allowed for the specified
+ * image type
+ */
+ boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
+
+ /**
+ * Gets data type of the specified attribute of the specified element.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute's data type
+ */
+ int getAttributeDataType(String elementName, String attrName);
+
+ /**
+ * Gets the default value of the specified attribute of the specified element.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute's default value
+ */
+ String getAttributeDefaultValue(String elementName, String attrName);
+
+ /**
+ * Gets the user-friendly description of the attribute.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ * @param locale the locale giving the desired language for the
+ * description
+ *
+ * @return the attribute description
+ */
+ String getAttributeDescription(String elementName, String attrName, Locale locale);
+
+ /**
+ * Gets the attribute enumerations.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute enumerations
+ */
+ String[] getAttributeEnumerations(String elementName, String attrName);
+
+ /**
+ * Gets the maximum length of the attribute list.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the maximum length of the attribute list
+ */
+ int getAttributeListMaxLength(String elementName, String attrName);
+
+ /**
+ * Gets the minimum length of the attribute list.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the minimum length of the attribute list
+ */
+ int getAttributeListMinLength(String elementName, String attrName);
+
+ /**
+ * Gets the maximum value allowed for the attribute.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the maximum value allowed for the attribute
+ */
+ String getAttributeMaxValue(String elementName, String attrName);
+
+ /**
+ * Gets the minimum value allowed for the attribute.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the minimum value allowed for the attribute
+ */
+ String getAttributeMinValue(String elementName, String attrName);
+
+ /**
+ * Gets the attribute names allowed for the specified element.
+ *
+ * @param elementName the element name
+ *
+ * @return the attribute names
+ */
+ String[] getAttributeNames(String elementName);
+
+ /**
+ * Gets the attribute value type.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute value type
+ */
+ int getAttributeValueType(String elementName, String attrName);
+
+ /**
+ * Checks whether the specified attribute is required
+ * for the specified element.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return true, if the specified attribute is required for the
+ * specified element
+ */
+ boolean isAttributeRequired(String elementName, String attrName);
+
+ /**
+ * Gets the names of the possible child elements for the given element.
+ *
+ * @param elementName the element name
+ *
+ * @return the child names
+ */
+ String[] getChildNames(String elementName);
+
+ /**
+ * Gets the constant describing the element's child policy.
+ *
+ * @param elementName the element name
+ *
+ * @return the child policy
+ */
+ int getChildPolicy(String elementName);
+
+ /**
+ * Gets the user-friendly description of the element.
+ *
+ * @param elementName the element name
+ * @param locale the locale giving the desired language for the
+ * description
+ *
+ * @return the element description
+ */
+ String getElementDescription(String elementName, Locale locale);
+
+ /**
+ * Gets the maximum number of children allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the maximum number of children allowed for the element
+ */
+ int getElementMaxChildren(String elementName);
+
+ /**
+ * Gets the minimum number of children allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the minimum number of children allowed for the element
+ */
+ int getElementMinChildren(String elementName);
+
+ /**
+ * Gets the maximum object array length allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the maximum object array length allowed for the element
+ */
+ int getObjectArrayMaxLength(String elementName);
+
+ /**
+ * Gets the minimum object array length allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the minimum object array length allowed for the element
+ */
+ int getObjectArrayMinLength(String elementName);
+
+ /**
+ * Gets the object class corresponding to the specified element.
+ *
+ * @param elementName the element name
+ *
+ * @return the object class corresponding to the specified element
+ */
+ Class<?> getObjectClass(String elementName);
+
+ /**
+ * Gets the object default value for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the object default value for the element
+ */
+ Object getObjectDefaultValue(String elementName);
+
+ /**
+ * Gets the object enumerations.
+ *
+ * @param elementName the element name
+ *
+ * @return the object enumerations
+ */
+ Object[] getObjectEnumerations(String elementName);
+
+ /**
+ * Gets the maximum value allowed for the element's object.
+ *
+ * @param elementName the element name
+ *
+ * @return the maximum value allowed for the element's object
+ */
+ Comparable<?> getObjectMaxValue(String elementName);
+
+ /**
+ * Gets the minimum value allowed for the element's object.
+ *
+ * @param elementName the element name
+ *
+ * @return the minimum value allowed for the element's object
+ */
+ Comparable<?> getObjectMinValue(String elementName);
+
+ /**
+ * Gets the constant that indicates the type of the element's value.
+ *
+ * @param elementName the element name
+ *
+ * @return the constant that indicates the type of the element's value
+ */
+ int getObjectValueType(String elementName);
+
+ /**
+ * Gets the name of the root element.
+ *
+ * @return the name of the root element
+ */
+ String getRootName();
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
new file mode 100644
index 0000000..438ae90
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
@@ -0,0 +1,939 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The IIOMetadataFormatImpl class provides an implementation of the
+ * IIOMetadataFormat interface.
+ */
+public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat {
+
+ /** The Constant standardMetadataFormatName. */
+ @SuppressWarnings({"ConstantDeclaredInAbstractClass"})
+ public static final String standardMetadataFormatName = "javax_imageio_1.0";
+
+ /** The standard format. */
+ @SuppressWarnings({"StaticNonFinalField"})
+ private static IIOMetadataFormatImpl standardFormat;
+
+ /** The root name. */
+ private String rootName;
+
+ /** The element hash. */
+ private HashMap<String, Element> elementHash = new HashMap<String, Element>();
+
+ /** The resource base name. */
+ private String resourceBaseName = getClass().getName() + "Resources";
+
+ /**
+ * Instantiates an IIOMetadataFormatImpl with the specified root
+ * name and child policy (not CHILD_POLICY_REPEAT).
+ *
+ * @param rootName the name of root element.
+ * @param childPolicy the child policy defined by one of the
+ * CHILD_POLICY_* constants (except CHILD_POLICY_REPEAT).
+ */
+ public IIOMetadataFormatImpl(String rootName, int childPolicy) {
+ if (rootName == null) {
+ throw new IllegalArgumentException("rootName is null");
+ }
+ if (
+ childPolicy < CHILD_POLICY_EMPTY ||
+ childPolicy > CHILD_POLICY_MAX ||
+ childPolicy == CHILD_POLICY_REPEAT
+ ) {
+ throw new IllegalArgumentException("childPolicy is not one of the predefined constants");
+ }
+
+ this.rootName = rootName;
+ Element root = new Element();
+ root.name = rootName;
+ root.childPolicy = childPolicy;
+ elementHash.put(rootName, root);
+ }
+
+ /**
+ * Instantiates an IIOMetadataFormatImpl with the specified root
+ * name and CHILD_POLICY_REPEAT child policy.
+ *
+ * @param rootName the name of root element.
+ * @param minChildren the minimum number of children.
+ * @param maxChildren the maximum number of children
+ */
+ public IIOMetadataFormatImpl(String rootName, int minChildren, int maxChildren) {
+ if (rootName == null) {
+ throw new IllegalArgumentException("rootName is null");
+ }
+ if (minChildren < 0) {
+ throw new IllegalArgumentException("minChildren < 0!");
+ }
+ if (minChildren > maxChildren) {
+ throw new IllegalArgumentException("minChildren > maxChildren!");
+ }
+
+ this.rootName = rootName;
+ Element root = new Element();
+ root.name = rootName;
+ root.minChildren = minChildren;
+ root.maxChildren = maxChildren;
+ root.childPolicy = CHILD_POLICY_REPEAT;
+ elementHash.put(rootName, root);
+ }
+
+ @SuppressWarnings({"AbstractMethodOverridesAbstractMethod"})
+ public abstract boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param listMinLength the minimum legal number of list items.
+ * @param listMaxLength the the maximum legal number of list items.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, int listMinLength, int listMaxLength
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+ if (listMinLength < 0 || listMinLength > listMaxLength) {
+ throw new IllegalArgumentException("Invalid list bounds!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.listMinLength = listMinLength;
+ attr.listMaxLength = listMaxLength;
+ attr.valueType = VALUE_LIST;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param defaultValue the default value of the attribute.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, String defaultValue
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.defaultValue = defaultValue;
+ attr.valueType = VALUE_ARBITRARY;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param defaultValue the default value of the attribute.
+ * @param enumeratedValues the legal values for the attribute as
+ * a list of strings.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, String defaultValue, List<String> enumeratedValues
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+ if (enumeratedValues == null || enumeratedValues.isEmpty()) {
+ throw new IllegalArgumentException("enumeratedValues is empty or null");
+ }
+
+ try {
+ for (String enumeratedValue : enumeratedValues) {
+ if (enumeratedValue == null) {
+ throw new IllegalArgumentException("enumeratedValues contains a null!");
+ }
+ }
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("enumeratedValues contains a non-String value!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.defaultValue = defaultValue;
+ attr.enumeratedValues = enumeratedValues;
+ attr.valueType = VALUE_ENUMERATION;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param defaultValue the default value of attribute.
+ * @param minValue the minimum legal value of an attribute.
+ * @param maxValue the maximum legal value of an attribute.
+ * @param minInclusive the flag which indicates
+ * whether the minValue is inclusive.
+ * @param maxInclusive the flag which indicates
+ * whether the maxValue is inclusive.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, String defaultValue,
+ String minValue, String maxValue,
+ boolean minInclusive, boolean maxInclusive
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.defaultValue = defaultValue;
+ attr.minValue = minValue;
+ attr.maxValue = maxValue;
+ attr.minInclusive = minInclusive;
+ attr.maxInclusive = maxInclusive;
+
+ attr.valueType = VALUE_RANGE;
+ attr.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0;
+ attr.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute with boolean data type to an existing
+ * element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param hasDefaultValue the flag which indicates whether this attribute
+ * must have a default value.
+ * @param defaultValue the default value.
+ */
+ protected void addBooleanAttribute(
+ String elementName, String attrName,
+ boolean hasDefaultValue, boolean defaultValue
+ ) {
+ String defaultVal = hasDefaultValue ? (defaultValue ? "TRUE" : "FALSE") : null;
+ ArrayList<String> values = new ArrayList<String>(2);
+ values.add("TRUE");
+ values.add("FALSE");
+
+ addAttribute(elementName, attrName, DATATYPE_BOOLEAN, true, defaultVal, values);
+ }
+
+ /**
+ * Adds an existing element to the list of child elements
+ * of the specified parent element.
+ *
+ * @param elementName the name of the element to be added.
+ * @param parentName the parent element name.
+ */
+ protected void addChildElement(String elementName, String parentName) {
+ Element parent = findElement(parentName);
+ Element element = findElement(elementName);
+ parent.children.add(element.name);
+ }
+
+ /**
+ * Adds a new element type to this IIOMetadataFormat with
+ * a child policy (if policy is not CHILD_POLICY_REPEAT).
+ *
+ * @param elementName the name of the element to be added.
+ * @param parentName the parent element name.
+ * @param childPolicy one of the CHILD_POLICY_* constants defined
+ * by IIOMetadataFormat.
+ */
+ protected void addElement(String elementName, String parentName, int childPolicy) {
+ if (
+ childPolicy < CHILD_POLICY_EMPTY ||
+ childPolicy > CHILD_POLICY_MAX ||
+ childPolicy == CHILD_POLICY_REPEAT
+ ) {
+ throw new IllegalArgumentException("childPolicy is not one of the predefined constants");
+ }
+
+ Element parent = findElement(parentName);
+ Element element = new Element();
+ element.name = elementName;
+ element.childPolicy = childPolicy;
+ elementHash.put(elementName, element);
+ parent.children.add(elementName);
+ }
+
+ /**
+ * Adds a new element type to this IIOMetadataFormat with
+ * CHILD_POLICY_REPEAT and the specified minimum and maximum
+ * number of child elements.
+ *
+ * @param elementName the element name to be added.
+ * @param parentName the parent element name.
+ * @param minChildren the minimum number of child elements.
+ * @param maxChildren the maximum number of child elements.
+ */
+ protected void addElement(
+ String elementName, String parentName,
+ int minChildren, int maxChildren
+ ) {
+ if (minChildren < 0) {
+ throw new IllegalArgumentException("minChildren < 0!");
+ }
+ if (minChildren > maxChildren) {
+ throw new IllegalArgumentException("minChildren > maxChildren!");
+ }
+
+ Element parent = findElement(parentName);
+ Element element = new Element();
+ element.name = elementName;
+ element.childPolicy = CHILD_POLICY_REPEAT;
+ element.minChildren = minChildren;
+ element.maxChildren = maxChildren;
+ elementHash.put(elementName, element);
+ parent.children.add(elementName);
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object's value.
+ * @param arrayMinLength the minimum legal length for the array.
+ * @param arrayMaxLength the maximum legal length for the array.
+ */
+ protected void addObjectValue(
+ String elementName, Class<?> classType,
+ int arrayMinLength, int arrayMaxLength
+ ) {
+ Element element = findElement(elementName);
+
+ ObjectValue objVal = new ObjectValue();
+ objVal.classType = classType;
+ objVal.arrayMaxLength = arrayMaxLength;
+ objVal.arrayMinLength = arrayMinLength;
+ objVal.valueType = VALUE_LIST;
+
+ element.objectValue = objVal;
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as an element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object's value.
+ * @param required a flag indicated that this object value
+ * must be present.
+ * @param defaultValue the default value, or null.
+ */
+ protected <T> void addObjectValue(
+ String elementName, Class<T> classType,
+ boolean required, T defaultValue
+ ) {
+ // note: reqired is an unused parameter
+ Element element = findElement(elementName);
+
+ ObjectValue<T> objVal = new ObjectValue<T>();
+ objVal.classType = classType;
+ objVal.defaultValue = defaultValue;
+ objVal.valueType = VALUE_ARBITRARY;
+
+ element.objectValue = objVal;
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as the element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object value.
+ * @param required a flag indicated that this object value
+ * must be present.
+ * @param defaultValue the default value, or null.
+ * @param enumeratedValues the list of legal values for the object.
+ */
+ protected <T> void addObjectValue(
+ String elementName, Class<T> classType,
+ boolean required, T defaultValue,
+ List<? extends T> enumeratedValues
+ ) {
+ // note: reqired is an unused parameter
+ if (enumeratedValues == null || enumeratedValues.isEmpty()) {
+ throw new IllegalArgumentException("enumeratedValues is empty or null");
+ }
+
+ try {
+ for (T enumeratedValue : enumeratedValues) {
+ if (enumeratedValue == null) {
+ throw new IllegalArgumentException("enumeratedValues contains a null!");
+ }
+ }
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!");
+ }
+
+ Element element = findElement(elementName);
+
+ ObjectValue<T> objVal = new ObjectValue<T>();
+ objVal.classType = classType;
+ objVal.defaultValue = defaultValue;
+ objVal.enumeratedValues = enumeratedValues;
+ objVal.valueType = VALUE_ENUMERATION;
+
+ element.objectValue = objVal;
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as the element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object value.
+ * @param defaultValue the default value, or null.
+ * @param minValue the minimum legal value for the object value.
+ * @param maxValue the maximum legal value for the object value.
+ * @param minInclusive the flag which indicates
+ * whether the minValue is inclusive.
+ * @param maxInclusive the flag which indicates
+ * whether the maxValue is inclusive.
+ */
+ protected <T extends Object & Comparable<? super T>> void addObjectValue(
+ String elementName, Class<T> classType,
+ T defaultValue, Comparable<? super T> minValue, Comparable<? super T> maxValue,
+ boolean minInclusive, boolean maxInclusive
+ ) {
+ Element element = findElement(elementName);
+
+ ObjectValue<T> objVal = new ObjectValue<T>();
+ objVal.classType = classType;
+ objVal.defaultValue = defaultValue;
+ objVal.minValue = minValue;
+ objVal.maxValue = maxValue;
+ objVal.minInclusive = minInclusive;
+ objVal.maxInclusive = maxInclusive;
+
+ objVal.valueType = VALUE_RANGE;
+ objVal.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0;
+ objVal.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0;
+
+ element.objectValue = objVal;
+ }
+
+ public int getAttributeDataType(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ return attr.dataType;
+ }
+
+ public String getAttributeDefaultValue(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ return attr.defaultValue;
+ }
+
+ public String getAttributeDescription(String elementName, String attrName, Locale locale) {
+ findAttribute(elementName, attrName);
+ return getResourceString(elementName + "/" + attrName, locale);
+ }
+
+ public String[] getAttributeEnumerations(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if (attr.valueType != VALUE_ENUMERATION) {
+ throw new IllegalArgumentException("Attribute is not an enumeration!");
+ }
+
+ return attr.enumeratedValues.toArray(new String[attr.enumeratedValues.size()]);
+ }
+
+ public int getAttributeListMaxLength(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if (attr.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Attribute is not a list!");
+ }
+ return attr.listMaxLength;
+ }
+
+ public int getAttributeListMinLength(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if (attr.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Attribute is not a list!");
+ }
+ return attr.listMinLength;
+ }
+
+ public String getAttributeMaxValue(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if ((attr.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Attribute is not a range!");
+ }
+ return attr.maxValue;
+ }
+
+ public String getAttributeMinValue(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if ((attr.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Attribute is not a range!");
+ }
+ return attr.minValue;
+ }
+
+ public String[] getAttributeNames(String elementName) {
+ Element element = findElement(elementName);
+ return element.attributes.keySet().toArray(new String[element.attributes.size()]);
+ }
+
+ public int getAttributeValueType(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ return attr.valueType;
+ }
+
+ public String[] getChildNames(String elementName) {
+ Element element = findElement(elementName);
+ if (element.childPolicy == CHILD_POLICY_EMPTY) { // Element cannot have children
+ return null;
+ }
+ return element.children.toArray(new String[element.children.size()]);
+ }
+
+ public int getChildPolicy(String elementName) {
+ Element element = findElement(elementName);
+ return element.childPolicy;
+ }
+
+ public String getElementDescription(String elementName, Locale locale) {
+ findElement(elementName); // Check if there is such element
+ return getResourceString(elementName, locale);
+ }
+
+ public int getElementMaxChildren(String elementName) {
+ Element element = findElement(elementName);
+ if (element.childPolicy != CHILD_POLICY_REPEAT) {
+ throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!");
+ }
+ return element.maxChildren;
+ }
+
+ public int getElementMinChildren(String elementName) {
+ Element element = findElement(elementName);
+ if (element.childPolicy != CHILD_POLICY_REPEAT) {
+ throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!");
+ }
+ return element.minChildren;
+ }
+
+ public int getObjectArrayMaxLength(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || v.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Not a list!");
+ }
+ return v.arrayMaxLength;
+ }
+
+ public int getObjectArrayMinLength(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || v.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Not a list!");
+ }
+ return v.arrayMinLength;
+ }
+
+ public Class<?> getObjectClass(String elementName) {
+ ObjectValue v = findObjectValue(elementName);
+ return v.classType;
+ }
+
+ public Object getObjectDefaultValue(String elementName) {
+ ObjectValue v = findObjectValue(elementName);
+ return v.defaultValue;
+ }
+
+ public Object[] getObjectEnumerations(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || v.valueType != VALUE_ENUMERATION) {
+ throw new IllegalArgumentException("Not an enumeration!");
+ }
+ return v.enumeratedValues.toArray();
+ }
+
+ public Comparable<?> getObjectMaxValue(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || (v.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Not a range!");
+ }
+ return v.maxValue;
+ }
+
+ public Comparable<?> getObjectMinValue(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || (v.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Not a range!");
+ }
+ return v.minValue;
+ }
+
+ public int getObjectValueType(String elementName) {
+ Element element = findElement(elementName);
+ if (element.objectValue == null) {
+ return VALUE_NONE;
+ }
+ return element.objectValue.valueType;
+ }
+
+ /**
+ * Gets the resource base name for locating ResourceBundles.
+ *
+ * @return the current resource base name.
+ */
+ protected String getResourceBaseName() {
+ return resourceBaseName;
+ }
+
+ public String getRootName() {
+ return rootName;
+ }
+
+ /**
+ * Gets the standard format instance.
+ *
+ * @return the IIOMetadataFormat instance.
+ */
+ public static IIOMetadataFormat getStandardFormatInstance() {
+ if (standardFormat == null) {
+ standardFormat = new IIOStandardMetadataFormat();
+ }
+
+ return standardFormat;
+ }
+
+ public boolean isAttributeRequired(String elementName, String attrName) {
+ return findAttribute(elementName, attrName).required;
+ }
+
+ /**
+ * Removes the specified attribute from the specified element.
+ *
+ * @param elementName the specified element name.
+ * @param attrName the specified attribute name.
+ */
+ protected void removeAttribute(String elementName, String attrName) {
+ Element element = findElement(elementName);
+ element.attributes.remove(attrName);
+ }
+
+ /**
+ * Removes the specified element from this format.
+ *
+ * @param elementName the specified element name.
+ */
+ protected void removeElement(String elementName) {
+ Element element;
+ if ((element = elementHash.get(elementName)) != null) {
+ elementHash.remove(elementName);
+ for (Element e : elementHash.values()) {
+ e.children.remove(element.name);
+ }
+ }
+ }
+
+ /**
+ * Removes the object value from the specified element.
+ *
+ * @param elementName the element name.
+ */
+ protected void removeObjectValue(String elementName) {
+ Element element = findElement(elementName);
+ element.objectValue = null;
+ }
+
+ /**
+ * Sets a new base name for ResourceBundles containing
+ * descriptions of elements and attributes for this format.
+ *
+ * @param resourceBaseName the new resource base name.
+ */
+ protected void setResourceBaseName(String resourceBaseName) {
+ if (resourceBaseName == null) {
+ throw new IllegalArgumentException("resourceBaseName == null!");
+ }
+ this.resourceBaseName = resourceBaseName;
+ }
+
+ /**
+ * The Class Element.
+ */
+ @SuppressWarnings({"ClassWithoutConstructor"})
+ private class Element {
+
+ /** The name. */
+ String name;
+
+ /** The children. */
+ ArrayList<String> children = new ArrayList<String>();
+
+ /** The attributes. */
+ HashMap<String, Attlist> attributes = new HashMap<String, Attlist>();
+
+ /** The min children. */
+ int minChildren;
+
+ /** The max children. */
+ int maxChildren;
+
+ /** The child policy. */
+ int childPolicy;
+
+ /** The object value. */
+ ObjectValue objectValue;
+ }
+
+ /**
+ * The Class Attlist.
+ */
+ @SuppressWarnings({"ClassWithoutConstructor"})
+ private class Attlist {
+
+ /** The name. */
+ String name;
+
+ /** The data type. */
+ int dataType;
+
+ /** The required. */
+ boolean required;
+
+ /** The list min length. */
+ int listMinLength;
+
+ /** The list max length. */
+ int listMaxLength;
+
+ /** The default value. */
+ String defaultValue;
+
+ /** The enumerated values. */
+ List<String> enumeratedValues;
+
+ /** The min value. */
+ String minValue;
+
+ /** The max value. */
+ String maxValue;
+
+ /** The min inclusive. */
+ boolean minInclusive;
+
+ /** The max inclusive. */
+ boolean maxInclusive;
+
+ /** The value type. */
+ int valueType;
+ }
+
+ /**
+ * The Class ObjectValue.
+ */
+ @SuppressWarnings({"ClassWithoutConstructor"})
+ private class ObjectValue<T> {
+
+ /** The class type. */
+ Class<T> classType;
+
+ /** The array min length. */
+ int arrayMinLength;
+
+ /** The array max length. */
+ int arrayMaxLength;
+
+ /** The default value. */
+ T defaultValue;
+
+ /** The enumerated values. */
+ List<? extends T> enumeratedValues;
+
+ /** The min value. */
+ Comparable<? super T> minValue;
+
+ /** The max value. */
+ Comparable<? super T> maxValue;
+
+ /** The min inclusive. */
+ boolean minInclusive;
+
+ /** The max inclusive. */
+ boolean maxInclusive;
+
+ /** The value type. */
+ int valueType;
+ }
+
+ /**
+ * Find element.
+ *
+ * @param name the name
+ *
+ * @return the element
+ */
+ private Element findElement(String name) {
+ Element element;
+ if ((element = elementHash.get(name)) == null) {
+ throw new IllegalArgumentException("element name is null or no such element: " + name);
+ }
+
+ return element;
+ }
+
+ /**
+ * Find attribute.
+ *
+ * @param elementName the element name
+ * @param attributeName the attribute name
+ *
+ * @return the attlist
+ */
+ private Attlist findAttribute(String elementName, String attributeName) {
+ Element element = findElement(elementName);
+ Attlist attribute;
+ if ((attribute = element.attributes.get(attributeName)) == null) {
+ throw new IllegalArgumentException("attribute name is null or no such attribute: " + attributeName);
+ }
+
+ return attribute;
+ }
+
+ /**
+ * Find object value.
+ *
+ * @param elementName the element name
+ *
+ * @return the object value
+ */
+ private ObjectValue findObjectValue(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null) {
+ throw new IllegalArgumentException("No object within element");
+ }
+ return v;
+ }
+
+ /**
+ * Gets the resource string.
+ *
+ * @param key the key
+ * @param locale the locale
+ *
+ * @return the resource string
+ */
+ private String getResourceString(String key, Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+
+ // Get the context class loader and try to locate the bundle with it first
+ ClassLoader contextClassloader = AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+
+ // Now try to get the resource bundle
+ ResourceBundle rb;
+ try {
+ rb = ResourceBundle.getBundle(resourceBaseName, locale, contextClassloader);
+ } catch (MissingResourceException e) {
+ try {
+ rb = ResourceBundle.getBundle(resourceBaseName, locale);
+ } catch (MissingResourceException e1) {
+ return null;
+ }
+ }
+
+ try {
+ return rb.getString(key);
+ } catch (MissingResourceException e) {
+ return null;
+ } catch (ClassCastException e) {
+ return null; // Not a string resource
+ }
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataNode.java b/awt/javax/imageio/metadata/IIOMetadataNode.java
new file mode 100644
index 0000000..d5ab7a5
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataNode.java
@@ -0,0 +1,675 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+//???AWT
+//import org.w3c.dom.TypeInfo;
+//import org.w3c.dom.UserDataHandler;
+
+/**
+ * The Class IIOMetadataNode represents a node of the
+ * (DOM-style) metadata tree.
+ */
+public class IIOMetadataNode implements Element, NodeList {
+
+ /** The node name. */
+ private String nodeName;
+
+ /** The node value. */
+ private String nodeValue;
+
+ /** The attributes. */
+ private IIOMetadataNodeList attrs = new IIOMetadataNodeList(new ArrayList<IIOMetadataNode>());
+
+ /** The parent node. */
+ private IIOMetadataNode parent;
+
+ /** The first child node. */
+ private IIOMetadataNode firstChild;
+
+ /** The last child node. */
+ private IIOMetadataNode lastChild;
+
+ /** The previous sibling. */
+ private IIOMetadataNode previousSibling;
+
+ /** The next sibling. */
+ private IIOMetadataNode nextSibling;
+
+ /** The number of children. */
+ private int nChildren;
+
+ /** The user object associated with this node. */
+ private Object userObject;
+
+ /** The text content of this node. */
+ private String textContent;
+
+ /**
+ * Instantiates a new empty node.
+ */
+ public IIOMetadataNode() {
+ }
+
+ /**
+ * Instantiates a new empty node with the specified name.
+ *
+ * @param nodeName the node name
+ */
+ public IIOMetadataNode(String nodeName) {
+ this.nodeName = nodeName;
+ }
+
+ /**
+ * Instantiates a new IIOMetadataNode with the specified
+ * name and value.
+ *
+ * @param nodeName the node name
+ * @param nodeValue the node value
+ */
+ private IIOMetadataNode(String nodeName, String nodeValue) {
+ this.nodeName = nodeName;
+ this.nodeValue = nodeValue;
+ }
+
+ public String getTagName() {
+ return nodeName;
+ }
+
+ public String getAttribute(String name) {
+ Attr attrNode = (Attr) attrs.getNamedItem(name);
+ return (attrNode == null) ? "" : attrNode.getValue();
+ }
+
+ public void setAttribute(String name, String value) throws DOMException {
+ Attr attr = (Attr) attrs.getNamedItem(name);
+ if (attr != null) {
+ attr.setValue(value);
+ } else {
+ attrs.list.add(new IIOMetadataAttr(name, value, this));
+ }
+ }
+
+ public void removeAttribute(String name) throws DOMException {
+ IIOMetadataAttr attr = (IIOMetadataAttr) attrs.getNamedItem(name);
+ if (attr != null) {
+ attr.setOwnerElement(null);
+ attrs.list.remove(attr);
+ }
+ }
+
+ public Attr getAttributeNode(String name) {
+ return (Attr) attrs.getNamedItem(name);
+ }
+
+ public Attr setAttributeNode(Attr newAttr) throws DOMException {
+ // Check if this attribute is already in use.
+ Element owner = newAttr.getOwnerElement();
+ if (owner != null) {
+ if (owner == this) { // Replacing an attribute node by itself has no effect
+ return null;
+ } else {
+ throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, "Attribute is already in use");
+ }
+ }
+
+ String name = newAttr.getName();
+ Attr oldAttr = getAttributeNode(name);
+ if (oldAttr != null) {
+ removeAttributeNode(oldAttr);
+ }
+
+ IIOMetadataAttr iioAttr;
+ if (newAttr instanceof IIOMetadataAttr) {
+ iioAttr = (IIOMetadataAttr) newAttr;
+ iioAttr.setOwnerElement(this);
+ } else {
+ iioAttr = new IIOMetadataAttr(name, newAttr.getValue(), this);
+ }
+
+ attrs.list.add(iioAttr);
+
+ return oldAttr;
+ }
+
+ public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
+ if (!attrs.list.remove(oldAttr)) { // Not found
+ throw new DOMException(DOMException.NOT_FOUND_ERR, "No such attribute!");
+ }
+
+ ((IIOMetadataAttr)oldAttr).setOwnerElement(null);
+
+ return oldAttr;
+ }
+
+ public NodeList getElementsByTagName(String name) {
+ ArrayList<IIOMetadataNode> nodes = new ArrayList<IIOMetadataNode>();
+
+ // Non-recursive tree walk
+ Node pos = this;
+
+ while (pos != null) {
+ if (pos.getNodeName().equals(name)) {
+ nodes.add((IIOMetadataNode)pos);
+ }
+
+ Node nextNode = pos.getFirstChild();
+
+ while (nextNode == null) {
+ if (pos == this) {
+ break;
+ }
+
+ nextNode = pos.getNextSibling();
+
+ if (nextNode == null) {
+ pos = pos.getParentNode();
+
+ if (pos == null || pos == this) {
+ nextNode = null;
+ break;
+ }
+ }
+ }
+ pos = nextNode;
+ }
+
+ return new IIOMetadataNodeList(nodes);
+ }
+
+ public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
+ return getAttribute(localName);
+ }
+
+ public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException {
+ setAttribute(qualifiedName, value);
+ }
+
+ public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
+ removeAttribute(localName);
+ }
+
+ public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
+ return getAttributeNode(localName);
+ }
+
+ public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
+ return setAttributeNode(newAttr);
+ }
+
+ public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException {
+ return getElementsByTagName(localName);
+ }
+
+ public boolean hasAttribute(String name) {
+ return attrs.getNamedItem(name) != null;
+ }
+
+ public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
+ return hasAttribute(localName);
+ }
+
+ //???AWT
+ /*
+ public TypeInfo getSchemaTypeInfo() {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }*/
+
+ public void setIdAttribute(String name, boolean isId) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ public String getNodeValue() throws DOMException {
+ return nodeValue;
+ }
+
+ public void setNodeValue(String nodeValue) throws DOMException {
+ this.nodeValue = nodeValue;
+ }
+
+ public short getNodeType() {
+ return ELEMENT_NODE;
+ }
+
+ public Node getParentNode() {
+ return parent;
+ }
+
+ public NodeList getChildNodes() {
+ return this;
+ }
+
+ public Node getFirstChild() {
+ return firstChild;
+ }
+
+ public Node getLastChild() {
+ return lastChild;
+ }
+
+ public Node getPreviousSibling() {
+ return previousSibling;
+ }
+
+ public Node getNextSibling() {
+ return nextSibling;
+ }
+
+ public NamedNodeMap getAttributes() {
+ return attrs;
+ }
+
+ public Document getOwnerDocument() {
+ return null;
+ }
+
+ public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+ if (newChild == null) {
+ throw new IllegalArgumentException("newChild == null!");
+ }
+
+ IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild;
+ IIOMetadataNode refIIOChild = (IIOMetadataNode) refChild;
+
+ newIIOChild.parent = this;
+
+ if (refIIOChild == null) {
+ newIIOChild.nextSibling = null;
+ newIIOChild.previousSibling = lastChild;
+
+ // Fix this node
+ lastChild = newIIOChild;
+ if (firstChild == null) {
+ firstChild = newIIOChild;
+ }
+ } else {
+ newIIOChild.nextSibling = refIIOChild;
+ newIIOChild.previousSibling = refIIOChild.previousSibling;
+
+ // Fix this node
+ if (firstChild == refIIOChild) {
+ firstChild = newIIOChild;
+ }
+
+ // Fix next node
+ if (refIIOChild != null) {
+ refIIOChild.previousSibling = newIIOChild;
+ }
+ }
+
+ // Fix prev node
+ if (newIIOChild.previousSibling != null) {
+ newIIOChild.previousSibling.nextSibling = newIIOChild;
+ }
+
+ nChildren++;
+
+ return newIIOChild;
+ }
+
+ public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+ if (newChild == null) {
+ throw new IllegalArgumentException("newChild == null!");
+ }
+
+ IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild;
+ IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild;
+
+ IIOMetadataNode next = oldIIOChild.nextSibling;
+ IIOMetadataNode previous = oldIIOChild.previousSibling;
+
+ // Fix new node
+ newIIOChild.parent = this;
+ newIIOChild.nextSibling = next;
+ newIIOChild.previousSibling = previous;
+
+ // Fix this node
+ if (lastChild == oldIIOChild) {
+ lastChild = newIIOChild;
+ }
+ if (firstChild == oldIIOChild) {
+ firstChild = newIIOChild;
+ }
+
+ // Fix siblings
+ if (next != null) {
+ next.previousSibling = newIIOChild;
+ }
+ if (previous != null) {
+ previous.nextSibling = newIIOChild;
+ }
+
+ // Fix old child
+ oldIIOChild.parent = null;
+ oldIIOChild.nextSibling = next;
+ oldIIOChild.previousSibling = previous;
+
+ return oldIIOChild;
+ }
+
+ public Node removeChild(Node oldChild) throws DOMException {
+ if (oldChild == null) {
+ throw new IllegalArgumentException("oldChild == null!");
+ }
+
+ IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild;
+
+ // Fix next and previous
+ IIOMetadataNode previous = oldIIOChild.previousSibling;
+ IIOMetadataNode next = oldIIOChild.nextSibling;
+
+ if (previous != null) {
+ previous.nextSibling = next;
+ }
+ if (next != null) {
+ next.previousSibling = previous;
+ }
+
+ // Fix this node
+ if (lastChild == oldIIOChild) {
+ lastChild = previous;
+ }
+ if (firstChild == oldIIOChild) {
+ firstChild = next;
+ }
+ nChildren--;
+
+ // Fix old child
+ oldIIOChild.parent = null;
+ oldIIOChild.previousSibling = null;
+ oldIIOChild.nextSibling = null;
+
+ return oldIIOChild;
+ }
+
+ public Node appendChild(Node newChild) throws DOMException {
+ return insertBefore(newChild, null);
+ }
+
+ public boolean hasChildNodes() {
+ return nChildren != 0;
+ }
+
+ public Node cloneNode(boolean deep) {
+ IIOMetadataNode cloned = new IIOMetadataNode(nodeName);
+ cloned.setUserObject(getUserObject());
+
+ if (deep) { // Clone recursively
+ IIOMetadataNode c = firstChild;
+ while (c != null) {
+ cloned.insertBefore(c.cloneNode(true), null);
+ c = c.nextSibling;
+ }
+ }
+
+ return cloned; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void normalize() {
+ // Do nothing
+ }
+
+ public boolean isSupported(String feature, String version) {
+ return false;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public String getPrefix() {
+ return null;
+ }
+
+ public void setPrefix(String prefix) throws DOMException {
+ // Do nothing
+ }
+
+ public String getLocalName() {
+ return nodeName;
+ }
+
+ public boolean hasAttributes() {
+ return attrs.list.size() > 0;
+ }
+
+ public String getBaseURI() {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public short compareDocumentPosition(Node other) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String getTextContent() throws DOMException {
+ return textContent;
+ }
+
+ public void setTextContent(String textContent) throws DOMException {
+ this.textContent = textContent;
+ }
+
+ public boolean isSameNode(Node other) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String lookupPrefix(String namespaceURI) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public boolean isDefaultNamespace(String namespaceURI) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String lookupNamespaceURI(String prefix) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public boolean isEqualNode(Node arg) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public Object getFeature(String feature, String version) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ //???AWT
+ /*
+ public Object setUserData(String key, Object data, UserDataHandler handler) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }*/
+
+ public Object getUserData(String key) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public Node item(int index) {
+ if (index < 0 || index >= nChildren) {
+ return null;
+ }
+
+ Node n;
+ for (n = getFirstChild(); index > 0; index--) {
+ n = n.getNextSibling();
+ }
+
+ return n;
+ }
+
+ public int getLength() {
+ return nChildren;
+ }
+
+ /**
+ * Gets the user object associated with this node.
+ *
+ * @return the user object associated with this node
+ */
+ public Object getUserObject() {
+ return userObject;
+ }
+
+ /**
+ * Sets the user object associated with this node.
+ *
+ * @param userObject the new user object associated with this node
+ */
+ public void setUserObject(Object userObject) {
+ this.userObject = userObject;
+ }
+
+ /**
+ * The Class IIOMetadataAttr.
+ */
+ private class IIOMetadataAttr extends IIOMetadataNode implements Attr {
+
+ /** The owner element. */
+ private Element ownerElement;
+
+ /**
+ * Instantiates a new iIO metadata attr.
+ *
+ * @param name the name
+ * @param value the value
+ * @param owner the owner
+ */
+ public IIOMetadataAttr(String name, String value, Element owner) {
+ super(name, value);
+ this.ownerElement = owner;
+ }
+
+ public String getName() {
+ return getNodeName();
+ }
+
+ public boolean getSpecified() {
+ return true;
+ }
+
+ public String getValue() {
+ return nodeValue;
+ }
+
+ public void setValue(String value) throws DOMException {
+ nodeValue = value;
+ }
+
+ public Element getOwnerElement() {
+ return ownerElement;
+ }
+
+ /**
+ * Sets the owner element.
+ *
+ * @param ownerElement the new owner element
+ */
+ public void setOwnerElement(Element ownerElement) {
+ this.ownerElement = ownerElement;
+ }
+
+ public boolean isId() {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ @Override
+ public short getNodeType() {
+ return ATTRIBUTE_NODE;
+ }
+ }
+
+ /**
+ * The Class IIOMetadataNodeList.
+ */
+ private class IIOMetadataNodeList implements NodeList, NamedNodeMap {
+
+ /** The list. */
+ private List<IIOMetadataNode> list;
+
+ /**
+ * Instantiates a new iIO metadata node list.
+ *
+ * @param list the list
+ */
+ IIOMetadataNodeList(List<IIOMetadataNode> list) {
+ this.list = list;
+ }
+
+ public Node item(int index) {
+ try {
+ return list.get(index);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ }
+
+ public int getLength() {
+ return list.size();
+ }
+
+ public Node getNamedItem(String name) {
+ for(IIOMetadataNode node:list) {
+ if (name.equals(node.getNodeName())) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public Node setNamedItem(Node arg) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+
+ public Node removeNamedItem(String name) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+
+ public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException {
+ return getNamedItem(localName);
+ }
+
+ public Node setNamedItemNS(Node arg) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+
+ public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
new file mode 100644
index 0000000..94d2125
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.ArrayList;
+
+/**
+ * The Class IIOStandardMetadataFormat describes the rules of the
+ * standard metadata format.
+ */
+class IIOStandardMetadataFormat extends IIOMetadataFormatImpl {
+
+ /**
+ * Instantiates a new IIOStandardMetadataFormat.
+ */
+ public IIOStandardMetadataFormat() {
+ super(standardMetadataFormatName, CHILD_POLICY_SOME);
+ buildDTD();
+ }
+
+ @Override
+ public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) {
+ return true;
+ }
+
+ /**
+ * Builds the dtd that describes the standard metadata format.
+ */
+ private void buildDTD() {
+ // CHROMA
+ addElement("Chroma", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("ColorSpaceType", "Chroma", CHILD_POLICY_EMPTY);
+
+ ArrayList<String> values = new ArrayList<String>(27);
+ values.add("XYZ");
+ values.add("Lab");
+ values.add("Luv");
+ values.add("YCbCr");
+ values.add("Yxy");
+ values.add("YCCK");
+ values.add("PhotoYCC");
+ values.add("RGB");
+ values.add("GRAY");
+ values.add("HSV");
+ values.add("HLS");
+ values.add("CMYK");
+ values.add("CMY");
+ values.add("2CLR");
+ values.add("3CLR");
+ values.add("4CLR");
+ values.add("5CLR");
+ values.add("6CLR");
+ values.add("7CLR");
+ values.add("8CLR");
+ values.add("9CLR");
+ values.add("ACLR");
+ values.add("BCLR");
+ values.add("CCLR");
+ values.add("DCLR");
+ values.add("ECLR");
+ values.add("FCLR");
+ addAttribute("ColorSpaceType", "name", DATATYPE_STRING, true, null, values);
+
+ addElement("NumChannels", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("NumChannels", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); // list - why?
+
+ addElement("Gamma", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("Gamma", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("BlackIsZero", "Chroma", CHILD_POLICY_EMPTY);
+ addBooleanAttribute("BlackIsZero", "value", true, true);
+
+ addElement("Palette", "Chroma", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+ addElement("PaletteEntry", "Palette", CHILD_POLICY_EMPTY);
+ addAttribute("PaletteEntry", "index", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "red", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "green", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "blue", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "alpha", DATATYPE_INTEGER, false, "255");
+
+ addElement("BackgroundIndex", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("BackgroundIndex", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("BackgroundColor", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("BackgroundColor", "red", DATATYPE_INTEGER, true, null);
+ addAttribute("BackgroundColor", "green", DATATYPE_INTEGER, true, null);
+ addAttribute("BackgroundColor", "blue", DATATYPE_INTEGER, true, null);
+
+ // COMPRESSION
+ addElement("Compression", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("CompressionTypeName", "Compression", CHILD_POLICY_EMPTY);
+ addAttribute("CompressionTypeName", "value", DATATYPE_STRING, true, null);
+
+ addElement("Lossless", "Compression", CHILD_POLICY_EMPTY);
+ addBooleanAttribute("Lossless", "value", true, true);
+
+ addElement("NumProgressiveScans", "Compression", CHILD_POLICY_EMPTY);
+ addAttribute("NumProgressiveScans", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("BitRate", "Compression", CHILD_POLICY_EMPTY);
+ addAttribute("BitRate", "value", DATATYPE_FLOAT, true, null);
+
+ // DATA
+ addElement("Data", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("PlanarConfiguration", "Data", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(4);
+ values.add("PixelInterleaved");
+ values.add("PlaneInterleaved");
+ values.add("LineInterleaved");
+ values.add("TileInterleaved");
+ addAttribute("PlanarConfiguration", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("SampleFormat", "Data", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(4);
+ values.add("SignedIntegral");
+ values.add("UnsignedIntegral");
+ values.add("Real");
+ values.add("Index");
+ addAttribute("SampleFormat", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("BitsPerSample", "Data", CHILD_POLICY_EMPTY);
+ addAttribute("BitsPerSample", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list
+
+ addElement("SignificantBitsPerSample", "Data", CHILD_POLICY_EMPTY);
+ addAttribute(
+ "SignificantBitsPerSample", "value",
+ DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE
+ ); // list
+
+ addElement("SampleMSB", "Data", CHILD_POLICY_EMPTY);
+ addAttribute("SampleMSB", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list
+
+ // DIMENSION
+ addElement("Dimension", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("PixelAspectRatio", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("PixelAspectRatio", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("ImageOrientation", "Dimension", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(8);
+ values.add("Normal");
+ values.add("Rotate90");
+ values.add("Rotate180");
+ values.add("Rotate270");
+ values.add("FlipH");
+ values.add("FlipV");
+ values.add("FlipHRotate90");
+ values.add("FlipVRotate90");
+ addAttribute("ImageOrientation", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("HorizontalPixelSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPixelSize", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("VerticalPixelSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPixelSize", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("HorizontalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("VerticalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("HorizontalPosition", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPosition", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("VerticalPosition", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPosition", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("HorizontalPixelOffset", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPixelOffset", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("VerticalPixelOffset", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPixelOffset", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("HorizontalScreenSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalScreenSize", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("VerticalScreenSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalScreenSize", "value", DATATYPE_INTEGER, true, null);
+
+ // DOCUMENT
+ addElement("Document", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("FormatVersion", "Document", CHILD_POLICY_EMPTY);
+ addAttribute("FormatVersion", "value", DATATYPE_STRING, true, null);
+
+ addElement("SubimageInterpretation", "Document", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(14);
+ values.add("Standalone");
+ values.add("SinglePage");
+ values.add("FullResolution");
+ values.add("ReducedResolution");
+ values.add("PyramidLayer");
+ values.add("Preview");
+ values.add("VolumeSlice");
+ values.add("ObjectView");
+ values.add("Panorama");
+ values.add("AnimationFrame");
+ values.add("TransparencyMask");
+ values.add("CompositingLayer");
+ values.add("SpectralSlice");
+ values.add("Unknown");
+ addAttribute("SubimageInterpretation", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("ImageCreationTime", "Document", CHILD_POLICY_EMPTY);
+ addAttribute("ImageCreationTime", "year", DATATYPE_INTEGER, true, null);
+ addAttribute(
+ "ImageCreationTime", "month",
+ DATATYPE_INTEGER, true, null, "1", "12", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "day",
+ DATATYPE_INTEGER, true, null, "1", "31", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "hour",
+ DATATYPE_INTEGER, false, "0", "0", "23", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "minute",
+ DATATYPE_INTEGER, false, "0", "0", "59", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "second",
+ DATATYPE_INTEGER, false, "0", "0", "60", true, true
+ );
+
+ addElement("ImageModificationTime", "Document", CHILD_POLICY_EMPTY);
+ addAttribute("ImageModificationTime", "year", DATATYPE_INTEGER, true, null);
+ addAttribute(
+ "ImageModificationTime", "month",
+ DATATYPE_INTEGER, true, null, "1", "12", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "day",
+ DATATYPE_INTEGER, true, null, "1", "31", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "hour",
+ DATATYPE_INTEGER, false, "0", "0", "23", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "minute",
+ DATATYPE_INTEGER, false, "0", "0", "59", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "second",
+ DATATYPE_INTEGER, false, "0", "0", "60", true, true
+ );
+
+ // TEXT
+ addElement("Text", standardMetadataFormatName, 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+ addElement("TextEntry", "Text", CHILD_POLICY_EMPTY);
+ addAttribute("TextEntry", "keyword", DATATYPE_STRING, false, null);
+ addAttribute("TextEntry", "value", DATATYPE_STRING, true, null);
+ addAttribute("TextEntry", "language", DATATYPE_STRING, false, null);
+ addAttribute("TextEntry", "encoding", DATATYPE_STRING, false, null);
+ values = new ArrayList<String>(5);
+ values.add("none");
+ values.add("lzw");
+ values.add("zip");
+ values.add("bzip");
+ values.add("other");
+ addAttribute("TextEntry", "compression", DATATYPE_STRING, false, "none", values);
+
+ // TRANSPARENCY
+ addElement("Transparency", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("Alpha", "Transparency", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(3);
+ values.add("none");
+ values.add("premultiplied");
+ values.add("nonpremultiplied");
+ addAttribute("Alpha", "value", DATATYPE_STRING, false, "none", values);
+
+ addElement("TransparentIndex", "Transparency", CHILD_POLICY_EMPTY);
+ addAttribute("TransparentIndex", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("TransparentColor", "Transparency", CHILD_POLICY_EMPTY);
+ addAttribute("TransparentColor", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE);
+
+ addElement("TileTransparencies", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+ addElement("TransparentTile", "TileTransparencies", CHILD_POLICY_EMPTY);
+ addAttribute("TransparentTile", "x", DATATYPE_INTEGER, true, null);
+ addAttribute("TransparentTile", "y", DATATYPE_INTEGER, true, null);
+
+ addElement("TileOpacities", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+ addElement("OpaqueTile", "TileOpacities", CHILD_POLICY_EMPTY);
+ addAttribute("OpaqueTile", "x", DATATYPE_INTEGER, true, null);
+ addAttribute("OpaqueTile", "y", DATATYPE_INTEGER, true, null);
+ }
+}
+
diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties b/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
new file mode 100644
index 0000000..d185808
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
@@ -0,0 +1,133 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Descriptions of elements and attributes of the plugin neutral metadata format
+# (see IIOStandardMetadataFormat)
+
+# Messages for EN locale
+Chroma=Chroma (color) information
+ColorSpaceType=The raw color space of the image
+ColorSpaceType/name=The raw color space of the image
+NumChannels=The number of channels in the raw image, including alpha
+NumChannels/value=The number of channels in the raw image, including alpha
+Gamma=The image gamma
+Gamma/value=The image gamma
+BlackIsZero=True if smaller values represent darker shades
+BlackIsZero/value=True if smaller values represent darker shades
+Palette=Palette-color information
+PaletteEntry=A palette entry
+PaletteEntry/index=The index of the palette entry
+PaletteEntry/red=The red value for the palette entry
+PaletteEntry/green=The green value for the palette entry
+PaletteEntry/blue=The blue value for the palette entry
+PaletteEntry/alpha=The alpha value for the palette entry
+BackgroundIndex=A palette index to be used as a background
+BackgroundIndex/value=A palette index to be used as a background
+BackgroundColor=An RGB triple to be used as a background
+BackgroundColor/red=The red background value
+BackgroundColor/green=The green background value
+BackgroundColor/blue=The blue background value
+
+Compression=Compression information
+CompressionTypeName=The name of the compression scheme in use
+CompressionTypeName/value=The name of the compression scheme in use
+Lossless=True if the compression scheme is lossless
+Lossless/value=True if the compression scheme is lossless
+NumProgressiveScans=The number of progressive scans used in the image encoding
+NumProgressiveScans/value=The number of progressive scans used in the image encoding
+BitRate=The estimated bit rate of the compression scheme
+BitRate/value=The estimated bit rate of the compression scheme
+
+Data=Information on the image layout
+PlanarConfiguration=The organization of image samples in the stream
+PlanarConfiguration/value=The organization of image samples in the stream
+SampleFormat=The numeric format of image samples
+SampleFormat/value=The numeric format of image samples
+BitsPerSample=The number of bits per sample
+BitsPerSample/value=A list of integers, one per channel
+SignificantBitsPerSample=The number of significant bits per sample
+SignificantBitsPerSample/value=A list of integers, one per channel
+SampleMSB=The position of the most significant bit of each sample
+SampleMSB/value=A list of integers, one per channel
+
+Dimension=Dimension information
+PixelAspectRatio=The width of a pixel divided by its height
+PixelAspectRatio/value=The width of a pixel divided by its height
+ImageOrientation=The desired orientation of the image in terms of flips and counter-clockwise rotations
+ImageOrientation/value=The desired orientation of the image in terms of flips and counter-clockwise rotations
+HorizontalPixelSize=The width of a pixel, in millimeters, as it should be rendered on media
+HorizontalPixelSize/value=The width of a pixel, in millimeters, as it should be rendered on media
+VerticalPixelSize=The height of a pixel, in millimeters, as it should be rendered on media
+VerticalPixelSize/value=The height of a pixel, in millimeters, as it should be rendered on media
+HorizontalPhysicalPixelSpacing=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+HorizontalPhysicalPixelSpacing/value=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+VerticalPhysicalPixelSpacing=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+VerticalPhysicalPixelSpacing/value=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+HorizontalPosition=The horizontal position, in millimeters, where the image should be rendered on media
+HorizontalPosition/value=The horizontal position, in millimeters, where the image should be rendered on media
+VerticalPosition=The vertical position, in millimeters, where the image should be rendered on media
+VerticalPosition/value=The vertical position, in millimeters, where the image should be rendered on media
+HorizontalPixelOffset=The horizonal position, in pixels, where the image should be rendered onto a raster display
+HorizontalPixelOffset/value=The horizonal position, in pixels, where the image should be rendered onto a raster display
+VerticalPixelOffset=The vertical position, in pixels, where the image should be rendered onto a raster display
+VerticalPixelOffset/value=The vertical position, in pixels, where the image should be rendered onto a raster display
+HorizontalScreenSize=The width, in pixels, of the raster display into which the image should be rendered
+HorizontalScreenSize/value=The width, in pixels, of the raster display into which the image should be rendered
+VerticalScreenSize=The height, in pixels, of the raster display into which the image should be rendered
+VerticalScreenSize/value=The height, in pixels, of the raster display into which the image should be rendered
+
+Document=Document information
+FormatVersion=The version of the format used by the stream
+FormatVersion/value=The version of the format used by the stream
+SubimageInterpretation=The interpretation of this image in relation to the other images stored in the same stream
+SubimageInterpretation/value=The interpretation of this image in relation to the other images stored in the same stream
+ImageCreationTime=The time of image creation
+ImageCreationTime/year=The full year (e.g., 1967, not 67)
+ImageCreationTime/month=The month, with January = 1
+ImageCreationTime/day=The day of the month
+ImageCreationTime/hour=The hour from 0 to 23
+ImageCreationTime/minute=The minute from 0 to 59
+ImageCreationTime/second=The second from 0 to 60 (60 = leap second)
+ImageModificationTime=The time of the last image modification
+ImageModificationTime/year=The full year (e.g., 1967, not 67)
+ImageModificationTime/month=The month, with January = 1
+ImageModificationTime/day=The day of the month
+ImageModificationTime/hour=The hour from 0 to 23
+ImageModificationTime/minute=The minute from 0 to 59
+ImageModificationTime/second=The second from 0 to 60 (60 = leap second)
+
+Text=Text information
+TextEntry=A text entry
+TextEntry/keyword=A keyword associated with the text entry
+TextEntry/value=the text entry
+TextEntry/language=The language of the text
+TextEntry/encoding=The encoding of the text
+TextEntry/compression=The method used to compress the text
+
+Transparency=Transparency information
+Alpha=The type of alpha information contained in the image
+Alpha/value=The type of alpha information contained in the image
+TransparentIndex=A palette index to be treated as transparent
+TransparentIndex/value=A palette index to be treated as transparent
+TransparentColor=An RGB color to be treated as transparent
+TransparentColor/value=An RGB color to be treated as transparent
+TileTransparencies=A list of completely transparent tiles
+TransparentTile=The index of a completely transparent tile
+TransparentTile/x=The tile's X index
+TransparentTile/y=The tile's Y index
+TileOpacities=A list of completely opaque tiles
+OpaqueTile=The index of a completely opaque tile
+OpaqueTile/x=The tile's X index
+OpaqueTile/y=The tile's Y index
diff --git a/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
new file mode 100644
index 0000000..0cd44db
--- /dev/null
+++ b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.plugins.bmp;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The BMPImageWriteParam class allows encoding an image in
+ * BMP format.
+ */
+public class BMPImageWriteParam extends ImageWriteParam {
+
+ /** The top down. */
+ private boolean topDown; // Default is bottom-up
+
+ /**
+ * Instantiates a new BMPImageWriteParam with default values of all
+ * parameters.
+ */
+ public BMPImageWriteParam() {
+ this(null);
+ }
+
+ /**
+ * Instantiates a new BMPImageWriteParam with the specified Locale.
+ *
+ * @param locale the specified Locale.
+ */
+ public BMPImageWriteParam(Locale locale) {
+ super(locale);
+
+ // Set the compression
+ canWriteCompressed = true;
+ compressionTypes = new String[] {"BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS"};
+ compressionType = compressionTypes[0];
+ }
+
+ /**
+ * Sets true if the data will be written in a top-down order,
+ * false otherwise.
+ *
+ * @param topDown the new top-down value.
+ */
+ public void setTopDown(boolean topDown) {
+ this.topDown = topDown;
+ }
+
+ /**
+ * Returns true if the data is written in top-down order, false
+ * otherwise.
+ *
+ * @return true if the data is written in top-down order, false
+ * otherwise.
+ */
+ public boolean isTopDown() {
+ return topDown;
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
new file mode 100644
index 0000000..398c960
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGHuffmanTable class represents a single JPEG Huffman table.
+ * It contains the standard tables from the JPEG specification.
+ */
+public class JPEGHuffmanTable {
+
+ /** The standard DC luminance Huffman table . */
+ public static final JPEGHuffmanTable StdDCLuminance = new JPEGHuffmanTable(
+ new short[] {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
+ new short[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B},
+ false
+ );
+
+ /** The standard DC chrominance Huffman table. */
+ public static final JPEGHuffmanTable StdDCChrominance = new JPEGHuffmanTable(
+ new short[] {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+ new short[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B},
+ false
+ );
+
+ /** The standard AC luminance Huffman table. */
+ public static final JPEGHuffmanTable StdACLuminance = new JPEGHuffmanTable(
+ new short[] {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D},
+ new short[] {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+ 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08,
+ 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
+ 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
+ 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
+ 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
+ 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
+ 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+ },
+ false
+ );
+
+ /**
+ * The standard AC chrominance Huffman table. */
+ public static final JPEGHuffmanTable StdACChrominance = new JPEGHuffmanTable(
+ new short[] {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77},
+ new short[] {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+ 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1,
+ 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
+ 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
+ 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,
+ 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+ },
+ false
+ );
+
+ /** The lengths. */
+ private short lengths[];
+
+ /** The values. */
+ private short values[];
+
+ /**
+ * Instantiates a new jPEG huffman table.
+ *
+ * @param lengths the lengths
+ * @param values the values
+ * @param copy the copy
+ */
+ JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) {
+ // Construction of standard tables without checks
+ // The third param is dummy
+ // Could be also used for copying of the existing tables
+ this.lengths = lengths;
+ this.values = values;
+ }
+
+ /**
+ * Instantiates a new JPEGHuffmanTable.
+ *
+ * @param lengths the array of shorts lengths.
+ * @param values the array of shorts containing
+ * the values in order of increasing code length.
+ */
+ public JPEGHuffmanTable(short[] lengths, short[] values) {
+ if (lengths == null) {
+ throw new IllegalArgumentException("lengths array is null!");
+ }
+ if (values == null) {
+ throw new IllegalArgumentException("values array is null!");
+ }
+ if (lengths.length > 16) { // According to the spec
+ throw new IllegalArgumentException("lengths array is too long!");
+ }
+ if (values.length > 256) { // According to the spec
+ throw new IllegalArgumentException("values array is too long");
+ }
+ for (short length : lengths) {
+ if (length < 0) {
+ throw new IllegalArgumentException("Values in lengths array must be non-negative.");
+ }
+ }
+ for (short value : values) {
+ if (value < 0) {
+ throw new IllegalArgumentException("Values in values array must be non-negative.");
+ }
+ }
+
+ checkHuffmanTable(lengths, values);
+
+ this.lengths = new short[lengths.length];
+ this.values = new short[values.length];
+ System.arraycopy(lengths, 0, this.lengths, 0, lengths.length);
+ System.arraycopy(values, 0, this.values, 0, values.length);
+ }
+
+ /**
+ * Gets an array of lengths in the Huffman table.
+ *
+ * @return the array of short values representing the
+ * length values in the Huffman table.
+ */
+ public short[] getLengths() {
+ short newLengths[] = new short[lengths.length];
+ System.arraycopy(lengths, 0, newLengths, 0, lengths.length);
+ return newLengths;
+ }
+
+ /**
+ * Gets an array of values represented by increasing length of
+ * their codes.
+ *
+ * @return the array of values.
+ */
+ public short[] getValues() {
+ short newValues[] = new short[values.length];
+ System.arraycopy(values, 0, newValues, 0, values.length);
+ return newValues;
+ }
+
+ /**
+ * Check huffman table.
+ *
+ * @param lengths the lengths
+ * @param values the values
+ */
+ private static void checkHuffmanTable(short[] lengths, short[] values) {
+ int numLeaves = 0;
+ int possibleLeaves = 2;
+ for (short length : lengths) {
+ numLeaves += length;
+ possibleLeaves -= length;
+ if (possibleLeaves < 0) {
+ throw new IllegalArgumentException("Invalid Huffman table provided, lengths are incorrect.");
+ }
+ possibleLeaves <<= 1;
+ }
+
+ if (values.length != numLeaves) {
+ throw new IllegalArgumentException("Invalid Huffman table provided, sum of lengths != values.");
+ }
+ }
+
+ /**
+ * Returns the string representation of this JPEGHuffmanTable object.
+ *
+ * @return the string representation of this JPEGHuffmanTable object.
+ */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("JPEGHuffmanTable:\nlengths:");
+ for (short length : lengths) {
+ sb.append(' ').append(length);
+ }
+
+ sb.append("\nvalues:");
+ for (short value : values) {
+ sb.append(' ').append(value);
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
new file mode 100644
index 0000000..dd08d51
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+import javax.imageio.ImageReadParam;
+
+/**
+ * The JPEGImageReadParam class provides functionality to set Huffman tables
+ * and quantization tables when using the JPEG reader plug-in.
+ */
+public class JPEGImageReadParam extends ImageReadParam {
+
+ /** The q tables. */
+ private JPEGQTable qTables[];
+
+ /** The dc huffman tables. */
+ private JPEGHuffmanTable dcHuffmanTables[];
+
+ /** The ac huffman tables. */
+ private JPEGHuffmanTable acHuffmanTables[];
+
+ /**
+ * Instantiates a new JPEGImageReadParam.
+ */
+ public JPEGImageReadParam() {
+ }
+
+ /**
+ * Returns true if tables are set, false otherwise.
+ *
+ * @return true if tables are set, false otherwise.
+ */
+ public boolean areTablesSet() {
+ return qTables != null;
+ }
+
+ /**
+ * Sets the quantization and Huffman tables for using in
+ * decoding streams.
+ *
+ * @param qTables the quantization tables.
+ * @param DCHuffmanTables the standart DC Huffman tables.
+ * @param ACHuffmanTables the standart AC huffman tables.
+ */
+ public void setDecodeTables(
+ JPEGQTable[] qTables,
+ JPEGHuffmanTable[] DCHuffmanTables,
+ JPEGHuffmanTable[] ACHuffmanTables
+ ) {
+ if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if(DCHuffmanTables.length != ACHuffmanTables.length) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if (qTables.length > 4 || DCHuffmanTables.length > 4) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+
+ // Do the shallow copy, it should be enough
+ this.qTables = qTables.clone();
+ dcHuffmanTables = DCHuffmanTables.clone();
+ acHuffmanTables = ACHuffmanTables.clone();
+ }
+
+ /**
+ * Unset all decoded tables.
+ */
+ public void unsetDecodeTables() {
+ qTables = null;
+ dcHuffmanTables = null;
+ acHuffmanTables = null;
+ }
+
+ /**
+ * Gets the quantization tables.
+ *
+ * @return the quantization tables, or null.
+ */
+ public JPEGQTable[] getQTables() {
+ return qTables == null ? null : qTables.clone();
+ }
+
+ /**
+ * Gets the DC Huffman tables.
+ *
+ * @return the DC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getDCHuffmanTables() {
+ return dcHuffmanTables == null ? null : dcHuffmanTables.clone();
+ }
+
+ /**
+ * Gets the AC Huffman tables.
+ *
+ * @return the AC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getACHuffmanTables() {
+ return acHuffmanTables == null ? null : acHuffmanTables.clone();
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
new file mode 100644
index 0000000..34a3cd9
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGConsts;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The JPEGImageWriteParam class allows to set JPEG Huffman tables
+ * and quantization when using the JPEG writer plug-in.
+ */
+public class JPEGImageWriteParam extends ImageWriteParam {
+
+ /** The Constant COMP_QUALITY_VALUES. */
+ private static final float[] COMP_QUALITY_VALUES = {0.05f, 0.75f, 0.95f};
+
+ /** The Constant COMP_QUALITY_DESCRIPTIONS. */
+ private static final String[] COMP_QUALITY_DESCRIPTIONS = {
+ "Minimum useful",
+ "Visually lossless",
+ "Maximum useful"
+ };
+
+ /** The q tables. */
+ private JPEGQTable[] qTables;
+
+ /** The dc huffman tables. */
+ private JPEGHuffmanTable[] dcHuffmanTables;
+
+ /** The ac huffman tables. */
+ private JPEGHuffmanTable[] acHuffmanTables;
+
+ /** The optimize huffman tables. */
+ private boolean optimizeHuffmanTables;
+
+ /**
+ * Instantiates a new JPEGImageWriteParam object with
+ * the specified Locale.
+ *
+ * @param locale the Locale.
+ */
+ public JPEGImageWriteParam(Locale locale) {
+ super(locale);
+
+ canWriteProgressive = true;
+ progressiveMode = ImageWriteParam.MODE_DISABLED;
+
+ canWriteCompressed = true;
+ compressionTypes = new String[]{"JPEG"};
+ compressionType = compressionTypes[0];
+ compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY;
+ }
+
+ /**
+ * Returns true if tables are set, false otherwise.
+ *
+ * @return true if tables are set, false otherwise.
+ */
+ public boolean areTablesSet() {
+ return qTables != null;
+ }
+
+ /**
+ * Sets the quantization and Huffman tables for using in
+ * encoding streams.
+ *
+ * @param qTables the quantization tables.
+ * @param DCHuffmanTables the standart DC Huffman tables.
+ * @param ACHuffmanTables the standart AC huffman tables.
+ */
+ public void setEncodeTables(
+ JPEGQTable[] qTables,
+ JPEGHuffmanTable[] DCHuffmanTables,
+ JPEGHuffmanTable[] ACHuffmanTables
+ ) {
+ if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if(DCHuffmanTables.length != ACHuffmanTables.length) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if (qTables.length > 4 || DCHuffmanTables.length > 4) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+
+ // Do the shallow copy, it should be enough
+ this.qTables = qTables.clone();
+ dcHuffmanTables = DCHuffmanTables.clone();
+ acHuffmanTables = ACHuffmanTables.clone();
+ }
+
+ /**
+ * Unset all encoded tables.
+ */
+ public void unsetEncodeTables() {
+ qTables = null;
+ dcHuffmanTables = null;
+ acHuffmanTables = null;
+ }
+
+ /**
+ * Gets the DC Huffman tables.
+ *
+ * @return the DC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getDCHuffmanTables() {
+ return dcHuffmanTables == null ? null : dcHuffmanTables.clone();
+ }
+
+ /**
+ * Gets the AC Huffman tables.
+ *
+ * @return the AC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getACHuffmanTables() {
+ return acHuffmanTables == null ? null : acHuffmanTables.clone();
+ }
+
+ /**
+ * Gets the quantization tables.
+ *
+ * @return the quantization tables, or null.
+ */
+ public JPEGQTable[] getQTables() {
+ return qTables == null ? null : qTables.clone();
+ }
+
+ @Override
+ public String[] getCompressionQualityDescriptions() {
+ super.getCompressionQualityDescriptions();
+ return COMP_QUALITY_DESCRIPTIONS.clone();
+ }
+
+ @Override
+ public float[] getCompressionQualityValues() {
+ super.getCompressionQualityValues();
+ return COMP_QUALITY_VALUES.clone();
+ }
+
+ /**
+ * Sets the flag indicated that the writer will generate optimized
+ * Huffman tables for the image as part of the writing process.
+ *
+ * @param optimize the flag of optimizing huffman tables.
+ */
+ public void setOptimizeHuffmanTables(boolean optimize) {
+ optimizeHuffmanTables = optimize;
+ }
+
+ /**
+ * Returns true if the writer generates optimized Huffman tables,
+ * false otherwise.
+ *
+ * @return the true if the writer generates optimized Huffman tables,
+ * false otherwise.
+ */
+ public boolean getOptimizeHuffmanTables() {
+ return optimizeHuffmanTables;
+ }
+
+ @Override
+ public boolean isCompressionLossless() {
+ if (getCompressionMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+ }
+ return false;
+ }
+
+ @Override
+ public void unsetCompression() {
+ if (getCompressionMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+ }
+ compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY;
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGQTable.java b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java
new file mode 100644
index 0000000..0c5b37e
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGQTable class represents a single JPEG quantization table
+ * and provides for the standard tables taken from the JPEG specification.
+ */
+public class JPEGQTable {
+
+ /** The Constant SIZE. */
+ private final static int SIZE = 64;
+
+ /** The Constant BASELINE_MAX. */
+ private final static int BASELINE_MAX = 255;
+
+ /** The Constant MAX. */
+ private final static int MAX = 32767;
+
+
+ /** The table. */
+ private int[] theTable;
+
+ /*
+ * K1 & K2 tables can be found in the JPEG format specification
+ * at http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+
+ /** The Constant K1LumTable. */
+ private static final int[] K1LumTable = new int[] {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ };
+
+ /** The Constant K2ChrTable. */
+ private static final int[] K2ChrTable = new int[] {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+ /**
+ * The K1Luminance indicates standart table K.1 from JPEG
+ * specification and produces "good" quality output.
+ */
+ public static final JPEGQTable K1Luminance = new JPEGQTable(K1LumTable);
+
+ /**
+ * The K1Div2Luminance indicates K.1 table from JPEG
+ * specification with all elements divided by 2 and produces
+ * "very good" quality output.
+ */
+ public static final JPEGQTable K1Div2Luminance = K1Luminance.getScaledInstance(0.5f, true);
+
+ /**
+ * The K2Chrominance indicates K.2 table from JPEG
+ * specification and produces "good" quality output.
+ */
+ public static final JPEGQTable K2Chrominance = new JPEGQTable(K2ChrTable);
+
+ /**
+ * The Constant K2Div2Chrominance indicates K.2 table from JPEG
+ * specification with all elements divided by 2 and produces
+ * "very good" quality output.
+ */
+ public static final JPEGQTable K2Div2Chrominance = K2Chrominance.getScaledInstance(0.5f, true);;
+
+
+ /**
+ * Instantiates a new JPEGQTable from the array, which
+ * should contain 64 elements in natural order.
+ *
+ * @param table the quantization table.
+ */
+ public JPEGQTable(int[] table) {
+ if (table == null) {
+ throw new IllegalArgumentException("table should not be NULL");
+ }
+ if (table.length != SIZE) {
+ throw new IllegalArgumentException("illegal table size: " + table.length);
+ }
+ theTable = table.clone();
+ }
+
+ /**
+ * Gets the current quantization table as an array of int values.
+ *
+ * @return the current quantization table as an array of int values.
+ */
+ public int[] getTable() {
+ return theTable.clone();
+ }
+
+ /**
+ * Gets the scaled instance as quantization table where
+ * the values are multiplied by the scaleFactor and then clamped
+ * if forceBaseline is true.
+ *
+ * @param scaleFactor the scale factor of table.
+ * @param forceBaseline the force baseline flag, the values
+ * should be clamped if true.
+ *
+ * @return the new quantization table.
+ */
+ public JPEGQTable getScaledInstance(float scaleFactor, boolean forceBaseline) {
+ int table[] = new int[SIZE];
+
+ int maxValue = forceBaseline ? BASELINE_MAX : MAX;
+
+ for (int i = 0; i < theTable.length; i++) {
+ int rounded = Math.round(theTable[i] * scaleFactor);
+ if (rounded < 1) {
+ rounded = 1;
+ }
+ if (rounded > maxValue) {
+ rounded = maxValue;
+ }
+ table[i] = rounded;
+ }
+ return new JPEGQTable(table);
+ }
+
+ /**
+ * Returns the string representation of this JPEGQTable object.
+ *
+ * @return the string representation of this JPEGQTable object.
+ */
+ @Override
+ public String toString() {
+ //-- TODO more informative info
+ return "JPEGQTable";
+ }
+}
diff --git a/awt/javax/imageio/spi/IIORegistry.java b/awt/javax/imageio/spi/IIORegistry.java
new file mode 100644
index 0000000..3c1c989
--- /dev/null
+++ b/awt/javax/imageio/spi/IIORegistry.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.util.Arrays;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi;
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi;
+import org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi;
+import org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi;
+import org.apache.harmony.x.imageio.spi.FileIISSpi;
+import org.apache.harmony.x.imageio.spi.FileIOSSpi;
+import org.apache.harmony.x.imageio.spi.InputStreamIISSpi;
+import org.apache.harmony.x.imageio.spi.OutputStreamIOSSpi;
+import org.apache.harmony.x.imageio.spi.RAFIISSpi;
+import org.apache.harmony.x.imageio.spi.RAFIOSSpi;
+
+/*
+ * @author Rustem V. Rafikov, Viskov Nikolay
+ * @version $Revision: 1.3 $
+ */
+
+/**
+ * The IIORegistry class registers service provider instances
+ * (SPI). Service provider instances are recognized by specific
+ * meta-information in the JAR files containing them. The JAR
+ * files with SPI classes are loaded from the application class
+ * path.
+ */
+public final class IIORegistry extends ServiceRegistry {
+
+ /** The instance. */
+ private static IIORegistry instance;
+
+ /** The Constant CATEGORIES. */
+ private static final Class[] CATEGORIES = new Class[] {
+ javax.imageio.spi.ImageWriterSpi.class,
+ javax.imageio.spi.ImageReaderSpi.class,
+ javax.imageio.spi.ImageInputStreamSpi.class,
+ //javax.imageio.spi.ImageTranscoderSpi.class,
+ javax.imageio.spi.ImageOutputStreamSpi.class
+ };
+
+ /**
+ * Instantiates a new iIO registry.
+ */
+ private IIORegistry() {
+ super(Arrays.<Class<?>>asList(CATEGORIES).iterator());
+ registerBuiltinSpis();
+ registerApplicationClasspathSpis();
+ }
+
+ /**
+ * Register builtin spis.
+ */
+ private void registerBuiltinSpis() {
+ registerServiceProvider(new JPEGImageWriterSpi());
+ registerServiceProvider(new JPEGImageReaderSpi());
+ registerServiceProvider(new PNGImageReaderSpi());
+ registerServiceProvider(new PNGImageWriterSpi());
+ registerServiceProvider(new FileIOSSpi());
+ registerServiceProvider(new FileIISSpi());
+ registerServiceProvider(new RAFIOSSpi());
+ registerServiceProvider(new RAFIISSpi());
+ registerServiceProvider(new OutputStreamIOSSpi());
+ registerServiceProvider(new InputStreamIISSpi());
+ //-- TODO implement
+ }
+
+ /**
+ * Gets the default IIORegistry instance.
+ *
+ * @return the default IIORegistry instance.
+ */
+ public static IIORegistry getDefaultInstance() {
+ // TODO implement own instance for each ThreadGroup (see also ThreadLocal)
+ synchronized (IIORegistry.class) {
+ if (instance == null) {
+ instance = new IIORegistry();
+ }
+ return instance;
+ }
+ }
+
+ /**
+ * Registers all service providers from the application class
+ * path.
+ */
+ public void registerApplicationClasspathSpis() {
+ //-- TODO implement for non-builtin plugins
+ }
+}
diff --git a/awt/javax/imageio/spi/IIOServiceProvider.java b/awt/javax/imageio/spi/IIOServiceProvider.java
new file mode 100644
index 0000000..f5873bf
--- /dev/null
+++ b/awt/javax/imageio/spi/IIOServiceProvider.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.util.Locale;
+
+/**
+ * The IIOServiceProvider abstract class provides base functionality
+ * for imageio service provider interfaces (SPIs).
+ */
+public abstract class IIOServiceProvider implements RegisterableService {
+
+ /** The vendor name of this service provider. */
+ protected String vendorName;
+
+ /** The version of this service provider. */
+ protected String version;
+
+ /**
+ * Instantiates a new IIOServiceProvider.
+ *
+ * @param vendorName the vendor name of service provider.
+ * @param version the version of service provider.
+ */
+ public IIOServiceProvider(String vendorName, String version) {
+ if (vendorName == null) {
+ throw new NullPointerException("vendor name cannot be NULL");
+ }
+ if (version == null) {
+ throw new NullPointerException("version name cannot be NULL");
+ }
+ this.vendorName = vendorName;
+ this.version = version;
+ }
+
+ /**
+ * Instantiates a new IIOServiceProvider.
+ */
+ public IIOServiceProvider() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ public void onRegistration(ServiceRegistry registry, Class<?> category) {
+ // the default impl. does nothing
+ }
+
+ public void onDeregistration(ServiceRegistry registry, Class<?> category) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the vendor name of this service provider.
+ *
+ * @return the vendor name of this service provider.
+ */
+ public String getVendorName() {
+ return vendorName;
+ }
+
+ /**
+ * Gets the version of this service provider.
+ *
+ * @return the version of this service provider.
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Gets a description of this service provider.
+ * The result string should be localized for the specified
+ * Locale.
+ *
+ * @param locale the specified Locale.
+ *
+ * @return the description of this service provider.
+ */
+ public abstract String getDescription(Locale locale);
+}
diff --git a/awt/javax/imageio/spi/ImageInputStreamSpi.java b/awt/javax/imageio/spi/ImageInputStreamSpi.java
new file mode 100644
index 0000000..47d210a
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageInputStreamSpi.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.stream.ImageInputStream;
+
+/**
+ * The ImageInputStreamSpi abstract class is a service provider
+ * interface (SPI) for ImageInputStreams.
+ */
+public abstract class ImageInputStreamSpi extends IIOServiceProvider implements
+ RegisterableService {
+
+ /** The input class. */
+ protected Class<?> inputClass;
+
+ /**
+ * Instantiates a new ImageInputStreamSpi.
+ */
+ protected ImageInputStreamSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageInputStreamSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param inputClass the input class.
+ */
+ public ImageInputStreamSpi(String vendorName, String version, Class<?> inputClass) {
+ super(vendorName, version);
+ this.inputClass = inputClass;
+ }
+
+ /**
+ * Gets an input Class object that represents class or
+ * interface that must be implemented by an input source.
+ *
+ * @return the input class.
+ */
+ public Class<?> getInputClass() {
+ return inputClass;
+ }
+
+ /**
+ * Returns true if the ImageInputStream can use a cache
+ * file. If this method returns false, the value of the
+ * useCache parameter of createInputStreamInstance will
+ * be ignored. The default implementation returns false.
+ *
+ * @return true if the ImageInputStream can use a cache
+ * file, false otherwise.
+ */
+ public boolean canUseCacheFile() {
+ return false; //-- def
+ }
+
+ /**
+ * Returns true if the ImageInputStream implementation
+ * requires the use of a cache file. The default implementation
+ * returns false.
+ *
+ * @return true if the ImageInputStream implementation
+ * requires the use of a cache file, false otherwise.
+ */
+ public boolean needsCacheFile() {
+ return false; // def
+ }
+
+ /**
+ * Creates the ImageInputStream associated with this
+ * service provider. The input object should
+ * be an instance of the class returned by th getInputClass
+ * method. This method uses the specified directory
+ * for the cache file if the useCache parameter is true.
+ *
+ * @param input the input Object.
+ * @param useCache the flag indicating if a cache file
+ * is needed or not.
+ * @param cacheDir the cache directory.
+ *
+ * @return the ImageInputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+ File cacheDir) throws IOException;
+
+ /**
+ * Creates the ImageInputStream associated with this
+ * service provider. The input object should
+ * be an instance of the class returned by getInputClass
+ * method. This method uses the default system directory
+ * for the cache file, if it is needed.
+ *
+ * @param input the input Object.
+ *
+ * @return the ImageInputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageInputStream createInputStreamInstance(Object input) throws IOException {
+ return createInputStreamInstance(input, true, null);
+ }
+}
diff --git a/awt/javax/imageio/spi/ImageOutputStreamSpi.java b/awt/javax/imageio/spi/ImageOutputStreamSpi.java
new file mode 100644
index 0000000..d45e24c
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageOutputStreamSpi.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageOutputStream;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * The ImageOutputStreamSpi abstract class is a service provider
+ * interface (SPI) for ImageOutputStreams.
+ */
+public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements
+ RegisterableService {
+
+ /** The output class. */
+ protected Class<?> outputClass;
+
+ /**
+ * Instantiates a new ImageOutputStreamSpi.
+ */
+ protected ImageOutputStreamSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageOutputStreamSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param outputClass the output class.
+ */
+ public ImageOutputStreamSpi(String vendorName, String version, Class<?> outputClass) {
+ super(vendorName, version);
+ this.outputClass = outputClass;
+ }
+
+ /**
+ * Gets an output Class object that represents the class or
+ * interface that must be implemented by an output source.
+ *
+ * @return the output class.
+ */
+ public Class<?> getOutputClass() {
+ return outputClass;
+ }
+
+ /**
+ * Returns true if the ImageOutputStream can use a cache
+ * file. If this method returns false, the value of the
+ * useCache parameter of createOutputStreamInstance will
+ * be ignored. The default implementation returns false.
+ *
+ * @return true if the ImageOutputStream can use a cache
+ * file, false otherwise.
+ */
+ public boolean canUseCacheFile() {
+ return false; // def
+ }
+
+ /**
+ * Returns true if the ImageOutputStream implementation
+ * requires the use of a cache file. The default implementation
+ * returns false.
+ *
+ * @return true if the ImageOutputStream implementation
+ * requires the use of a cache file, false otherwise.
+ */
+ public boolean needsCacheFile() {
+ return false; // def
+ }
+
+ /**
+ * Creates the ImageOutputStream associated with this
+ * service provider. The output object should
+ * be an instance of the class returned by getOutputClass
+ * method. This method uses the default system directory
+ * for the cache file, if it is needed.
+ *
+ * @param output the output Object.
+ *
+ * @return the ImageOutputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageOutputStream createOutputStreamInstance(Object output) throws IOException {
+ return createOutputStreamInstance(output, true, null);
+ }
+
+ /**
+ * Creates the ImageOutputStream associated with this
+ * service provider. The output object should
+ * be an instance of the class returned by getInputClass
+ * method. This method uses the specified directory
+ * for the cache file, if the useCache parameter is true.
+ *
+ * @param output the output Object.
+ * @param useCache the flag indicating if cache file
+ * is needed or not.
+ * @param cacheDir the cache directory.
+ *
+ * @return the ImageOutputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageOutputStream createOutputStreamInstance(Object output,
+ boolean useCache, File cacheDir) throws IOException;
+}
diff --git a/awt/javax/imageio/spi/ImageReaderSpi.java b/awt/javax/imageio/spi/ImageReaderSpi.java
new file mode 100644
index 0000000..2e2484c
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderSpi.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.ImageReader;
+import java.io.IOException;
+
+/**
+ * The ImageReaderSpi abstract class is a service provider
+ * interface (SPI) for ImageReaders.
+ */
+public abstract class ImageReaderSpi extends ImageReaderWriterSpi {
+
+ /**
+ * The STANDARD_INPUT_TYPE contains ImageInputStream.class.
+ */
+ public static final Class[] STANDARD_INPUT_TYPE = new Class[] {ImageInputStream.class};
+
+ /** The input types. */
+ protected Class[] inputTypes;
+
+ /** The writer SPI names. */
+ protected String[] writerSpiNames;
+
+ /**
+ * Instantiates a new ImageReaderSpi.
+ */
+ protected ImageReaderSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageReaderSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param names the format names.
+ * @param suffixes the array of strings representing the file suffixes.
+ * @param MIMETypes the an array of strings representing MIME types.
+ * @param pluginClassName the plugin class name.
+ * @param inputTypes the input types.
+ * @param writerSpiNames the array of strings with class names of all
+ * associated ImageWriters.
+ * @param supportsStandardStreamMetadataFormat the value indicating
+ * if stream metadata can be described by standart metadata format.
+ * @param nativeStreamMetadataFormatName the native stream metadata
+ * format name, returned by getNativeStreamMetadataFormatName.
+ * @param nativeStreamMetadataFormatClassName the native stream
+ * metadata format class name, returned by getNativeStreamMetadataFormat.
+ * @param extraStreamMetadataFormatNames the extra stream metadata
+ * format names, returned by getExtraStreamMetadataFormatNames.
+ * @param extraStreamMetadataFormatClassNames the extra stream metadata
+ * format class names, returned by getStreamMetadataFormat.
+ * @param supportsStandardImageMetadataFormat the value indicating
+ * if image metadata can be described by standart metadata format.
+ * @param nativeImageMetadataFormatName the native image metadata
+ * format name, returned by getNativeImageMetadataFormatName.
+ * @param nativeImageMetadataFormatClassName the native image
+ * metadata format class name, returned by getNativeImageMetadataFormat.
+ * @param extraImageMetadataFormatNames the extra image metadata
+ * format names, returned by getExtraImageMetadataFormatNames.
+ * @param extraImageMetadataFormatClassNames the extra image metadata
+ * format class names, returned by getImageMetadataFormat.
+ */
+ public ImageReaderSpi(String vendorName, String version, String[] names, String[] suffixes,
+ String[] MIMETypes, String pluginClassName,
+ Class[] inputTypes, String[] writerSpiNames,
+ boolean supportsStandardStreamMetadataFormat,
+ String nativeStreamMetadataFormatName,
+ String nativeStreamMetadataFormatClassName,
+ String[] extraStreamMetadataFormatNames,
+ String[] extraStreamMetadataFormatClassNames,
+ boolean supportsStandardImageMetadataFormat,
+ String nativeImageMetadataFormatName,
+ String nativeImageMetadataFormatClassName,
+ String[] extraImageMetadataFormatNames,
+ String[] extraImageMetadataFormatClassNames) {
+ super(vendorName, version, names, suffixes, MIMETypes, pluginClassName,
+ supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+ nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+ extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames, extraImageMetadataFormatClassNames);
+
+ if (inputTypes == null || inputTypes.length == 0) {
+ throw new NullPointerException("input types array cannot be NULL or empty");
+ }
+ this.inputTypes = inputTypes;
+ this.writerSpiNames = writerSpiNames;
+ }
+
+ /**
+ * Gets an array of Class objects whose types can be used
+ * as input for this reader.
+ *
+ * @return the input types.
+ */
+ public Class[] getInputTypes() {
+ return inputTypes;
+ }
+
+ /**
+ * Returns true if the format of source object is
+ * supported by this reader.
+ *
+ * @param source the source object to be decoded
+ * (for example an ImageInputStream).
+ *
+ * @return true if the format of source object is
+ * supported by this reader, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract boolean canDecodeInput(Object source) throws IOException;
+
+ /**
+ * Returns an instance of the ImageReader implementation for
+ * this service provider.
+ *
+ * @return the ImageReader.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageReader createReaderInstance() throws IOException {
+ return createReaderInstance(null);
+ }
+
+ /**
+ * Returns an instance of the ImageReader implementation for
+ * this service provider.
+ *
+ * @param extension the a plugin specific extension object, or null.
+ *
+ * @return the ImageReader.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageReader createReaderInstance(Object extension) throws IOException;
+
+ /**
+ * Checks whether or not the specified ImageReader object
+ * is an instance of the ImageReader associated with this
+ * service provider or not.
+ *
+ * @param reader the ImageReader.
+ *
+ * @return true, if the specified ImageReader object
+ * is an instance of the ImageReader associated with this
+ * service provider, false otherwise.
+ */
+ public boolean isOwnReader(ImageReader reader) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of strings with names of the ImageWriterSpi
+ * classes that support the internal metadata representation
+ * used by the ImageReader of this service provider, or null if
+ * there are no such ImageWriters.
+ *
+ * @return an array of strings with names of the ImageWriterSpi
+ * classes.
+ */
+ public String[] getImageWriterSpiNames() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+}
diff --git a/awt/javax/imageio/spi/ImageReaderWriterSpi.java b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
new file mode 100644
index 0000000..b3c0f92
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils;
+
+import javax.imageio.metadata.IIOMetadataFormat;
+
+/**
+ * The ImageReaderWriterSpi class is a superclass for the
+ * ImageReaderSpi and ImageWriterSpi SPIs.
+ */
+public abstract class ImageReaderWriterSpi extends IIOServiceProvider
+ implements RegisterableService {
+
+ /** The names. */
+ protected String[] names;
+
+ /** The suffixes. */
+ protected String[] suffixes;
+
+ /** The MIME types. */
+ protected String[] MIMETypes;
+
+ /** The plugin class name. */
+ protected String pluginClassName;
+
+ /** Whether the reader/writer supports standard stream metadata format. */
+ protected boolean supportsStandardStreamMetadataFormat;
+
+ /** The native stream metadata format name. */
+ protected String nativeStreamMetadataFormatName;
+
+ /** The native stream metadata format class name. */
+ protected String nativeStreamMetadataFormatClassName;
+
+ /** The extra stream metadata format names. */
+ protected String[] extraStreamMetadataFormatNames;
+
+ /** The extra stream metadata format class names. */
+ protected String[] extraStreamMetadataFormatClassNames;
+
+ /** Whether the reader/writer supports standard image metadata format. */
+ protected boolean supportsStandardImageMetadataFormat;
+
+ /** The native image metadata format name. */
+ protected String nativeImageMetadataFormatName;
+
+ /** The native image metadata format class name. */
+ protected String nativeImageMetadataFormatClassName;
+
+ /** The extra image metadata format names. */
+ protected String[] extraImageMetadataFormatNames;
+
+ /** The extra image metadata format class names. */
+ protected String[] extraImageMetadataFormatClassNames;
+
+ /**
+ * Instantiates a new ImageReaderWriterSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param names the format names.
+ * @param suffixes the array of strings representing the file suffixes.
+ * @param MIMETypes the an array of strings representing MIME types.
+ * @param pluginClassName the plugin class name.
+ * @param supportsStandardStreamMetadataFormat the value indicating
+ * if stream metadata can be described by standart metadata format.
+ * @param nativeStreamMetadataFormatName the native stream metadata
+ * format name, returned by getNativeStreamMetadataFormatName.
+ * @param nativeStreamMetadataFormatClassName the native stream
+ * metadata format class name, returned by getNativeStreamMetadataFormat.
+ * @param extraStreamMetadataFormatNames the extra stream metadata
+ * format names, returned by getExtraStreamMetadataFormatNames.
+ * @param extraStreamMetadataFormatClassNames the extra stream metadata
+ * format class names, returned by getStreamMetadataFormat.
+ * @param supportsStandardImageMetadataFormat the value indicating
+ * if image metadata can be described by standard metadata format.
+ * @param nativeImageMetadataFormatName the native image metadata
+ * format name, returned by getNativeImageMetadataFormatName.
+ * @param nativeImageMetadataFormatClassName the native image
+ * metadata format class name, returned by getNativeImageMetadataFormat.
+ * @param extraImageMetadataFormatNames the extra image metadata
+ * format names, returned by getExtraImageMetadataFormatNames.
+ * @param extraImageMetadataFormatClassNames the extra image metadata
+ * format class names, returned by getImageMetadataFormat.
+ */
+ public ImageReaderWriterSpi(String vendorName, String version, String[] names,
+ String[] suffixes, String[] MIMETypes,
+ String pluginClassName,
+ boolean supportsStandardStreamMetadataFormat,
+ String nativeStreamMetadataFormatName,
+ String nativeStreamMetadataFormatClassName,
+ String[] extraStreamMetadataFormatNames,
+ String[] extraStreamMetadataFormatClassNames,
+ boolean supportsStandardImageMetadataFormat,
+ String nativeImageMetadataFormatName,
+ String nativeImageMetadataFormatClassName,
+ String[] extraImageMetadataFormatNames,
+ String[] extraImageMetadataFormatClassNames) {
+ super(vendorName, version);
+
+ if (names == null || names.length == 0) {
+ throw new NullPointerException("format names array cannot be NULL or empty");
+ }
+
+ if (pluginClassName == null) {
+ throw new NullPointerException("Plugin class name cannot be NULL");
+ }
+
+ // We clone all the arrays to be consistent with the fact that
+ // some methods of this class must return clones of the arrays
+ // as it is stated in the spec.
+ this.names = names.clone();
+ this.suffixes = suffixes == null ? null : suffixes.clone();
+ this.MIMETypes = MIMETypes == null ? null : MIMETypes.clone();
+ this.pluginClassName = pluginClassName;
+ this.supportsStandardStreamMetadataFormat = supportsStandardStreamMetadataFormat;
+ this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
+ this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName;
+
+ this.extraStreamMetadataFormatNames =
+ extraStreamMetadataFormatNames == null ?
+ null : extraStreamMetadataFormatNames.clone();
+
+ this.extraStreamMetadataFormatClassNames =
+ extraStreamMetadataFormatClassNames == null ?
+ null : extraStreamMetadataFormatClassNames.clone();
+
+ this.supportsStandardImageMetadataFormat = supportsStandardImageMetadataFormat;
+ this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
+ this.nativeImageMetadataFormatClassName = nativeImageMetadataFormatClassName;
+
+ this.extraImageMetadataFormatNames =
+ extraImageMetadataFormatNames == null ?
+ null : extraImageMetadataFormatNames.clone();
+
+ this.extraImageMetadataFormatClassNames =
+ extraImageMetadataFormatClassNames == null ?
+ null : extraImageMetadataFormatClassNames.clone();
+ }
+
+ /**
+ * Instantiates a new ImageReaderWriterSpi.
+ */
+ public ImageReaderWriterSpi() {}
+
+ /**
+ * Gets an array of strings representing names of the formats
+ * that can be used by the ImageReader
+ * or ImageWriter implementation associated with this service
+ * provider.
+ *
+ * @return an array of supported format names.
+ */
+ public String[] getFormatNames() {
+ return names.clone();
+ }
+
+ /**
+ * Gets an array of strings representing file suffixes
+ * associated with the formats that can be used by the
+ * ImageReader or ImageWriter implementation of this
+ * service provider.
+ *
+ * @return an array of file suffixes.
+ */
+ public String[] getFileSuffixes() {
+ return suffixes == null ? null : suffixes.clone();
+ }
+
+ /**
+ * Gets an array of strings with the names of
+ * additional formats of the image metadata objects
+ * produced or consumed by this plug-in.
+ *
+ * @return the array of extra image metadata format names.
+ */
+ public String[] getExtraImageMetadataFormatNames() {
+ return extraImageMetadataFormatNames == null ? null : extraImageMetadataFormatNames.clone();
+ }
+
+ /**
+ * Gets an array of strings with the names of
+ * additional formats of the stream metadata objects
+ * produced or consumed by this plug-in.
+ *
+ * @return the array of extra stream metadata format names.
+ */
+ public String[] getExtraStreamMetadataFormatNames() {
+ return extraStreamMetadataFormatNames == null ? null : extraStreamMetadataFormatNames.clone();
+ }
+
+ /**
+ * Gets an IIOMetadataFormat object for the specified image
+ * metadata format name.
+ *
+ * @param formatName the format name.
+ *
+ * @return the IIOMetadataFormat, or null.
+ */
+ public IIOMetadataFormat getImageMetadataFormat(String formatName) {
+ return IIOMetadataUtils.instantiateMetadataFormat(
+ formatName, supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames, extraImageMetadataFormatClassNames
+ );
+ }
+
+ /**
+ * Gets an IIOMetadataFormat object for the specified stream
+ * metadata format name.
+ *
+ * @param formatName the format name.
+ *
+ * @return the IIOMetadataFormat, or null.
+ */
+ public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
+ return IIOMetadataUtils.instantiateMetadataFormat(
+ formatName, supportsStandardStreamMetadataFormat,
+ nativeStreamMetadataFormatName, nativeStreamMetadataFormatClassName,
+ extraStreamMetadataFormatNames, extraStreamMetadataFormatClassNames
+ );
+ }
+
+ /**
+ * Gets an array of strings representing the MIME types
+ * of the formats that are supported by the
+ * ImageReader or ImageWriter implementation of this
+ * service provider.
+ *
+ * @return the array MIME types.
+ */
+ public String[] getMIMETypes() {
+ return MIMETypes == null ? null : MIMETypes.clone();
+ }
+
+ /**
+ * Gets the name of the native image metadata format for
+ * this reader/writer, which allows for lossless encoding
+ * or decoding of the image metadata with the format.
+ *
+ * @return the string with native image metadata format name,
+ * or null.
+ */
+ public String getNativeImageMetadataFormatName() {
+ return nativeImageMetadataFormatName;
+ }
+
+ /**
+ * Gets the name of the native stream metadata format for
+ * this reader/writer, which allows for lossless encoding
+ * or decoding of the stream metadata with the format.
+ *
+ * @return the string with native stream metadata format name,
+ * or null.
+ */
+ public String getNativeStreamMetadataFormatName() {
+ return nativeStreamMetadataFormatName;
+ }
+
+ /**
+ * Gets the class name of the ImageReader
+ * or ImageWriter associated with this service provider.
+ *
+ * @return the class name.
+ */
+ public String getPluginClassName() {
+ return pluginClassName;
+ }
+
+ /**
+ * Checks if the standard metadata format is supported
+ * by the getAsTree and setFromTree methods for the
+ * image metadata objects produced or consumed by this
+ * reader or writer.
+ *
+ * @return true, if standard image metadata format is
+ * supported, false otherwise.
+ */
+ public boolean isStandardImageMetadataFormatSupported() {
+ return supportsStandardImageMetadataFormat;
+ }
+
+ /**
+ * Checks if the standard metadata format is supported
+ * by the getAsTree and setFromTree methods for the
+ * stream metadata objects produced or consumed by this
+ * reader or writer.
+ *
+ * @return true, if standard stream metadata format is
+ * supported, false otherwise.
+ */
+ public boolean isStandardStreamMetadataFormatSupported() {
+ return supportsStandardStreamMetadataFormat;
+ }
+}
diff --git a/awt/javax/imageio/spi/ImageTranscoderSpi.java b/awt/javax/imageio/spi/ImageTranscoderSpi.java
new file mode 100644
index 0000000..68c4024
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageTranscoderSpi.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.ImageTranscoder;
+
+/**
+ * The ImageTranscoderSpi class is a service provider interface (SPI)
+ * for ImageTranscoders.
+ */
+public abstract class ImageTranscoderSpi extends IIOServiceProvider
+ implements RegisterableService {
+
+ /**
+ * Instantiates a new ImageTranscoderSpi.
+ */
+ protected ImageTranscoderSpi() {
+ }
+
+ /**
+ * Instantiates a new ImageTranscoderSpi with the specified
+ * vendor name and version.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ */
+ public ImageTranscoderSpi(String vendorName, String version) {
+ super(vendorName, version);
+ }
+
+ /**
+ * Gets the class name of an ImageReaderSpi that
+ * produces IIOMetadata objects that can be used as
+ * input to this transcoder.
+ *
+ * @return the class name of an ImageReaderSpi.
+ */
+ public abstract String getReaderServiceProviderName();
+
+ /**
+ * Gets the class name of an ImageWriterSpi that
+ * produces IIOMetadata objects that can be used as
+ * input to this transcoder.
+ *
+ * @return the class name of an ImageWriterSpi.
+ */
+ public abstract String getWriterServiceProviderName();
+
+ /**
+ * Creates an instance of the ImageTranscoder associated
+ * with this service provider.
+ *
+ * @return the ImageTranscoder instance.
+ */
+ public abstract ImageTranscoder createTranscoderInstance();
+}
diff --git a/awt/javax/imageio/spi/ImageWriterSpi.java b/awt/javax/imageio/spi/ImageWriterSpi.java
new file mode 100644
index 0000000..979ef77
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageWriterSpi.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+/**
+ * The ImageWriterSpi abstract class is a service provider
+ * interface (SPI) for ImageWriters.
+ */
+public abstract class ImageWriterSpi extends ImageReaderWriterSpi {
+
+ /** The STANDARD_OUTPUT_TYPE contains ImageInputStream.class. */
+ public static final Class[] STANDARD_OUTPUT_TYPE = new Class[] {ImageInputStream.class};
+
+ /** The output types. */
+ protected Class[] outputTypes;
+
+ /** The reader spi names. */
+ protected String[] readerSpiNames;
+
+ /**
+ * Instantiates a new ImageWriterSpi.
+ */
+ protected ImageWriterSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageWriterSpi with the specified parameters.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param names the format names.
+ * @param suffixes the array of strings representing the file suffixes.
+ * @param MIMETypes the an array of strings representing MIME types.
+ * @param pluginClassName the plugin class name.
+ * @param outputTypes the output types.
+ * @param readerSpiNames the array of strings with class names of all
+ * associated ImageReaders.
+ * @param supportsStandardStreamMetadataFormat the value indicating
+ * if stream metadata can be described by standard metadata format.
+ * @param nativeStreamMetadataFormatName the native stream metadata
+ * format name, returned by getNativeStreamMetadataFormatName.
+ * @param nativeStreamMetadataFormatClassName the native stream
+ * metadata format class name, returned by getNativeStreamMetadataFormat.
+ * @param extraStreamMetadataFormatNames the extra stream metadata
+ * format names, returned by getExtraStreamMetadataFormatNames.
+ * @param extraStreamMetadataFormatClassNames the extra stream metadata
+ * format class names, returned by getStreamMetadataFormat.
+ * @param supportsStandardImageMetadataFormat the value indicating
+ * if image metadata can be described by standard metadata format.
+ * @param nativeImageMetadataFormatName the native image metadata
+ * format name, returned by getNativeImageMetadataFormatName.
+ * @param nativeImageMetadataFormatClassName the native image
+ * metadata format class name, returned by getNativeImageMetadataFormat.
+ * @param extraImageMetadataFormatNames the extra image metadata
+ * format names, returned by getExtraImageMetadataFormatNames.
+ * @param extraImageMetadataFormatClassNames the extra image metadata
+ * format class names, returned by getImageMetadataFormat.
+ */
+ public ImageWriterSpi(String vendorName, String version, String[] names,
+ String[] suffixes, String[] MIMETypes,
+ String pluginClassName,
+ Class[] outputTypes, String[] readerSpiNames,
+ boolean supportsStandardStreamMetadataFormat,
+ String nativeStreamMetadataFormatName,
+ String nativeStreamMetadataFormatClassName,
+ String[] extraStreamMetadataFormatNames,
+ String[] extraStreamMetadataFormatClassNames,
+ boolean supportsStandardImageMetadataFormat,
+ String nativeImageMetadataFormatName,
+ String nativeImageMetadataFormatClassName,
+ String[] extraImageMetadataFormatNames,
+ String[] extraImageMetadataFormatClassNames) {
+ super(vendorName, version, names, suffixes, MIMETypes, pluginClassName,
+ supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+ nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+ extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames, extraImageMetadataFormatClassNames);
+
+ if (outputTypes == null || outputTypes.length == 0) {
+ throw new NullPointerException("output types array cannot be NULL or empty");
+ }
+
+ this.outputTypes = outputTypes;
+ this.readerSpiNames = readerSpiNames;
+ }
+
+ /**
+ * Returns true if the format of the writer's output is lossless.
+ * The default implementation returns true.
+ *
+ * @return true, if a format is lossless, false otherwise.
+ */
+ public boolean isFormatLossless() {
+ return true;
+ }
+
+ /**
+ * Gets an array of Class objects whose types
+ * can be used as output for this writer.
+ *
+ * @return the output types.
+ */
+ public Class[] getOutputTypes() {
+ return outputTypes;
+ }
+
+ /**
+ * Checks whether or not the ImageWriter implementation associated
+ * with this service provider can encode an image with
+ * the specified type.
+ *
+ * @param type the ImageTypeSpecifier.
+ *
+ * @return true, if an image with the specified type can be
+ * encoded, false otherwise.
+ */
+ public abstract boolean canEncodeImage(ImageTypeSpecifier type);
+
+ /**
+ * Checks whether or not the ImageWriter implementation associated
+ * with this service provider can encode the specified RenderedImage.
+ *
+ * @param im the RenderedImage.
+ *
+ * @return true, if RenderedImage can be encoded,
+ * false otherwise.
+ */
+ public boolean canEncodeImage(RenderedImage im) {
+ return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im));
+ }
+
+ /**
+ * Returns an instance of the ImageWriter implementation for
+ * this service provider.
+ *
+ * @return the ImageWriter.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageWriter createWriterInstance() throws IOException {
+ return createWriterInstance(null);
+ }
+
+ /**
+ * Returns an instance of the ImageWriter implementation for
+ * this service provider.
+ *
+ * @param extension the a plugin specific extension object, or null.
+ *
+ * @return the ImageWriter.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageWriter createWriterInstance(Object extension) throws IOException;
+
+ /**
+ * Checks whether or not the specified ImageWriter object
+ * is an instance of the ImageWriter associated with this
+ * service provider or not.
+ *
+ * @param writer the ImageWriter.
+ *
+ * @return true, if the specified ImageWriter object
+ * is an instance of the ImageWriter associated with this
+ * service provider, false otherwise.
+ */
+ public boolean isOwnWriter(ImageWriter writer) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of strings with names of the ImageReaderSpi
+ * classes that support the internal metadata representation
+ * used by the ImageWriter of this service provider, or null if
+ * there are no such ImageReaders.
+ *
+ * @return an array of strings with names of the ImageWriterSpi
+ * classes.
+ */
+ public String[] getImageReaderSpiNames() {
+ return readerSpiNames;
+ }
+}
diff --git a/awt/javax/imageio/spi/RegisterableService.java b/awt/javax/imageio/spi/RegisterableService.java
new file mode 100644
index 0000000..b50754e
--- /dev/null
+++ b/awt/javax/imageio/spi/RegisterableService.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+/**
+ * The RegisterableService interface provides service provider
+ * objects that can be registered by a ServiceRegistry, and
+ * notifications that registration and deregistration have been
+ * performed.
+ */
+public interface RegisterableService {
+
+ /**
+ * This method is called when the object which implements this
+ * interface is registered to the specified category of the
+ * specified registry.
+ *
+ * @param registry the ServiceRegistry to be registered.
+ * @param category the class representing a category.
+ */
+ void onRegistration(ServiceRegistry registry, Class<?> category);
+
+ /**
+ * This method is called when the object which implements this
+ * interface is deregistered to the specified category of the
+ * specified registry.
+ *
+ * @param registry the ServiceRegistry to be registered.
+ * @param category the class representing a category.
+ */
+ void onDeregistration(ServiceRegistry registry, Class<?> category);
+}
diff --git a/awt/javax/imageio/spi/ServiceRegistry.java b/awt/javax/imageio/spi/ServiceRegistry.java
new file mode 100644
index 0000000..1a18b02
--- /dev/null
+++ b/awt/javax/imageio/spi/ServiceRegistry.java
@@ -0,0 +1,516 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * The ServiceRegistry class provides ability to register,
+ * deregister, look up and obtain service provider instances (SPIs).
+ * A service means a set of interfaces and classes, and a service
+ * provider is an implementation of a service. Service providers can
+ * be associated with one or more categories. Each category is defined
+ * by a class or interface. Only a single instance of a each class is
+ * allowed to be registered as a category.
+ */
+public class ServiceRegistry {
+
+ /** The categories. */
+ CategoriesMap categories = new CategoriesMap(this);
+
+ /**
+ * Instantiates a new ServiceRegistry with the specified categories.
+ *
+ * @param categoriesIterator an Iterator of Class objects
+ * for defining of categories.
+ */
+ public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
+ if (null == categoriesIterator) {
+ throw new IllegalArgumentException("categories iterator should not be NULL");
+ }
+ while(categoriesIterator.hasNext()) {
+ Class<?> c = categoriesIterator.next();
+ categories.addCategory(c);
+ }
+ }
+
+ /**
+ * Looks up and instantiates the available providers of this service using
+ * the specified class loader.
+ *
+ * @param providerClass the Class object of the provider to be looked up.
+ * @param loader the class loader to be used.
+ *
+ * @return the iterator of providers objects for this service.
+ */
+ public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Looks up and instantiates the available providers of this service using
+ * the context class loader.
+ *
+ * @param providerClass the Class object of the provider to be looked up.
+ *
+ * @return the iterator of providers objects for this service.
+ */
+ public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
+ return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * Registers the specified service provider object in the
+ * specified categories.
+ *
+ * @param provider the specified provider to be registered.
+ * @param category the category.
+ *
+ * @return true if no provider of the same class is registered
+ * in this category, false otherwise.
+ */
+ public <T> boolean registerServiceProvider(T provider, Class<T> category) {
+ return categories.addProvider(provider, category);
+ }
+
+ /**
+ * Registers a list of service providers.
+ *
+ * @param providers the list of service providers.
+ */
+ public void registerServiceProviders(Iterator<?> providers) {
+ for (Iterator<?> iterator = providers; iterator.hasNext();) {
+ categories.addProvider(iterator.next(), null);
+ }
+ }
+
+ /**
+ * Registers the specified service provider object in all
+ * categories.
+ *
+ * @param provider the service provider.
+ */
+ public void registerServiceProvider(Object provider) {
+ categories.addProvider(provider, null);
+ }
+
+ /**
+ * Deregisters the specifies service provider from the
+ * specified category.
+ *
+ * @param provider the service provider to be deregistered.
+ * @param category the specified category.
+ *
+ * @return true if the provider was already registered
+ * in the specified category, false otherwise.
+ */
+ public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Deregisters the specified service provider from all
+ * categories.
+ *
+ * @param provider the specified service provider.
+ */
+ public void deregisterServiceProvider(Object provider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an Iterator of registered service providers
+ * in the specified category which satisfy the specified Filter.
+ * The useOrdering parameter indicates whether the iterator will
+ * return all of the server provider objects in a set order.
+ *
+ * @param category the specified category.
+ * @param filter the specified filter.
+ * @param useOrdering the flag indicating that providers are ordered
+ * in the returned Iterator.
+ *
+ * @return the iterator of registered service providers.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
+ return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category, useOrdering));
+ }
+
+ /**
+ * Gets an Iterator of all registered service providers
+ * in the specified category. The useOrdering parameter
+ * indicates whether the iterator will return all of the server
+ * provider objects in a set order.
+ *
+ * @param category the specified category.
+ * @param useOrdering the flag indicating that providers are ordered
+ * in the returned Iterator.
+ *
+ * @return the Iterator of service providers.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) {
+ return (Iterator<T>)categories.getProviders(category, useOrdering);
+ }
+
+ /**
+ * Gets the registered service provider object that has the
+ * specified class type.
+ *
+ * @param providerClass the specified provider class.
+ *
+ * @return the service provider object.
+ */
+ public <T> T getServiceProviderByClass(Class<T> providerClass) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Sets an ordering between two service provider objects
+ * within the specified category.
+ *
+ * @param category the specified category.
+ * @param firstProvider the first provider.
+ * @param secondProvider the second provider.
+ *
+ * @return true if a previously unset order was set.
+ */
+ public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Unsets an ordering between two service provider objects
+ * within the specified category.
+ *
+ * @param category the specified category.
+ * @param firstProvider the first provider.
+ * @param secondProvider the second provider.
+ *
+ * @return true if a previously unset order was removed.
+ */
+ public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Deregisters all providers from the specified category.
+ *
+ * @param category the specified category.
+ */
+ public void deregisterAll(Class<?> category) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Deregister all providers from all categories.
+ */
+ public void deregisterAll() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Finalizes this object.
+ *
+ * @throws Throwable throws if an error occurs during
+ * finalization.
+ */
+ @Override
+ public void finalize() throws Throwable {
+ //TODO uncomment when deregisterAll is implemented
+ //deregisterAll();
+ }
+
+ /**
+ * Checks whether the specified provider has been already registered.
+ *
+ * @param provider the provider to be checked.
+ *
+ * @return true, if the specified provider has been already registered,
+ * false otherwise.
+ */
+ public boolean contains(Object provider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an iterator of Class objects representing the current
+ * categories.
+ *
+ * @return the Iterator of Class objects.
+ */
+ public Iterator<Class<?>> getCategories() {
+ return categories.list();
+ }
+
+ /**
+ * The ServiceRegistry.Filter interface is used by
+ * ServiceRegistry.getServiceProviders to filter providers according
+ * to the specified criterion.
+ */
+ public static interface Filter {
+
+ /**
+ * Returns true if the specified provider satisfies the
+ * criterion of this Filter.
+ *
+ * @param provider the provider.
+ *
+ * @return true if the specified provider satisfies the
+ * criterion of this Filter, false otherwise.
+ */
+ boolean filter(Object provider);
+ }
+
+ /**
+ * The Class CategoriesMap.
+ */
+ private static class CategoriesMap {
+
+ /** The categories. */
+ Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
+
+ /** The registry. */
+ ServiceRegistry registry;
+
+ /**
+ * Instantiates a new categories map.
+ *
+ * @param registry the registry
+ */
+ public CategoriesMap(ServiceRegistry registry) {
+ this.registry = registry;
+ }
+
+ //-- TODO: useOrdering
+ /**
+ * Gets the providers.
+ *
+ * @param category the category
+ * @param useOrdering the use ordering
+ *
+ * @return the providers
+ */
+ Iterator<?> getProviders(Class<?> category, boolean useOrdering) {
+ ProvidersMap providers = categories.get(category);
+ if (null == providers) {
+ throw new IllegalArgumentException("Unknown category: " + category);
+ }
+ return providers.getProviders(useOrdering);
+ }
+
+ /**
+ * List.
+ *
+ * @return the iterator< class<?>>
+ */
+ Iterator<Class<?>> list() {
+ return categories.keySet().iterator();
+ }
+
+ /**
+ * Adds the category.
+ *
+ * @param category the category
+ */
+ void addCategory(Class<?> category) {
+ categories.put(category, new ProvidersMap());
+ }
+
+ /**
+ * Adds a provider to the category. If <code>category</code> is
+ * <code>null</code> then the provider will be added to all categories
+ * which the provider is assignable from.
+ *
+ * @param provider provider to add
+ * @param category category to add provider to
+ *
+ * @return if there were such provider in some category
+ */
+ boolean addProvider(Object provider, Class<?> category) {
+ if (provider == null) {
+ throw new IllegalArgumentException("provider should be != NULL");
+ }
+
+ boolean rt;
+ if (category == null) {
+ rt = findAndAdd(provider);
+ } else {
+ rt = addToNamed(provider, category);
+ }
+
+ if (provider instanceof RegisterableService) {
+ ((RegisterableService) provider).onRegistration(registry, category);
+ }
+
+ return rt;
+ }
+
+ /**
+ * Adds the to named.
+ *
+ * @param provider the provider
+ * @param category the category
+ *
+ * @return true, if successful
+ */
+ private boolean addToNamed(Object provider, Class<?> category) {
+ Object obj = categories.get(category);
+
+ if (null == obj) {
+ throw new IllegalArgumentException("Unknown category: " + category);
+ }
+
+ return ((ProvidersMap) obj).addProvider(provider);
+ }
+
+ /**
+ * Find and add.
+ *
+ * @param provider the provider
+ *
+ * @return true, if successful
+ */
+ private boolean findAndAdd(Object provider) {
+ boolean rt = false;
+ for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) {
+ if (e.getKey().isAssignableFrom(provider.getClass())) {
+ rt |= e.getValue().addProvider(provider);
+ }
+ }
+ return rt;
+ }
+ }
+
+ /**
+ * The Class ProvidersMap.
+ */
+ private static class ProvidersMap {
+ //-- TODO: providers ordering support
+
+ /** The providers. */
+ Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
+
+ /**
+ * Adds the provider.
+ *
+ * @param provider the provider
+ *
+ * @return true, if successful
+ */
+ boolean addProvider(Object provider) {
+ return providers.put(provider.getClass(), provider) != null;
+ }
+
+ /**
+ * Gets the provider classes.
+ *
+ * @return the provider classes
+ */
+ Iterator<Class<?>> getProviderClasses() {
+ return providers.keySet().iterator();
+ }
+
+ //-- TODO ordering
+ /**
+ * Gets the providers.
+ *
+ * @param userOrdering the user ordering
+ *
+ * @return the providers
+ */
+ Iterator<?> getProviders(boolean userOrdering) {
+ return providers.values().iterator();
+ }
+ }
+
+ /**
+ * The Class FilteredIterator.
+ */
+ private static class FilteredIterator<E> implements Iterator<E> {
+
+ /** The filter. */
+ private Filter filter;
+
+ /** The backend. */
+ private Iterator<E> backend;
+
+ /** The next obj. */
+ private E nextObj;
+
+ /**
+ * Instantiates a new filtered iterator.
+ *
+ * @param filter the filter
+ * @param backend the backend
+ */
+ public FilteredIterator(Filter filter, Iterator<E> backend) {
+ this.filter = filter;
+ this.backend = backend;
+ findNext();
+ }
+
+ /**
+ * Next.
+ *
+ * @return the e
+ */
+ public E next() {
+ if (nextObj == null) {
+ throw new NoSuchElementException();
+ }
+ E tmp = nextObj;
+ findNext();
+ return tmp;
+ }
+
+ /**
+ * Checks for next.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNext() {
+ return nextObj != null;
+ }
+
+ /**
+ * Removes the.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets nextObj to a next provider matching the criterion given by the filter.
+ */
+ private void findNext() {
+ nextObj = null;
+ while (backend.hasNext()) {
+ E o = backend.next();
+ if (filter.filter(o)) {
+ nextObj = o;
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/awt/javax/imageio/stream/FileCacheImageInputStream.java b/awt/javax/imageio/stream/FileCacheImageInputStream.java
new file mode 100644
index 0000000..47bc189
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageInputStream.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import java.io.*;
+
+/**
+ * The FileCacheImageInputStream class is an implementation of
+ * ImageInputStream which reads from its InputStream
+ * and uses a temporary file as a cache.
+ */
+public class FileCacheImageInputStream extends ImageInputStreamImpl {
+
+ /** The is. */
+ private InputStream is;
+
+ /** The file. */
+ private File file;
+
+ /** The raf. */
+ private RandomAccessFile raf;
+
+
+ /**
+ * Instantiates a new FileCacheImageInputStream from
+ * the specified InputStream and using the specified
+ * File as its cache directory.
+ *
+ * @param stream the InputStream for reading.
+ * @param cacheDir the cache directory where the chache file
+ * will be created.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public FileCacheImageInputStream(InputStream stream, File cacheDir) throws IOException {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ is = stream;
+
+ if (cacheDir == null || cacheDir.isDirectory()) {
+ file = File.createTempFile(FileCacheImageOutputStream.IIO_TEMP_FILE_PREFIX, null, cacheDir);
+ file.deleteOnExit();
+ } else {
+ throw new IllegalArgumentException("Not a directory!");
+ }
+
+ raf = new RandomAccessFile(file, "rw");
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= raf.length()) {
+ int b = is.read();
+
+ if (b < 0) {
+ return -1;
+ }
+
+ raf.seek(streamPos++);
+ raf.write(b);
+ return b;
+ }
+
+ raf.seek(streamPos++);
+ return raf.read();
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= raf.length()) {
+ int nBytes = is.read(b, off, len);
+
+ if (nBytes < 0) {
+ return -1;
+ }
+
+ raf.seek(streamPos);
+ raf.write(b, off, nBytes);
+ streamPos += nBytes;
+ return nBytes;
+ }
+
+ raf.seek(streamPos);
+ int nBytes = raf.read(b, off, len);
+ streamPos += nBytes;
+ return nBytes;
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ raf.close();
+ file.delete();
+ }
+}
diff --git a/awt/javax/imageio/stream/FileCacheImageOutputStream.java b/awt/javax/imageio/stream/FileCacheImageOutputStream.java
new file mode 100644
index 0000000..ae48585
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageOutputStream.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+/**
+ * The FileCacheImageOutputStream class is an implementation of
+ * ImageOutputStream that writes to its OutputStream
+ * using a temporary file as a cache.
+ */
+public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
+
+ /** The Constant IIO_TEMP_FILE_PREFIX. */
+ static final String IIO_TEMP_FILE_PREFIX = "iioCache";
+
+ /** The Constant MAX_BUFFER_LEN. */
+ static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much?
+
+ /** The os. */
+ private OutputStream os;
+
+ /** The file. */
+ private File file;
+
+ /** The raf. */
+ private RandomAccessFile raf;
+
+ /**
+ * Instantiates a FileCacheImageOutputStream.
+ *
+ * @param stream the OutputStream for writing.
+ * @param cacheDir the cache directory where the chache file
+ * will be created.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ os = stream;
+
+ if (cacheDir == null || cacheDir.isDirectory()) {
+ file = File.createTempFile(IIO_TEMP_FILE_PREFIX, null, cacheDir);
+ file.deleteOnExit();
+ } else {
+ throw new IllegalArgumentException("Not a directory!");
+ }
+
+ raf = new RandomAccessFile(file, "rw");
+ }
+
+ @Override
+ public void close() throws IOException {
+ flushBefore(raf.length());
+ super.close();
+ raf.close();
+ file.delete();
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return false;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ raf.write(b);
+ streamPos++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ raf.write(b, off, len);
+ streamPos += len;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0; // Should reset
+
+ int res = raf.read();
+ if (res >= 0) {
+ streamPos++;
+ }
+
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ int numRead = raf.read(b, off, len);
+ if (numRead > 0) {
+ streamPos += numRead;
+ }
+
+ return numRead;
+ }
+
+ @Override
+ public void flushBefore(long pos) throws IOException {
+ long readFromPos = flushedPos;
+ super.flushBefore(pos);
+
+ long bytesToRead = pos - readFromPos;
+ raf.seek(readFromPos);
+
+ if (bytesToRead < MAX_BUFFER_LEN) {
+ byte buffer[] = new byte[(int)bytesToRead];
+ raf.readFully(buffer);
+ os.write(buffer);
+ } else {
+ byte buffer[] = new byte[MAX_BUFFER_LEN];
+ while (bytesToRead > 0) {
+ int count = (int) Math.min(MAX_BUFFER_LEN, bytesToRead);
+ raf.readFully(buffer, 0, count);
+ os.write(buffer, 0, count);
+ bytesToRead -= count;
+ }
+ }
+
+ os.flush();
+
+ if (pos != streamPos) {
+ raf.seek(streamPos); // Reset the position
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ if (pos < flushedPos) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ raf.seek(pos);
+ streamPos = raf.getFilePointer();
+ bitOffset = 0;
+ }
+
+ @Override
+ public long length() {
+ try {
+ return raf.length();
+ } catch(IOException e) {
+ return -1L;
+ }
+ }
+}
diff --git a/awt/javax/imageio/stream/FileImageInputStream.java b/awt/javax/imageio/stream/FileImageInputStream.java
new file mode 100644
index 0000000..6680ae0
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageInputStream.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * The FileImageInputStream class implements ImageInputStream
+ * and obtains its input data from a File or RandomAccessFile.
+ */
+public class FileImageInputStream extends ImageInputStreamImpl {
+
+ /** The raf. */
+ RandomAccessFile raf;
+
+ /**
+ * Instantiates a new FileImageInputStream from the specified File.
+ *
+ * @param f the File of input data.
+ *
+ * @throws FileNotFoundException if the specified file
+ * doesn't exist.
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @SuppressWarnings({"DuplicateThrows"})
+ public FileImageInputStream(File f) throws FileNotFoundException, IOException {
+ if (f == null) {
+ throw new IllegalArgumentException("f == null!");
+ }
+
+ raf = new RandomAccessFile(f, "r");
+ }
+
+ /**
+ * Instantiates a new FileImageInputStream from the specified
+ * RandomAccessFile.
+ *
+ * @param raf the RandomAccessFile of input data.
+ */
+ public FileImageInputStream(RandomAccessFile raf) {
+ if (raf == null) {
+ throw new IllegalArgumentException("raf == null!");
+ }
+
+ this.raf = raf;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ int res = raf.read();
+ if (res != -1) {
+ streamPos++;
+ }
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ int numRead = raf.read(b, off, len);
+ if (numRead >= 0) {
+ streamPos += numRead;
+ }
+
+ return numRead;
+ }
+
+ @Override
+ public long length() {
+ try {
+ return raf.length();
+ } catch(IOException e) {
+ return -1L;
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ if (pos < getFlushedPosition()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ raf.seek(pos);
+ streamPos = raf.getFilePointer();
+ bitOffset = 0;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ raf.close();
+ }
+}
diff --git a/awt/javax/imageio/stream/FileImageOutputStream.java b/awt/javax/imageio/stream/FileImageOutputStream.java
new file mode 100644
index 0000000..eaafe14
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageOutputStream.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.stream;
+
+import java.io.*;
+
+/**
+ * The FileImageOutputStream class implements ImageOutputStream
+ * and writes the output data to a File or RandomAccessFile.
+ */
+public class FileImageOutputStream extends ImageOutputStreamImpl {
+
+ /** The file. */
+ RandomAccessFile file;
+
+ /**
+ * Instantiates a new FileImageOutputStream with the specified
+ * File.
+ *
+ * @param f the output File.
+ *
+ * @throws FileNotFoundException if the file not found.
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public FileImageOutputStream(File f) throws FileNotFoundException, IOException {
+ this(f != null
+ ? new RandomAccessFile(f, "rw")
+ : null);
+ }
+
+ /**
+ * Instantiates a new FileImageOutputStream with the specified
+ * RandomAccessFile.
+ *
+ * @param raf the output RandomAccessFile.
+ */
+ public FileImageOutputStream(RandomAccessFile raf) {
+ if (raf == null) {
+ throw new IllegalArgumentException("file should not be NULL");
+ }
+ file = raf;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ checkClosed();
+ // according to the spec for ImageOutputStreamImpl#flushBits()
+ flushBits();
+ file.write(b);
+ streamPos++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ checkClosed();
+ // according to the spec for ImageOutputStreamImpl#flushBits()
+ flushBits();
+ file.write(b, off, len);
+ streamPos += len;
+ }
+
+ @Override
+ public int read() throws IOException {
+ checkClosed();
+ int rt = file.read();
+ if (rt != -1) {
+ streamPos++;
+ }
+ return rt;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ checkClosed();
+ int rt = file.read(b, off, len);
+ if (rt != -1) {
+ streamPos += rt;
+ }
+ return rt;
+ }
+
+ @Override
+ public long length() {
+ try {
+ checkClosed();
+ return file.length();
+ } catch(IOException e) {
+ return super.length(); // -1L
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ //-- checkClosed() is performed in super.seek()
+ super.seek(pos);
+ file.seek(pos);
+ streamPos = file.getFilePointer();
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ file.close();
+ }
+}
diff --git a/awt/javax/imageio/stream/IIOByteBuffer.java b/awt/javax/imageio/stream/IIOByteBuffer.java
new file mode 100644
index 0000000..961a7b3
--- /dev/null
+++ b/awt/javax/imageio/stream/IIOByteBuffer.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.stream;
+
+/**
+* @author Sergey I. Salishev
+* @version $Revision: 1.2 $
+*/
+
+/**
+ * The IIOByteBuffer class represents a byte array with offset and
+ * length that is used by ImageInputStream for obtaining a sequence
+ * of bytes.
+ */
+public class IIOByteBuffer {
+
+ /** The data. */
+ private byte[] data;
+
+ /** The offset. */
+ private int offset;
+
+ /** The length. */
+ private int length;
+
+ /**
+ * Instantiates a new IIOByteBuffer.
+ *
+ * @param data the byte array.
+ * @param offset the offset in the array.
+ * @param length the length of array.
+ */
+ public IIOByteBuffer(byte[] data, int offset, int length) {
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the byte array of this IIOByteBuffer.
+ *
+ * @return the byte array.
+ */
+ public byte[] getData() {
+ return data;
+ }
+
+ /**
+ * Gets the length in the array which will be used.
+ *
+ * @return the length of the data.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Gets the offset of this IIOByteBuffer.
+ *
+ * @return the offset of this IIOByteBuffer.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Sets the new data array to this IIOByteBuffer object.
+ *
+ * @param data the new data array.
+ */
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ /**
+ * Sets the length of data which will be used.
+ *
+ * @param length the new length.
+ */
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ /**
+ * Sets the offset in the data array of this IIOByteBuffer.
+ *
+ * @param offset the new offset.
+ */
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+}
+
diff --git a/awt/javax/imageio/stream/ImageInputStream.java b/awt/javax/imageio/stream/ImageInputStream.java
new file mode 100644
index 0000000..771e9ff
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStream.java
@@ -0,0 +1,485 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.stream;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * The ImageInputStream represents input stream interface that is
+ * used by ImageReaders.
+ */
+public interface ImageInputStream extends DataInput {
+
+ /**
+ * Sets the specified byte order for reading of data values
+ * from this stream.
+ *
+ * @param byteOrder the byte order.
+ */
+ void setByteOrder(ByteOrder byteOrder);
+
+ /**
+ * Gets the byte order.
+ *
+ * @return the byte order.
+ */
+ ByteOrder getByteOrder();
+
+ /**
+ * Reads a byte from the stream.
+ *
+ * @return the byte of the stream, or -1 for EOF indicating.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int read() throws IOException;
+
+ /**
+ * Reads number of bytes which is equal to the specified array's length
+ * and stores a result to this array.
+ *
+ * @param b the byte array.
+ *
+ * @return the number of read bytes, or -1 indicated EOF.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int read(byte[] b) throws IOException;
+
+ /**
+ * Reads the number of bytes specified by len parameter from
+ * the stream and stores a result to the specified array
+ * with the specified offset.
+ *
+ * @param b the byte array.
+ * @param off the offset.
+ * @param len the number of bytes to be read.
+ *
+ * @return the number of read bytes, or -1 indicated EOF.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int read(byte[] b, int off, int len) throws IOException;
+
+ /**
+ * Reads the number of bytes specified by len parameter
+ * from the stream, and modifies the specified IIOByteBuffer
+ * with the byte array, offset, and length.
+ *
+ * @param buf the IIOByteBuffer.
+ * @param len the number of bytes to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readBytes(IIOByteBuffer buf, int len) throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns a boolean true value
+ * if it is non zero, false if it is zero.
+ *
+ * @return a boolean value for read byte.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ boolean readBoolean() throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns its value
+ * as signed byte.
+ *
+ * @return a signed byte value for read byte.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ byte readByte() throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns its value
+ * as int.
+ *
+ * @return a unsigned byte value for read byte as int.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readUnsignedByte() throws IOException;
+
+ /**
+ * Reads 2 bytes from the stream, and returns the result
+ * as a short.
+ *
+ * @return the signed short value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ short readShort() throws IOException;
+
+ /**
+ * Reads 2 bytes from the stream and returns its value
+ * as an unsigned short.
+ *
+ * @return a unsigned short value coded in an int.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readUnsignedShort() throws IOException;
+
+ /**
+ * Reads 2 bytes from the stream and returns their
+ * unsigned char value.
+ *
+ * @return the unsigned char value.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ char readChar() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream, and returns the result
+ * as an int.
+ *
+ * @return the signed int value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readInt() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream and returns its value
+ * as long.
+ *
+ * @return a unsigned int value as long.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long readUnsignedInt() throws IOException;
+
+ /**
+ * Reads 8 bytes from the stream, and returns the result
+ * as a long.
+ *
+ * @return the long value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long readLong() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream, and returns the result
+ * as a float.
+ *
+ * @return the float value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ float readFloat() throws IOException;
+
+ /**
+ * Reads 8 bytes from the stream, and returns the result
+ * as a double.
+ *
+ * @return the double value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ double readDouble() throws IOException;
+
+ /**
+ * Reads a line from the stream.
+ *
+ * @return the string contained the line from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ String readLine() throws IOException;
+
+ /**
+ * Reads bytes from the stream in a string that has been encoded
+ * in a modified UTF-8 format.
+ *
+ * @return the string read from stream and modified UTF-8 format.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ String readUTF() throws IOException;
+
+ /**
+ * Reads the specified number of bytes from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param b the byte array.
+ * @param off the offset.
+ * @param len the number of bytes to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(byte[] b, int off, int len) throws IOException;
+
+ /**
+ * Reads number of bytes from the stream which is equal to
+ * the specified array's length, and stores them into
+ * this array.
+ *
+ * @param b the byte array.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(byte[] b) throws IOException;
+
+ /**
+ * Reads the specified number of shorts from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param s the short array.
+ * @param off the offset.
+ * @param len the number of shorts to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(short[] s, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of chars from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param c the char array.
+ * @param off the offset.
+ * @param len the number of chars to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(char[] c, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of ints from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param i the int array.
+ * @param off the offset.
+ * @param len the number of ints to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(int[] i, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of longs from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param l the long array.
+ * @param off the offset.
+ * @param len the number of longs to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(long[] l, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of floats from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param f the float array.
+ * @param off the offset.
+ * @param len the number of floats to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(float[] f, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of doubles from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param d the double array.
+ * @param off the offset.
+ * @param len the number of doubles to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(double[] d, int off, int len) throws IOException;
+
+ /**
+ * Gets the stream position.
+ *
+ * @return the stream position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long getStreamPosition() throws IOException;
+
+ /**
+ * Gets the bit offset.
+ *
+ * @return the bit offset.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int getBitOffset() throws IOException;
+
+ /**
+ * Sets the bit offset to an integer between 0 and 7.
+ *
+ * @param bitOffset the bit offset.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void setBitOffset(int bitOffset) throws IOException;
+
+ /**
+ * Reads a bit from the stream and returns the value 0 or 1.
+ *
+ * @return the value of single bit: 0 or 1.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readBit() throws IOException;
+
+ /**
+ * Read the specified number of bits and returns their values as long.
+ *
+ * @param numBits the number of bits to be read.
+ *
+ * @return the bit string as a long.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long readBits(int numBits) throws IOException;
+
+ /**
+ * Returns the length of the stream.
+ *
+ * @return the length of the stream, or -1 if unknown.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long length() throws IOException;
+
+ /**
+ * Skipes the specified number of bytes by moving stream position.
+ *
+ * @param n the number of bytes.
+ *
+ * @return the actual skipped number of bytes.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int skipBytes(int n) throws IOException;
+
+ /**
+ * Skipes the specified number of bytes by moving stream position.
+ *
+ * @param n the number of bytes.
+ *
+ * @return the actual skipped number of bytes.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long skipBytes(long n) throws IOException;
+
+ /**
+ * Sets the current stream position to the specified location.
+ *
+ * @param pos a file pointer position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void seek(long pos) throws IOException;
+
+ /**
+ * Marks a position in the stream to be returned to by a subsequent
+ * call to reset.
+ */
+ void mark();
+
+ /**
+ * Returns the file pointer to its previous position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void reset() throws IOException;
+
+ /**
+ * Flushes the initial position in this stream prior to the
+ * specified stream position.
+ *
+ * @param pos the position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void flushBefore(long pos) throws IOException;
+
+ /**
+ * Flushes the initial position in this stream prior to the
+ * current stream position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void flush() throws IOException;
+
+ /**
+ * Gets the flushed position.
+ *
+ * @return the flushed position.
+ */
+ long getFlushedPosition();
+
+ /**
+ * Returns true if this ImageInputStream caches data in order
+ * to allow seeking backwards.
+ *
+ * @return true if this ImageInputStream caches data in order
+ * to allow seeking backwards, false otherwise.
+ */
+ boolean isCached();
+
+ /**
+ * Returns true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in memory.
+ *
+ * @return true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in memory.
+ */
+ boolean isCachedMemory();
+
+ /**
+ * Returns true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in a temporary file.
+ *
+ * @return true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in a temporary file.
+ */
+ boolean isCachedFile();
+
+ /**
+ * Closes this stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void close() throws IOException;
+}
diff --git a/awt/javax/imageio/stream/ImageInputStreamImpl.java b/awt/javax/imageio/stream/ImageInputStreamImpl.java
new file mode 100644
index 0000000..83ac13a
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStreamImpl.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.stream;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * The ImageInputStreamImpl abstract class implements
+ * the ImageInputStream interface.
+ */
+public abstract class ImageInputStreamImpl implements ImageInputStream {
+
+ /** The byte order. */
+ protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+ /** The stream position. */
+ protected long streamPos = 0;
+
+ /** The flushed position. */
+ protected long flushedPos = 0;
+
+ /** The bit offset. */
+ protected int bitOffset = 0;
+
+ /** The closed. */
+ private boolean closed = false;
+
+ /** The position stack. */
+ private final PositionStack posStack = new PositionStack();
+
+ /**
+ * Instantiates a new ImageInputStreamImpl.
+ */
+ public ImageInputStreamImpl() {}
+
+ /**
+ * Check if the stream is closed and if true, throws an IOException.
+ *
+ * @throws IOException Signals that the stream is closed.
+ */
+ protected final void checkClosed() throws IOException {
+ if (closed) {
+ throw new IOException("stream is closed");
+ }
+ }
+
+ public void setByteOrder(ByteOrder byteOrder) {
+ this.byteOrder = byteOrder;
+ }
+
+ public ByteOrder getByteOrder() {
+ return byteOrder;
+ }
+
+ public abstract int read() throws IOException;
+
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public abstract int read(byte[] b, int off, int len) throws IOException;
+
+ public void readBytes(IIOByteBuffer buf, int len) throws IOException {
+ if (buf == null) {
+ throw new NullPointerException("buffer is NULL");
+ }
+
+ byte[] b = new byte[len];
+ len = read(b, 0, b.length);
+
+ buf.setData(b);
+ buf.setOffset(0);
+ buf.setLength(len);
+ }
+
+ public boolean readBoolean() throws IOException {
+ int b = read();
+ if (b < 0) {
+ throw new EOFException("EOF reached");
+ }
+ return b != 0;
+ }
+
+ public byte readByte() throws IOException {
+ int b = read();
+ if (b < 0) {
+ throw new EOFException("EOF reached");
+ }
+ return (byte) b;
+ }
+
+ public int readUnsignedByte() throws IOException {
+ int b = read();
+ if (b < 0) {
+ throw new EOFException("EOF reached");
+ }
+ return b;
+ }
+
+ public short readShort() throws IOException {
+ int b1 = read();
+ int b2 = read();
+
+ if (b1 < 0 || b2 < 0) {
+ throw new EOFException("EOF reached");
+ }
+
+ return byteOrder == ByteOrder.BIG_ENDIAN ?
+ (short) ((b1 << 8) | (b2 & 0xff)) :
+ (short) ((b2 << 8) | (b1 & 0xff));
+ }
+
+ public int readUnsignedShort() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public char readChar() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public int readInt() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long readUnsignedInt() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long readLong() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public float readFloat() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public double readDouble() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public String readLine() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public String readUTF() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(byte[] b, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(byte[] b) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ public void readFully(short[] s, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(char[] c, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(int[] i, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(long[] l, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(float[] f, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(double[] d, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long getStreamPosition() throws IOException {
+ checkClosed();
+ return streamPos;
+ }
+
+ public int getBitOffset() throws IOException {
+ checkClosed();
+ return bitOffset;
+ }
+
+ public void setBitOffset(int bitOffset) throws IOException {
+ checkClosed();
+ this.bitOffset = bitOffset;
+ }
+
+ public int readBit() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long readBits(int numBits) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long length() {
+ return -1L;
+ }
+
+ public int skipBytes(int n) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long skipBytes(long n) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void seek(long pos) throws IOException {
+ checkClosed();
+ if (pos < getFlushedPosition()) {
+ throw new IllegalArgumentException("trying to seek before flushed pos");
+ }
+ bitOffset = 0;
+ streamPos = pos;
+ }
+
+ public void mark() {
+ try {
+ posStack.push(getStreamPosition());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Stream marking error");
+ }
+ }
+
+ public void reset() throws IOException {
+ //-- TODO bit pos
+ if (!posStack.isEmpty()) {
+ long p = posStack.pop();
+ if (p < flushedPos) {
+ throw new IOException("marked position lies in the flushed portion of the stream");
+ }
+ seek(p);
+ }
+ }
+
+ public void flushBefore(long pos) throws IOException {
+ if (pos > getStreamPosition()) {
+ throw new IndexOutOfBoundsException("Trying to flush outside of current position");
+ }
+ if (pos < flushedPos) {
+ throw new IndexOutOfBoundsException("Trying to flush within already flushed portion");
+ }
+ flushedPos = pos;
+ //-- TODO implement
+ }
+
+ public void flush() throws IOException {
+ flushBefore(getStreamPosition());
+ }
+
+ public long getFlushedPosition() {
+ return flushedPos;
+ }
+
+ public boolean isCached() {
+ return false; //def
+ }
+
+ public boolean isCachedMemory() {
+ return false; //def
+ }
+
+ public boolean isCachedFile() {
+ return false; //def
+ }
+
+ public void close() throws IOException {
+ checkClosed();
+ closed = true;
+
+ }
+
+ /**
+ * Finalizes this object.
+ *
+ * @throws Throwable if an error occurs.
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ if (!closed) {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ /**
+ * The Class PositionStack.
+ */
+ private static class PositionStack {
+
+ /** The Constant SIZE. */
+ private static final int SIZE = 10;
+
+ /** The values. */
+ private long[] values = new long[SIZE];
+
+ /** The pos. */
+ private int pos = 0;
+
+
+ /**
+ * Push.
+ *
+ * @param v the v
+ */
+ void push(long v) {
+ if (pos >= values.length) {
+ ensure(pos+1);
+ }
+ values[pos++] = v;
+ }
+
+ /**
+ * Pop.
+ *
+ * @return the long
+ */
+ long pop() {
+ return values[--pos];
+ }
+
+ /**
+ * Checks if is empty.
+ *
+ * @return true, if is empty
+ */
+ boolean isEmpty() {
+ return pos == 0;
+ }
+
+ /**
+ * Ensure.
+ *
+ * @param size the size
+ */
+ private void ensure(int size) {
+ long[] arr = new long[Math.max(2 * values.length, size)];
+ System.arraycopy(values, 0, arr, 0, values.length);
+ values = arr;
+ }
+ }
+}
diff --git a/awt/javax/imageio/stream/ImageOutputStream.java b/awt/javax/imageio/stream/ImageOutputStream.java
new file mode 100644
index 0000000..e59b69d
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStream.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.stream;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * The ImageOutputStream represents output stream interface that is
+ * used by ImageWriters.
+ */
+public interface ImageOutputStream extends DataOutput, ImageInputStream {
+
+ /**
+ * Writes a single byte to the stream at the current position.
+ *
+ * @param b the int value, of which the 8 lowest bits
+ * will be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void write(int b) throws IOException;
+
+ /**
+ * Writes the bytes array to the stream.
+ *
+ * @param b the byte array to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void write(byte[] b) throws IOException;
+
+ /**
+ * Writes a number of bytes from the specified byte array
+ * beggining from the specified offset.
+ *
+ * @param b the byte array.
+ * @param off the offset.
+ * @param len the number of bytes to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void write(byte[] b, int off, int len) throws IOException;
+
+ /**
+ * Writes the specified boolean value to the stream, 1 if it is true,
+ * 0 if it is false.
+ *
+ * @param b the boolean value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBoolean(boolean b) throws IOException;
+
+ /**
+ * Writes the 8 lowest bits of the specified int value to the stream.
+ *
+ * @param b the specified int value.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeByte(int b) throws IOException;
+
+ /**
+ * Writes a short value to the output stream.
+ *
+ * @param v the short value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeShort(int v) throws IOException;
+
+ /**
+ * Writes the 16 lowest bits of the specified int value to the stream.
+ *
+ * @param v the specified int value.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeChar(int v) throws IOException;
+
+ /**
+ * Writes an integer value to the output stream.
+ *
+ * @param v the integer value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeInt(int v) throws IOException;
+
+ /**
+ * Write long.
+ *
+ * @param v the long value
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeLong(long v) throws IOException;
+
+ /**
+ * Writes a float value to the output stream.
+ *
+ * @param v the float which contains value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeFloat(float v) throws IOException;
+
+ /**
+ * Writes a double value to the output stream.
+ *
+ * @param v the double which contains value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeDouble(double v) throws IOException;
+
+ /**
+ * Writes the specified string to the stream.
+ *
+ * @param s the string to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBytes(String s) throws IOException;
+
+ /**
+ * Writes the specified String to the output stream.
+ *
+ * @param s the String to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeChars(String s) throws IOException;
+
+ /**
+ * Writes 2 bytes to the output stream in
+ * the modified UTF-8 representation of every character of
+ * the specified string.
+ *
+ * @param s the specified string to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeUTF(String s) throws IOException;
+
+ /**
+ * Flushes the initial position in this stream prior to the
+ * specified stream position.
+ *
+ * @param pos the position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void flushBefore(long pos) throws IOException;
+
+
+ /**
+ * Writes a len number of short values from the specified array
+ * to the stream.
+ *
+ * @param s the shorts array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeShorts(short[] s, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of chars to the stream.
+ *
+ * @param c the char array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeChars(char[] c, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of int values from the specified array
+ * to the stream.
+ *
+ * @param i the int array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeInts(int[] i, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of long values from the specified array
+ * to the stream.
+ *
+ * @param l the long array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeLongs(long[] l, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of float values from the specified array
+ * to the stream.
+ *
+ * @param f the float array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeFloats(float[] f, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of double values from the specified array
+ * to the stream.
+ *
+ * @param d the double array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeDoubles(double[] d, int off, int len) throws IOException;
+
+ /**
+ * Writes a single bit at the current position.
+ *
+ * @param bit the an int whose least significant bit is to be
+ * written to the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBit(int bit) throws IOException;
+
+ /**
+ * Writes a sequence of bits beggining from the current position.
+ *
+ * @param bits a long value containing the bits to be written,
+ * starting with the bit in position numBits - 1 down to the
+ * least significant bit.
+ * @param numBits the number of significant bit ,
+ * it can be between 0 and 64.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBits(long bits, int numBits) throws IOException;
+
+}
diff --git a/awt/javax/imageio/stream/ImageOutputStreamImpl.java b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
new file mode 100644
index 0000000..c3d80fa
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/*
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+/**
+ * The ImageOutputStreamImpl abstract class implements
+ * the ImageOutputStream interface.
+ */
+public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl
+ implements ImageOutputStream {
+
+ /**
+ * Instantiates a new ImageOutputStreamImpl.
+ */
+ public ImageOutputStreamImpl() {}
+
+ public abstract void write(int b) throws IOException;
+
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ public abstract void write(byte[] b, int off, int len) throws IOException;
+
+ public void writeBoolean(boolean v) throws IOException {
+ write(v ? 1 : 0);
+ }
+
+ public void writeByte(int v) throws IOException {
+ write(v);
+ }
+
+ public void writeShort(int v) throws IOException {
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+ } else {
+
+ }
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeChar(int v) throws IOException {
+ writeShort(v);
+ }
+
+ public void writeInt(int v) throws IOException {
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+ } else {
+
+ }
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeLong(long v) throws IOException {
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+ } else {
+
+ }
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ public void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ public void writeBytes(String s) throws IOException {
+ write(s.getBytes());
+ }
+
+ public void writeChars(String s) throws IOException {
+ char[] chs = s.toCharArray();
+ writeChars(chs, 0, chs.length);
+ }
+
+ public void writeUTF(String s) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeShorts(short[] s, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeChars(char[] c, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeInts(int[] i, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeLongs(long[] l, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeFloats(float[] f, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeDoubles(double[] d, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeBit(int bit) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeBits(long bits, int numBits) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Flushes the bits. This method should be called in the write
+ * methods by subclasses.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected final void flushBits() throws IOException {
+ if (bitOffset == 0) {
+ return;
+ }
+
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+}
diff --git a/awt/javax/imageio/stream/MemoryCacheImageInputStream.java b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
new file mode 100644
index 0000000..a3d470b
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The MemoryCacheImageInputStream class implements ImageInputStream
+ * using a memory buffer for caching the data.
+ */
+public class MemoryCacheImageInputStream extends ImageInputStreamImpl {
+
+ /** The is. */
+ private InputStream is;
+
+ /** The ramc. */
+ private RandomAccessMemoryCache ramc = new RandomAccessMemoryCache();
+
+ /**
+ * Instantiates a new MemoryCacheImageInputStream
+ * which reads from the specified InputStream.
+ *
+ * @param stream the InputStream to be read.
+ */
+ public MemoryCacheImageInputStream(InputStream stream) {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ is = stream;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= ramc.length()) {
+ int count = (int)(streamPos - ramc.length() + 1);
+ int bytesAppended = ramc.appendData(is, count);
+
+ if (bytesAppended < count) {
+ return -1;
+ }
+ }
+
+ int res = ramc.getData(streamPos);
+ if (res >= 0) {
+ streamPos++;
+ }
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= ramc.length()) {
+ int count = (int)(streamPos - ramc.length() + len);
+ ramc.appendData(is, count);
+ }
+
+ int res = ramc.getData(b, off, len, streamPos);
+ if (res > 0) {
+ streamPos += res;
+ }
+ return res;
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return false;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return true;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ ramc.close();
+ }
+
+ @Override
+ public void flushBefore(long pos) throws IOException {
+ super.flushBefore(pos);
+ ramc.freeBefore(getFlushedPosition());
+ }
+}
diff --git a/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
new file mode 100644
index 0000000..96ded43
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+
+/**
+ * The MemoryCacheImageOutputStream class implements ImageOutputStream
+ * using a memory buffer for caching the data.
+ */
+public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {
+
+ /** The os. */
+ OutputStream os;
+
+ /** The ramc. */
+ RandomAccessMemoryCache ramc = new RandomAccessMemoryCache();
+
+ /**
+ * Instantiates a new MemoryCacheImageOutputStream
+ * which writes to the specified OutputStream.
+ *
+ * @param stream the OutputStream.
+ */
+ public MemoryCacheImageOutputStream(OutputStream stream) {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ os = stream;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ ramc.putData(b, streamPos);
+ streamPos++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ ramc.putData(b, off, len, streamPos);
+ streamPos += len;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ int res = ramc.getData(streamPos);
+ if (res >= 0) {
+ streamPos++;
+ }
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ int res = ramc.getData(b, off, len, streamPos);
+ if (res > 0) {
+ streamPos += res;
+ }
+ return res;
+ }
+
+ @Override
+ public long length() {
+ return ramc.length();
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ flushBefore(length());
+ super.close();
+ ramc.close();
+ }
+
+ @Override
+ public void flushBefore(long pos) throws IOException {
+ long flushedPosition = getFlushedPosition();
+ super.flushBefore(pos);
+
+ long newFlushedPosition = getFlushedPosition();
+ int nBytes = (int)(newFlushedPosition - flushedPosition);
+
+ ramc.getData(os, nBytes, flushedPosition);
+ ramc.freeBefore(newFlushedPosition);
+
+ os.flush();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/ChoiceStyle.java b/awt/org/apache/harmony/awt/ChoiceStyle.java
new file mode 100644
index 0000000..93b7aad
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ChoiceStyle.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+/**
+ * ChoiceStyle.
+ * Is used to define custom choice properties:
+ * width and x screen coordinate of the list popup window.
+ */
+public interface ChoiceStyle {
+
+ int getPopupX(int x, int width, int choiceWidth, int screenWidth);
+ int getPopupWidth(int choiceWidth);
+
+}
diff --git a/awt/org/apache/harmony/awt/ClipRegion.java b/awt/org/apache/harmony/awt/ClipRegion.java
new file mode 100644
index 0000000..c89a81d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ClipRegion.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov, Anton Avtamonov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.awt.Component;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class ClipRegion extends Rectangle {
+ private final MultiRectArea clip;
+
+ public ClipRegion(final MultiRectArea clip) {
+ this.clip = new MultiRectArea(clip);
+ setBounds(clip.getBounds());
+ }
+
+ public MultiRectArea getClip() {
+ return clip;
+ }
+
+ @Override
+ public String toString() {
+ String str = clip.toString();
+ int i = str.indexOf('[');
+ str = str.substring(i);
+ if (clip.getRectCount() == 1) {
+ str = str.substring(1, str.length() - 1);
+ }
+ return getClass().getName() + str;
+ }
+
+
+ public void convertRegion(final Component child, final Component parent) {
+ convertRegion(child, clip, parent);
+ }
+
+ public void intersect(final Rectangle rect) {
+ clip.intersect(rect);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return clip.isEmpty();
+ }
+
+ public static void convertRegion(final Component child,
+ final MultiRectArea region,
+ final Component parent) {
+ int x = 0, y = 0;
+ Component c = child;
+ //???AWT
+ /*
+ for (; c != null && c != parent; c = c.getParent()) {
+ x += c.getX();
+ y += c.getY();
+ }
+ */
+ if (c == null) {
+ // awt.51=Component expected to be a parent
+ throw new IllegalArgumentException(Messages.getString("awt.51")); //$NON-NLS-1$
+ }
+ region.translate(x, y);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/ComponentInternals.java b/awt/org/apache/harmony/awt/ComponentInternals.java
new file mode 100644
index 0000000..c359784
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ComponentInternals.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+//???AWT
+//import java.awt.Component;
+//import java.awt.Container;
+//import java.awt.Dialog;
+import java.awt.Dimension;
+//import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+//import java.awt.Window;
+//import java.awt.Choice;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+//import org.apache.harmony.awt.text.TextFieldKit;
+//import org.apache.harmony.awt.text.TextKit;
+//import org.apache.harmony.awt.wtk.NativeWindow;
+
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ * The accessor to AWT private API
+ */
+public abstract class ComponentInternals {
+
+ /**
+ * @return the ComponentInternals instance to serve the requests
+ */
+ public static ComponentInternals getComponentInternals() {
+ return ContextStorage.getComponentInternals();
+ }
+
+ /**
+ * This method must be called by AWT to establish the connection
+ * @param internals - implementation of ComponentInternals created by AWT
+ */
+ public static void setComponentInternals(ComponentInternals internals) {
+ ContextStorage.setComponentInternals(internals);
+ }
+
+ /**
+ * The accessor to native resource connected to a component.
+ * It returns non-<code>null</code> value only if component
+ * already has the native resource
+ */
+ //public abstract NativeWindow getNativeWindow(Component component);
+
+ /**
+ * Connect Window object to existing native resource
+ * @param nativeWindowId - id of native window to attach
+ * @return Window object with special behaviour that
+ * restricts manupulation with that window
+ */
+ //public abstract Window attachNativeWindow(long nativeWindowId);
+
+ /**
+ * Start mouse grab in "client" mode.
+ * All mouse events in AWT components will be reported as usual,
+ * mouse events that occured outside of AWT components will be sent to
+ * the window passed as grabWindow parameter. When mouse grab is canceled
+ * (because of click in non-AWT window or by task switching)
+ * the whenCanceled callback is called
+ *
+ * @param grabWindow - window that will own the grab
+ * @param whenCanceled - callback called when grab is canceled by user's action
+ */
+ //public abstract void startMouseGrab(Window grabWindow, Runnable whenCanceled);
+
+ /**
+ * End mouse grab and resume normal processing of mouse events
+ */
+ //public abstract void endMouseGrab();
+
+ /**
+ * Set the <code>popup</code> flag of the window to true.
+ * This window won't be controlled by window manager on Linux.
+ * Call this method before the window is shown first time
+ * @param window - the window that should become popup one
+ */
+ //public abstract void makePopup(Window window);
+
+ /**
+ * This method must be called by Graphics at the beginning of drawImage()
+ * to store image drawing parameters (defined by application developer) in component
+ *
+ * @param comp - component that draws the image
+ * @param image - image to be drawn
+ * @param destLocation - location of the image upon the component's surface. Never null.
+ * @param destSize - size of the component's area to be filled with the image.
+ * Equals to null if size parameters omitted in drawImage.
+ * @param source - area of the image to be drawn on the component.
+ * Equals to null if src parameters omitted in drawImage.
+ */
+ /*
+ public abstract void onDrawImage(Component comp, Image image, Point destLocation,
+ Dimension destSize, Rectangle source);
+*/
+ /**
+ * Sets system's caret position.
+ * This method should be called by text component to synchronize our caret position
+ * with system's caret position.
+ * @param x
+ * @param y
+ */
+ //public abstract void setCaretPos(Component c, int x, int y);
+
+ /**
+ * NEVER USE IT. FORGET IT. IT DOES NOT EXIST.
+ * See Toolkit.unsafeInvokeAndWait(Runnable).
+ *
+ * Accessor for Toolkit.unsafeInvokeAndWait(Runnable) method.
+ * For use in exceptional cases only.
+ * Read comments for Toolkit.unsafeInvokeAndWait(Runnable) before use.
+ */
+ /*
+ public abstract void unsafeInvokeAndWait(Runnable runnable)
+ throws InterruptedException, InvocationTargetException;
+
+ public abstract TextKit getTextKit(Component comp);
+
+ public abstract void setTextKit(Component comp, TextKit kit);
+
+ public abstract TextFieldKit getTextFieldKit(Component comp);
+
+ public abstract void setTextFieldKit(Component comp, TextFieldKit kit);
+*/
+ /**
+ * Terminate event dispatch thread, completely destroy AWT context.<br>
+ * Intended for multi-context mode, in single-context mode does nothing.
+ *
+ */
+ public abstract void shutdown();
+
+ /**
+ * Sets mouse events preprocessor for event queue
+ */
+ //public abstract void setMouseEventPreprocessor(MouseEventPreprocessor preprocessor);
+
+ /**
+ * Create customized Choice using style
+ */
+ //public abstract Choice createCustomChoice(ChoiceStyle style);
+
+ //public abstract Insets getNativeInsets(Window w);
+
+ /**
+ * Region to be repainted (could be null). Use this in overridden repaint()
+ */
+ //public abstract MultiRectArea getRepaintRegion(Component c);
+
+ //public abstract MultiRectArea subtractPendingRepaintRegion(Component c, MultiRectArea mra);
+
+ /**
+ * Returns true if the window was at least once painted due to native paint events
+ */
+ //public abstract boolean wasPainted(Window w);
+
+ /**
+ * The component's region hidden behind top-level windows
+ * (belonging to both this Java app and all other apps), and behind
+ * heavyweight components overlapping with passed component
+ */
+ //public abstract MultiRectArea getObscuredRegion(Component c);
+
+ /**
+ * An accessor to Container.addObscuredRegions() method
+ * @see java.awt.Container#addObscuredRegions(MultiRectArea, Component)
+ */
+ //public abstract void addObscuredRegions(MultiRectArea mra, Component c, Container container);
+
+ /**
+ * Makes it possible to call protected Toolkit.setDesktopProperty()
+ * method from any class outside of java.awt package
+ */
+ public abstract void setDesktopProperty(String name, Object value);
+
+ /**
+ * Makes it possible to start/stop dialog modal loop
+ * from anywhere outside of java.awt package
+ */
+ //public abstract void runModalLoop(Dialog dlg);
+ //public abstract void endModalLoop(Dialog dlg);
+
+ /**
+ * Sets component's visible flag only
+ * (the component is not actually shown/hidden)
+ */
+ //public abstract void setVisibleFlag(Component comp, boolean visible);
+
+}
diff --git a/awt/org/apache/harmony/awt/ContextStorage.java b/awt/org/apache/harmony/awt/ContextStorage.java
new file mode 100644
index 0000000..d44648a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ContextStorage.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.awt.*;
+
+//???AWT
+//import org.apache.harmony.awt.datatransfer.*;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.*;
+
+
+public final class ContextStorage {
+
+ private static volatile boolean multiContextMode = false;
+ private volatile boolean shutdownPending = false;
+
+ private static final ContextStorage globalContext = new ContextStorage();
+
+ private Toolkit toolkit;
+ private ComponentInternals componentInternals;
+ //???AWT: private DTK dtk;
+ private WTK wtk;
+ private GraphicsEnvironment graphicsEnvironment;
+
+ private class ContextLock {}
+ private final Object contextLock = new ContextLock();
+ private final Synchronizer synchronizer = new Synchronizer();
+
+ public static void activateMultiContextMode() {
+ // TODO: checkPermission
+ multiContextMode = true;
+ }
+
+ public static void setDefaultToolkit(Toolkit newToolkit) {
+ // TODO: checkPermission
+ getCurrentContext().toolkit = newToolkit;
+ }
+
+ public static Toolkit getDefaultToolkit() {
+ return getCurrentContext().toolkit;
+ }
+
+ //???AWT
+ /*
+ public static void setDTK(DTK dtk) {
+ // TODO: checkPermission
+ getCurrentContext().dtk = dtk;
+ }
+
+ public static DTK getDTK() {
+ return getCurrentContext().dtk;
+ }
+ */
+
+ public static Synchronizer getSynchronizer() {
+ return getCurrentContext().synchronizer;
+ }
+
+ public static ComponentInternals getComponentInternals() {
+ return getCurrentContext().componentInternals;
+ }
+
+ static void setComponentInternals(ComponentInternals internals) {
+ // TODO: checkPermission
+ getCurrentContext().componentInternals = internals;
+ }
+
+ public static Object getContextLock() {
+ return getCurrentContext().contextLock;
+ }
+
+ public static WindowFactory getWindowFactory() {
+ return getCurrentContext().wtk.getWindowFactory();
+ }
+
+ public static void setWTK(WTK wtk) {
+ getCurrentContext().wtk = wtk;
+ }
+
+ public static NativeIM getNativeIM() {
+ return getCurrentContext().wtk.getNativeIM();
+ }
+
+ public static NativeEventQueue getNativeEventQueue() {
+ return getCurrentContext().wtk.getNativeEventQueue();
+ }
+
+ public static GraphicsEnvironment getGraphicsEnvironment() {
+ return getCurrentContext().graphicsEnvironment;
+ }
+
+ public static void setGraphicsEnvironment(GraphicsEnvironment environment) {
+ getCurrentContext().graphicsEnvironment = environment;
+ }
+
+ private static ContextStorage getCurrentContext() {
+ return multiContextMode ? getContextThreadGroup().context : globalContext;
+ }
+
+ private static ContextThreadGroup getContextThreadGroup() {
+
+ Thread thread = Thread.currentThread();
+ ThreadGroup group = thread.getThreadGroup();
+ while (group != null) {
+ if (group instanceof ContextThreadGroup) {
+ return (ContextThreadGroup)group;
+ }
+ group = group.getParent();
+ }
+ // awt.59=Application has run out of context thread group
+ throw new RuntimeException(Messages.getString("awt.59")); //$NON-NLS-1$
+ }
+
+ public static boolean shutdownPending() {
+ return getCurrentContext().shutdownPending;
+ }
+
+ void shutdown() {
+ if (!multiContextMode) {
+ return;
+ }
+ shutdownPending = true;
+
+ //???AWT: componentInternals.shutdown();
+
+ synchronized(contextLock) {
+ toolkit = null;
+ componentInternals = null;
+ //???AWT: dtk = null;
+ wtk = null;
+ graphicsEnvironment = null;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/ContextThreadGroup.java b/awt/org/apache/harmony/awt/ContextThreadGroup.java
new file mode 100644
index 0000000..4f0af52
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ContextThreadGroup.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+public class ContextThreadGroup extends ThreadGroup {
+
+ final ContextStorage context = new ContextStorage();
+
+ public ContextThreadGroup(String name) {
+ super(name);
+ }
+
+ public void dispose() {
+ context.shutdown();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/ListenerList.java b/awt/org/apache/harmony/awt/ListenerList.java
new file mode 100644
index 0000000..f5c55f1
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ListenerList.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.awt;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * List of AWT listeners. It is for 3 purposes.
+ * 1. To support list modification from listeners
+ * 2. To ensure call for all listeners as atomic operation
+ * 3. To support system listeners that are needed for built-in AWT components
+ */
+public class ListenerList<T extends EventListener> implements Serializable {
+ private static final long serialVersionUID = 9180703263299648154L;
+
+ private transient ArrayList<T> systemList;
+ private transient ArrayList<T> userList;
+
+ public ListenerList() {
+ super();
+ }
+
+ /**
+ * Adds system listener to this list.
+ *
+ * @param listener - listener to be added.
+ */
+ public void addSystemListener(T listener) {
+ if (systemList == null) {
+ systemList = new ArrayList<T>();
+ }
+ systemList.add(listener);
+ }
+
+ /**
+ * Adds user (public) listener to this list.
+ *
+ * @param listener - listener to be added.
+ */
+ public void addUserListener(T listener) {
+ if (listener == null) {
+ return;
+ }
+ // transactionally replace old list
+ synchronized (this) {
+ if (userList == null) {
+ userList = new ArrayList<T>();
+ userList.add(listener);
+ return;
+ }
+ ArrayList<T> newList = new ArrayList<T>(userList);
+ newList.add(listener);
+ userList = newList;
+ }
+ }
+
+ /**
+ * Removes user (public) listener to this list.
+ *
+ * @param listener - listener to be removed.
+ */
+ public void removeUserListener(Object listener) {
+ if (listener == null) {
+ return;
+ }
+ // transactionally replace old list
+ synchronized (this) {
+ if (userList == null || !userList.contains(listener)) {
+ return;
+ }
+ ArrayList<T> newList = new ArrayList<T>(userList);
+ newList.remove(listener);
+ userList = (newList.size() > 0 ? newList : null);
+ }
+ }
+
+ /**
+ * Gets all user (public) listeners in one array.
+ *
+ * @param emptyArray - empty array, it's for deriving particular listeners class.
+ * @return array of all user listeners.
+ */
+ public <AT> AT[] getUserListeners(AT[] emptyArray){
+ synchronized (this) {
+ return (userList != null ? userList.toArray(emptyArray) : emptyArray);
+
+ }
+ }
+
+ /**
+ * Gets all user (public) listeners in one list.
+ *
+ * @return list of all user listeners.
+ */
+ public List<T> getUserListeners() {
+ synchronized (this) {
+ if (userList == null || userList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<T>(userList);
+ }
+ }
+
+ public List<T> getSystemListeners() {
+ synchronized (this) {
+ if (systemList == null || systemList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<T>(systemList);
+ }
+ }
+
+ /**
+ * Gets iterator for user listeners.
+ *
+ * @return iterator for user listeners.
+ */
+ public Iterator<T> getUserIterator() {
+ synchronized (this) {
+ if (userList == null) {
+ List<T> emptyList = Collections.emptyList();
+ return emptyList.iterator();
+ }
+ return new ReadOnlyIterator<T>(userList.iterator());
+ }
+ }
+
+ /**
+ * Gets iterator for system listeners.
+ *
+ * @return iterator for system listeners.
+ */
+ public Iterator<T> getSystemIterator() {
+ return systemList.iterator();
+ }
+
+ private static ArrayList<?> getOnlySerializable(ArrayList<?> list) {
+ if (list == null) {
+ return null;
+ }
+
+ ArrayList<Object> result = new ArrayList<Object>();
+ for (Iterator<?> it = list.iterator(); it.hasNext();) {
+ Object obj = it.next();
+ if (obj instanceof Serializable) {
+ result.add(obj);
+ }
+ }
+
+ return (result.size() != 0) ? result : null;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+
+ stream.defaultWriteObject();
+
+ stream.writeObject(getOnlySerializable(systemList));
+ stream.writeObject(getOnlySerializable(userList));
+ }
+
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+
+ stream.defaultReadObject();
+
+ systemList = (ArrayList<T>)stream.readObject();
+ userList = (ArrayList<T>)stream.readObject();
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/ReadOnlyIterator.java b/awt/org/apache/harmony/awt/ReadOnlyIterator.java
new file mode 100644
index 0000000..671653f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ReadOnlyIterator.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.util.Iterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * ReadOnlyIterator
+ */
+public final class ReadOnlyIterator<E> implements Iterator<E> {
+
+ private final Iterator<E> it;
+
+ public ReadOnlyIterator(Iterator<E> it) {
+ if (it == null) {
+ throw new NullPointerException();
+ }
+ this.it = it;
+ }
+
+ public void remove() {
+ // awt.50=Iterator is read-only
+ throw new UnsupportedOperationException(Messages.getString("awt.50")); //$NON-NLS-1$
+ }
+
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ public E next() {
+ return it.next();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java b/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
new file mode 100644
index 0000000..bd5f6c6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 23.11.2005
+ *
+ */
+
+
+package org.apache.harmony.awt.gl;
+
+import java.awt.Image;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.DataBufferInt;
+
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+
+/**
+ * This class give an opportunity to get access to private data of
+ * some java.awt.image classes
+ * Implementation of this class placed in java.awt.image package
+ */
+
+public abstract class AwtImageBackdoorAccessor {
+
+ static protected AwtImageBackdoorAccessor inst;
+
+ public static AwtImageBackdoorAccessor getInstance(){
+ // First we need to run the static initializer in the DataBuffer class to resolve inst.
+ new DataBufferInt(0);
+ return inst;
+ }
+
+ public abstract Surface getImageSurface(Image image);
+ public abstract boolean isGrayPallete(IndexColorModel icm);
+
+ public abstract Object getData(DataBuffer db);
+ public abstract int[] getDataInt(DataBuffer db);
+ public abstract byte[] getDataByte(DataBuffer db);
+ public abstract short[] getDataShort(DataBuffer db);
+ public abstract short[] getDataUShort(DataBuffer db);
+ public abstract double[] getDataDouble(DataBuffer db);
+ public abstract float[] getDataFloat(DataBuffer db);
+ public abstract void releaseData(DataBuffer db);
+
+ public abstract void addDataBufferListener(DataBuffer db, DataBufferListener listener);
+ public abstract void removeDataBufferListener(DataBuffer db);
+ public abstract void validate(DataBuffer db);
+}
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java b/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
new file mode 100644
index 0000000..a33c38b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
@@ -0,0 +1,1132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderableImage;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.RoundRectangle2D;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+import org.apache.harmony.awt.gl.render.Blitter;
+import org.apache.harmony.awt.gl.render.JavaArcRasterizer;
+import org.apache.harmony.awt.gl.render.JavaLineRasterizer;
+import org.apache.harmony.awt.gl.render.JavaShapeRasterizer;
+import org.apache.harmony.awt.gl.render.JavaTextRenderer;
+import org.apache.harmony.awt.gl.render.NullBlitter;
+
+/*
+ * List of abstract methods to implement in subclusses
+ * Graphics.copyArea(int x, int y, int width, int height, int dx, int dy)
+ * Graphics.create()
+ * Graphics2D.getDeviceConfiguration()
+ * CommonGraphics2D.fillMultiRectAreaColor(MultiRectArea mra);
+ * CommonGraphics2D.fillMultiRectAreaPaint(MultiRectArea mra);
+ */
+
+/**
+ * CommonGraphics2D class is a super class for all system-dependent
+ * implementations. It implements major part of Graphics and Graphics2D
+ * abstract methods.
+ * <h2>CommonGraphics2D Class Internals</h2>
+ * <h3>Line and Shape Rasterizers</h3>
+ * <p>
+ * The CommonGraphics2D class splits all shapes into a set of rectangles
+ * to unify the drawing process for different operating systems and architectures.
+ * For this purpose Java 2D* uses the JavaShapeRasterizer and the JavaLineRasterizer
+ * classes from the org.apache.harmony.awt.gl.render package. The JavaShapeRasterizer
+ * class splits an object implementing a Shape interface into a set of rectangles and
+ * produces a MultiRectArea object. The JavaLineRasterizer class makes line drawing
+ * more accurate and processes lines with strokes, which are instances of the BasicStroke
+ * class.
+ * </p>
+ * <p>
+ * To port the shape drawing to another platform you just need to override
+ * rectangle-drawing methods. However, if your operating system has functions to draw
+ * particular shapes, you can optimize your subclass of the CommonGraphics2D class by
+ * using this functionality in overridden methods.
+ * </p>
+
+ * <h3>Blitters</h3>
+ * <p>
+ * Blitter classes draw images on the display or buffered images. All blitters inherit
+ * the org.apache.harmony.awt.gl.render.Blitter interface.
+ * </p>
+ * <p>Blitters are divided into:
+ * <ul>
+ * <li>Native blitters for simple types of images, which the underlying native library
+ * can draw.</li>
+ * <li>Java* blitters for those types of images, which the underlying native library
+ * cannot handle.</li>
+ * </ul></p>
+ * <p>
+ * DRL Java 2D* also uses blitters to fill the shapes and the user-defined subclasses
+ * of the java.awt.Paint class with paints, which the system does not support.
+ * </p>
+ *
+ *<h3>Text Renderers</h3>
+ *<p>
+ *Text renderers draw strings and glyph vectors. All text renderers are subclasses
+ *of the org.apache.harmony.awt.gl.TextRenderer class.
+ *</p>
+ *
+ */
+public abstract class CommonGraphics2D extends Graphics2D {
+ protected Surface dstSurf = null;
+ protected Blitter blitter = NullBlitter.getInstance();
+ protected RenderingHints hints = new RenderingHints(null);
+
+ // Clipping things
+ protected MultiRectArea clip = null;
+
+ protected Paint paint = Color.WHITE;
+ protected Color fgColor = Color.WHITE;
+ protected Color bgColor = Color.BLACK;
+
+ protected Composite composite = AlphaComposite.SrcOver;
+
+ protected Stroke stroke = new BasicStroke();
+
+ //TODO: Think more about FontRenderContext
+ protected FontRenderContext frc = new FontRenderContext(null, false, false);
+
+ protected JavaShapeRasterizer jsr = new JavaShapeRasterizer();
+
+ protected Font font = new Font("Dialog", Font.PLAIN, 12);; //$NON-NLS-1$
+
+ protected TextRenderer jtr = JavaTextRenderer.inst;
+
+ // Current graphics transform
+ protected AffineTransform transform = new AffineTransform();
+ protected double[] matrix = new double[6];
+
+ // Original user->device translation as transform and point
+ //public AffineTransform origTransform = new AffineTransform();
+ public Point origPoint = new Point(0, 0);
+
+
+ // Print debug output or not
+ protected static final boolean debugOutput = "1".equals(System.getProperty("g2d.debug")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Constructors
+ protected CommonGraphics2D() {
+ }
+
+ protected CommonGraphics2D(int tx, int ty) {
+ this(tx, ty, null);
+ }
+
+ protected CommonGraphics2D(int tx, int ty, MultiRectArea clip) {
+ setTransform(AffineTransform.getTranslateInstance(tx, ty));
+ //origTransform = AffineTransform.getTranslateInstance(tx, ty);
+ origPoint = new Point(tx, ty);
+ setClip(clip);
+ }
+
+ // Public methods
+ @Override
+ public void addRenderingHints(Map<?,?> hints) {
+ this.hints.putAll(hints);
+ }
+
+ @Override
+ public void clearRect(int x, int y, int width, int height) {
+ Color c = getColor();
+ Paint p = getPaint();
+ setColor(getBackground());
+ fillRect(x, y, width, height);
+ setColor(c);
+ setPaint(p);
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.clearRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ }
+
+ @Override
+ public void clipRect(int x, int y, int width, int height) {
+ clip(new Rectangle(x, y, width, height));
+ }
+
+
+ @Override
+ public void clip(Shape s) {
+ if (s == null) {
+ clip = null;
+ return;
+ }
+
+ MultiRectArea mra = null;
+ if (s instanceof MultiRectArea) {
+ mra = new MultiRectArea((MultiRectArea)s);
+ mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+ } else {
+ int type = transform.getType();
+ if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY |
+ AffineTransform.TYPE_TRANSLATION)) != 0){
+ mra = new MultiRectArea((Rectangle)s);
+ if(type == AffineTransform.TYPE_TRANSLATION){
+ mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+ }
+ } else {
+ s = transform.createTransformedShape(s);
+ mra = jsr.rasterize(s, 0.5);
+ }
+ }
+
+ if (clip == null) {
+ setTransformedClip(mra);
+ } else {
+ clip.intersect(mra);
+ setTransformedClip(clip);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ // Do nothing for Java only classes
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Draw methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void draw(Shape s) {
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) {
+ //TODO: Think about drawing the shape in one fillMultiRectArea call
+ BasicStroke bstroke = (BasicStroke)stroke;
+ JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase());
+ PathIterator pi = s.getPathIterator(transform, 0.5);
+ float []points = new float[6];
+ int x1 = Integer.MIN_VALUE;
+ int y1 = Integer.MIN_VALUE;
+ int cx1 = Integer.MIN_VALUE;
+ int cy1 = Integer.MIN_VALUE;
+ while (!pi.isDone()) {
+ switch (pi.currentSegment(points)) {
+ case PathIterator.SEG_MOVETO:
+ x1 = (int)Math.floor(points[0]);
+ y1 = (int)Math.floor(points[1]);
+ cx1 = x1;
+ cy1 = y1;
+ break;
+ case PathIterator.SEG_LINETO:
+ int x2 = (int)Math.floor(points[0]);
+ int y2 = (int)Math.floor(points[1]);
+ fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false));
+ x1 = x2;
+ y1 = y2;
+ break;
+ case PathIterator.SEG_CLOSE:
+ x2 = cx1;
+ y2 = cy1;
+ fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false));
+ x1 = x2;
+ y1 = y2;
+ break;
+ }
+ pi.next();
+ }
+ } else {
+ s = stroke.createStrokedShape(s);
+ s = transform.createTransformedShape(s);
+ fillMultiRectArea(jsr.rasterize(s, 0.5));
+ }
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int sa, int ea) {
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 &&
+ ((BasicStroke)stroke).getDashArray() == null &&
+ (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) {
+ Point p = new Point(x, y);
+ transform.transform(p, p);
+ MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, sa, ea, clip);
+ fillMultiRectArea(mra);
+ return;
+ }
+ draw(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.OPEN));
+ }
+
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
+ return drawImage(image, x, y, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(width == 0 || height == 0) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ if(w == width && h == height){
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)width / w, (float)height / h);
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ ImageObserver imageObserver) {
+ return drawImage(image, x, y, width, height, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+
+ int dstX = dx1;
+ int dstY = dy1;
+ int srcX = sx1;
+ int srcY = sy1;
+
+ int dstW = dx2 - dx1;
+ int dstH = dy2 - dy1;
+ int srcW = sx2 - sx1;
+ int srcH = sy2 - sy1;
+
+ if(srcW == dstW && srcH == dstH){
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
+
+ return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
+ imageObserver);
+ }
+
+ @Override
+ public void drawImage(BufferedImage bufImage, BufferedImageOp op,
+ int x, int y) {
+
+ if(bufImage == null) {
+ return;
+ }
+
+ if(op == null) {
+ drawImage(bufImage, x, y, null);
+ } else if(op instanceof AffineTransformOp){
+ AffineTransformOp atop = (AffineTransformOp) op;
+ AffineTransform xform = atop.getTransform();
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(), xform,
+ composite, null, clip);
+ } else {
+ bufImage = op.filter(bufImage, null);
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, null, clip);
+ }
+ }
+
+ @Override
+ public boolean drawImage(Image image, AffineTransform trans,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(trans == null || trans.isIdentity()) {
+ return drawImage(image, 0, 0, imageObserver);
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ AffineTransform xform = (AffineTransform) transform.clone();
+ xform.concatenate(trans);
+ blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
+ null, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.drawLine("+x1+", "+y1+", "+x2+", "+y2+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) {
+ BasicStroke bstroke = (BasicStroke)stroke;
+ Point p1 = new Point(x1, y1);
+ Point p2 = new Point(x2, y2);
+ transform.transform(p1, p1);
+ transform.transform(p2, p2);
+ JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase());
+ MultiRectArea mra = JavaLineRasterizer.rasterize(p1.x, p1.y, p2.x, p2.y, null, ld, false);
+ fillMultiRectArea(mra);
+ return;
+ }
+ draw(new Line2D.Float(x1, y1, x2, y2));
+ }
+
+ @Override
+ public void drawOval(int x, int y, int width, int height) {
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 &&
+ ((BasicStroke)stroke).getDashArray() == null &&
+ (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) {
+ Point p = new Point(x, y);
+ transform.transform(p, p);
+ MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, 0, 360, clip);
+ fillMultiRectArea(mra);
+ return;
+ }
+ draw(new Ellipse2D.Float(x, y, width, height));
+ }
+
+ @Override
+ public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ draw(new Polygon(xpoints, ypoints, npoints));
+ }
+
+ @Override
+ public void drawPolygon(Polygon polygon) {
+ draw(polygon);
+ }
+
+ @Override
+ public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
+ for (int i = 0; i < npoints-1; i++) {
+ drawLine(xpoints[i], ypoints[i], xpoints[i+1], ypoints[i+1]);
+ }
+ }
+
+ @Override
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ if (img == null) {
+ return;
+ }
+
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ if (scaleX == 1 && scaleY == 1) {
+ drawRenderedImage(img.createDefaultRendering(), xform);
+ } else {
+ int width = (int)Math.round(img.getWidth()*scaleX);
+ int height = (int)Math.round(img.getHeight()*scaleY);
+ xform = (AffineTransform)xform.clone();
+ xform.scale(1, 1);
+ drawRenderedImage(img.createScaledRendering(width, height, null), xform);
+ }
+ }
+
+ @Override
+ public void drawRenderedImage(RenderedImage rimg, AffineTransform xform) {
+ if (rimg == null) {
+ return;
+ }
+
+ Image img = null;
+
+ if (rimg instanceof Image) {
+ img = (Image)rimg;
+ } else {
+ //TODO: Create new class to provide Image interface for RenderedImage or rewrite this method
+ img = new BufferedImage(rimg.getColorModel(), rimg.copyData(null), false, null);
+ }
+
+ drawImage(img, xform, null);
+ }
+
+ @Override
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.drawRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+ }
+
+ draw(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+ }
+
+
+
+
+
+ /***************************************************************************
+ *
+ * String methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+ GlyphVector gv = font.createGlyphVector(frc, iterator);
+ drawGlyphVector(gv, x, y);
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ drawString(iterator, (float)x, (float)y);
+ }
+
+ @Override
+ public void drawString(String str, int x, int y) {
+ drawString(str, (float)x, (float)y);
+ }
+
+ @Override
+ public void drawString(String str, float x, float y) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.drawString("+str+", "+x+", "+y+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ AffineTransform at = (AffineTransform)this.getTransform().clone();
+ AffineTransform fontTransform = font.getTransform();
+ at.concatenate(fontTransform);
+
+ double[] matrix = new double[6];
+ if (!at.isIdentity()){
+
+ int atType = at.getType();
+ at.getMatrix(matrix);
+
+ // TYPE_TRANSLATION
+ if (atType == AffineTransform.TYPE_TRANSLATION){
+ jtr.drawString(this, str,
+ (float)(x+fontTransform.getTranslateX()),
+ (float)(y+fontTransform.getTranslateY()));
+ return;
+ }
+ // TODO: we use slow type of drawing strings when Font object
+ // in Graphics has transforms, we just fill outlines. New textrenderer
+ // is to be implemented.
+ Shape sh = font.createGlyphVector(this.getFontRenderContext(), str).getOutline(x, y);
+ this.fill(sh);
+
+ } else {
+ jtr.drawString(this, str, x, y);
+ }
+
+ }
+
+ @Override
+ public void drawGlyphVector(GlyphVector gv, float x, float y) {
+
+ AffineTransform at = gv.getFont().getTransform();
+
+ double[] matrix = new double[6];
+ if ((at != null) && (!at.isIdentity())){
+
+ int atType = at.getType();
+ at.getMatrix(matrix);
+
+ // TYPE_TRANSLATION
+ if ((atType == AffineTransform.TYPE_TRANSLATION) &&
+ ((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){
+ jtr.drawGlyphVector(this, gv, (int)(x+matrix[4]), (int)(y+matrix[5]));
+ return;
+ }
+ } else {
+ if (((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){
+ jtr.drawGlyphVector(this, gv, x, y);
+ return;
+ }
+ }
+
+ // TODO: we use slow type of drawing strings when Font object
+ // in Graphics has transforms, we just fill outlines. New textrenderer
+ // is to be implemented.
+
+ Shape sh = gv.getOutline(x, y);
+ this.fill(sh);
+
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Fill methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void fill(Shape s) {
+ s = transform.createTransformedShape(s);
+ MultiRectArea mra = jsr.rasterize(s, 0.5);
+ fillMultiRectArea(mra);
+ }
+
+ @Override
+ public void fillArc(int x, int y, int width, int height, int sa, int ea) {
+ fill(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.PIE));
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ fill(new Ellipse2D.Float(x, y, width, height));
+ }
+
+ @Override
+ public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ fill(new Polygon(xpoints, ypoints, npoints));
+ }
+
+ @Override
+ public void fillPolygon(Polygon polygon) {
+ fill(polygon);
+ }
+
+ @Override
+ public void fillRect(int x, int y, int width, int height) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.fillRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+
+ fill(new Rectangle(x, y, width, height));
+ }
+
+ @Override
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.fillRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+ }
+
+ fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Get methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public Color getBackground() {
+ return bgColor;
+ }
+
+ @Override
+ public Shape getClip() {
+ if (clip == null) {
+ return null;
+ }
+
+ MultiRectArea res = new MultiRectArea(clip);
+ res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY()));
+ return res;
+ }
+
+ @Override
+ public Rectangle getClipBounds() {
+ if (clip == null) {
+ return null;
+ }
+
+ Rectangle res = (Rectangle) clip.getBounds().clone();
+ res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY()));
+ return res;
+ }
+
+ @Override
+ public Color getColor() {
+ return fgColor;
+ }
+
+ @Override
+ public Composite getComposite() {
+ return composite;
+ }
+
+ @Override
+ public Font getFont() {
+ return font;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public FontMetrics getFontMetrics(Font font) {
+ return Toolkit.getDefaultToolkit().getFontMetrics(font);
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return frc;
+ }
+
+ @Override
+ public Paint getPaint() {
+ return paint;
+ }
+
+ @Override
+ public Object getRenderingHint(RenderingHints.Key key) {
+ return hints.get(key);
+ }
+
+ @Override
+ public RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ @Override
+ public Stroke getStroke() {
+ return stroke;
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ return (AffineTransform)transform.clone();
+ }
+
+ @Override
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ //TODO: Implement method....
+ return false;
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Transformation methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void rotate(double theta) {
+ transform.rotate(theta);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void rotate(double theta, double x, double y) {
+ transform.rotate(theta, x, y);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void scale(double sx, double sy) {
+ transform.scale(sx, sy);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void shear(double shx, double shy) {
+ transform.shear(shx, shy);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void transform(AffineTransform at) {
+ transform.concatenate(at);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void translate(double tx, double ty) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ transform.translate(tx, ty);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void translate(int tx, int ty) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ transform.translate(tx, ty);
+ transform.getMatrix(matrix);
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Set methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void setBackground(Color color) {
+ bgColor = color;
+ }
+
+ @Override
+ public void setClip(int x, int y, int width, int height) {
+ setClip(new Rectangle(x, y, width, height));
+ }
+
+ @Override
+ public void setClip(Shape s) {
+ if (s == null) {
+ setTransformedClip(null);
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.setClip(null)"); //$NON-NLS-1$
+ }
+ return;
+ }
+
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.setClip("+s.getBounds()+")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (s instanceof MultiRectArea) {
+ MultiRectArea nclip = new MultiRectArea((MultiRectArea)s);
+ nclip.translate(Math.round((float)transform.getTranslateX()), Math.round((float)transform.getTranslateY()));
+ setTransformedClip(nclip);
+ } else {
+ int type = transform.getType();
+ if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY |
+ AffineTransform.TYPE_TRANSLATION)) != 0){
+ MultiRectArea nclip = new MultiRectArea((Rectangle)s);
+ if(type == AffineTransform.TYPE_TRANSLATION){
+ nclip.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+ }
+ setTransformedClip(nclip);
+ } else {
+ s = transform.createTransformedShape(s);
+ setTransformedClip(jsr.rasterize(s, 0.5));
+ }
+ }
+ }
+
+ @Override
+ public void setColor(Color color) {
+ if (color != null) {
+ fgColor = color;
+ paint = color;
+ }
+ }
+
+ @Override
+ public void setComposite(Composite composite) {
+ this.composite = composite;
+ }
+
+ @Override
+ public void setFont(Font font) {
+ this.font = font;
+ }
+
+ @Override
+ public void setPaint(Paint paint) {
+ if (paint == null)
+ return;
+
+ this.paint = paint;
+ if (paint instanceof Color) {
+ fgColor = (Color)paint;
+ }
+ }
+
+ @Override
+ public void setPaintMode() {
+ composite = AlphaComposite.SrcOver;
+ }
+
+ @Override
+ public void setRenderingHint(RenderingHints.Key key, Object value) {
+ hints.put(key, value);
+ }
+
+ @Override
+ public void setRenderingHints(Map<?,?> hints) {
+ this.hints.clear();
+ this.hints.putAll(hints);
+ }
+
+ @Override
+ public void setStroke(Stroke stroke) {
+ this.stroke = stroke;
+ }
+
+ @Override
+ public void setTransform(AffineTransform transform) {
+ this.transform = transform;
+
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void setXORMode(Color color) {
+ composite = new XORComposite(color);
+ }
+
+
+ // Protected methods
+ protected void setTransformedClip(MultiRectArea clip) {
+ this.clip = clip;
+ }
+
+ /**
+ * This method fills the given MultiRectArea with current paint.
+ * It calls fillMultiRectAreaColor and fillMultiRectAreaPaint
+ * methods depending on the type of current paint.
+ * @param mra MultiRectArea to fill
+ */
+ protected void fillMultiRectArea(MultiRectArea mra) {
+ if (clip != null) {
+ mra.intersect(clip);
+ }
+
+ // Return if all stuff is clipped
+ if (mra.rect[0] < 5) {
+ return;
+ }
+
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.fillMultiRectArea("+mra+")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (paint instanceof Color){
+ fillMultiRectAreaColor(mra);
+ }else{
+ fillMultiRectAreaPaint(mra);
+ }
+ }
+
+ /**
+ * This method fills the given MultiRectArea with solid color.
+ * @param mra MultiRectArea to fill
+ */
+ protected void fillMultiRectAreaColor(MultiRectArea mra) {
+ fillMultiRectAreaPaint(mra);
+ }
+
+ /**
+ * This method fills the given MultiRectArea with any paint.
+ * @param mra MultiRectArea to fill
+ */
+ protected void fillMultiRectAreaPaint(MultiRectArea mra) {
+ Rectangle rec = mra.getBounds();
+ int x = rec.x;
+ int y = rec.y;
+ int w = rec.width;
+ int h = rec.height;
+ if(w <= 0 || h <= 0) {
+ return;
+ }
+ PaintContext pc = paint.createContext(null, rec, rec, transform, hints);
+ Raster r = pc.getRaster(x, y, w, h);
+ WritableRaster wr;
+ if(r instanceof WritableRaster){
+ wr = (WritableRaster) r;
+ }else{
+ wr = r.createCompatibleWritableRaster();
+ wr.setRect(r);
+ }
+ Surface srcSurf = new ImageSurface(pc.getColorModel(), wr);
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ composite, null, mra);
+ srcSurf.dispose();
+ }
+
+ /**
+ * Copies graphics class fields.
+ * Used in create method
+ *
+ * @param copy Graphics class to copy
+ */
+ protected void copyInternalFields(CommonGraphics2D copy) {
+ if (clip == null) {
+ copy.setTransformedClip(null);
+ } else {
+ copy.setTransformedClip(new MultiRectArea(clip));
+ }
+ copy.setBackground(bgColor);
+ copy.setColor(fgColor);
+ copy.setPaint(paint);
+ copy.setComposite(composite);
+ copy.setStroke(stroke);
+ copy.setFont(font);
+ copy.setTransform(new AffineTransform(transform));
+ //copy.origTransform = new AffineTransform(origTransform);
+ copy.origPoint = new Point(origPoint);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java b/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
new file mode 100644
index 0000000..27e3ef0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko, Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.peer.FontPeer;
+
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+/**
+ * Common GraphicsFactory implementation
+ *
+ */
+public abstract class CommonGraphics2DFactory implements GraphicsFactory {
+
+ // static instance of CommonGraphics2DFactory
+ public static CommonGraphics2DFactory inst;
+
+ /**
+ * Returns FontMetrics object that keeps metrics of the specified font.
+ *
+ * @param font specified Font
+ * @return FontMetrics object corresponding to the specified Font object
+ */
+ public FontMetrics getFontMetrics(Font font) {
+ FontMetrics fm;
+ for (FontMetrics element : cacheFM) {
+ fm = element;
+ if (fm == null){
+ break;
+ }
+
+ if (fm.getFont().equals(font)){
+ return fm;
+ }
+ }
+ fm = new FontMetricsImpl(font);
+
+ System.arraycopy(cacheFM, 0, cacheFM, 1, cacheFM.length -1);
+ cacheFM[0] = fm;
+
+ return fm;
+ }
+ // Font methods
+
+ public FontPeer getFontPeer(Font font) {
+ return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize());
+ }
+
+ /**
+ * Embeds font from gile with specified path into the system.
+ *
+ * @param fontFilePath path to the font file
+ * @return Font object that was created from the file.
+ */
+ public abstract Font embedFont(String fontFilePath);
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java b/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
new file mode 100644
index 0000000..5c78e50
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko, Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
+
+/**
+ * Common GraphicsEnvironment implementation
+ *
+ */
+public abstract class CommonGraphicsEnvironment extends GraphicsEnvironment {
+
+ @Override
+ public Graphics2D createGraphics(BufferedImage bufferedImage) {
+ return new BufferedImageGraphics2D(bufferedImage);
+ }
+
+ @Override
+ public String[] getAvailableFontFamilyNames(Locale locale) {
+ Font[] fonts = getAllFonts();
+ ArrayList<String> familyNames = new ArrayList<String>();
+
+ for (Font element : fonts) {
+ String name = element.getFamily(locale);
+ if (!familyNames.contains(name)) {
+ familyNames.add(name);
+ }
+ }
+
+ return familyNames.toArray(new String[familyNames.size()]);
+ }
+
+ @Override
+ public Font[] getAllFonts() {
+ return CommonGraphics2DFactory.inst.getFontManager().getAllFonts();
+ }
+
+ @Override
+ public String[] getAvailableFontFamilyNames() {
+ return CommonGraphics2DFactory.inst.getFontManager().getAllFamilies();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/Crossing.java b/awt/org/apache/harmony/awt/gl/Crossing.java
new file mode 100644
index 0000000..ae7fb0e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/Crossing.java
@@ -0,0 +1,889 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+
+public class Crossing {
+
+ /**
+ * Allowable tolerance for bounds comparison
+ */
+ static final double DELTA = 1E-5;
+
+ /**
+ * If roots have distance less then <code>ROOT_DELTA</code> they are double
+ */
+ static final double ROOT_DELTA = 1E-10;
+
+ /**
+ * Rectangle cross segment
+ */
+ public static final int CROSSING = 255;
+
+ /**
+ * Unknown crossing result
+ */
+ static final int UNKNOWN = 254;
+
+ /**
+ * Solves quadratic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveQuad(double eqn[], double res[]) {
+ double a = eqn[2];
+ double b = eqn[1];
+ double c = eqn[0];
+ int rc = 0;
+ if (a == 0.0) {
+ if (b == 0.0) {
+ return -1;
+ }
+ res[rc++] = -c / b;
+ } else {
+ double d = b * b - 4.0 * a * c;
+ // d < 0.0
+ if (d < 0.0) {
+ return 0;
+ }
+ d = Math.sqrt(d);
+ res[rc++] = (- b + d) / (a * 2.0);
+ // d != 0.0
+ if (d != 0.0) {
+ res[rc++] = (- b - d) / (a * 2.0);
+ }
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Solves cubic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveCubic(double eqn[], double res[]) {
+ double d = eqn[3];
+ if (d == 0) {
+ return solveQuad(eqn, res);
+ }
+ double a = eqn[2] / d;
+ double b = eqn[1] / d;
+ double c = eqn[0] / d;
+ int rc = 0;
+
+ double Q = (a * a - 3.0 * b) / 9.0;
+ double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
+ double Q3 = Q * Q * Q;
+ double R2 = R * R;
+ double n = - a / 3.0;
+
+ if (R2 < Q3) {
+ double t = Math.acos(R / Math.sqrt(Q3)) / 3.0;
+ double p = 2.0 * Math.PI / 3.0;
+ double m = -2.0 * Math.sqrt(Q);
+ res[rc++] = m * Math.cos(t) + n;
+ res[rc++] = m * Math.cos(t + p) + n;
+ res[rc++] = m * Math.cos(t - p) + n;
+ } else {
+// Debug.println("R2 >= Q3 (" + R2 + "/" + Q3 + ")");
+ double A = Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0);
+ if (R > 0.0) {
+ A = -A;
+ }
+// if (A == 0.0) {
+ if (-ROOT_DELTA < A && A < ROOT_DELTA) {
+ res[rc++] = n;
+ } else {
+ double B = Q / A;
+ res[rc++] = A + B + n;
+// if (R2 == Q3) {
+ double delta = R2 - Q3;
+ if (-ROOT_DELTA < delta && delta < ROOT_DELTA) {
+ res[rc++] = - (A + B) / 2.0 + n;
+ }
+ }
+
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Excludes double roots. Roots are double if they lies enough close with each other.
+ * @param res - the roots
+ * @param rc - the roots count
+ * @return new roots count
+ */
+ static int fixRoots(double res[], int rc) {
+ int tc = 0;
+ for(int i = 0; i < rc; i++) {
+ out: {
+ for(int j = i + 1; j < rc; j++) {
+ if (isZero(res[i] - res[j])) {
+ break out;
+ }
+ }
+ res[tc++] = res[i];
+ }
+ }
+ return tc;
+ }
+
+ /**
+ * QuadCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class QuadCurve {
+
+ double ax, ay, bx, by;
+ double Ax, Ay, Bx, By;
+
+ public QuadCurve(double x1, double y1, double cx, double cy, double x2, double y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx - x1;
+ by = cy - y1;
+
+ Bx = bx + bx; // Bx = 2.0 * bx
+ Ax = ax - Bx; // Ax = ax - 2.0 * bx
+
+ By = by + by; // By = 2.0 * by
+ Ay = ay - By; // Ay = ay - 2.0 * by
+ }
+
+ int cross(double res[], int rc, double py1, double py2) {
+ int cross = 0;
+
+ for (int i = 0; i < rc; i++) {
+ double t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : ax - bx) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != bx ? ax - bx : bx) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ double ry = t * (t * Ay + By);
+ // ry = t * t * Ay + t * By
+ if (ry > py2) {
+ double rxt = t * Ax + bx;
+ // rxt = 2.0 * t * Ax + Bx = 2.0 * t * Ax + 2.0 * bx
+ if (rxt > -DELTA && rxt < DELTA) {
+ continue;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } // for
+
+ return cross;
+ }
+
+ int solvePoint(double res[], double px) {
+ double eqn[] = {-px, Bx, Ax};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtrem(double res[]) {
+ int rc = 0;
+ if (Ax != 0.0) {
+ res[rc++] = - Bx / (Ax + Ax);
+ }
+ if (Ay != 0.0) {
+ res[rc++] = - By / (Ay + Ay);
+ }
+ return rc;
+ }
+
+ int addBound(double bound[], int bc, double res[], int rc, double minX, double maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ double t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ double rx = t * (t * Ax + Bx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * Ay + By);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * CubicCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class CubicCurve {
+
+ double ax, ay, bx, by, cx, cy;
+ double Ax, Ay, Bx, By, Cx, Cy;
+ double Ax3, Bx2;
+
+ public CubicCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx1 - x1;
+ by = cy1 - y1;
+ cx = cx2 - x1;
+ cy = cy2 - y1;
+
+ Cx = bx + bx + bx; // Cx = 3.0 * bx
+ Bx = cx + cx + cx - Cx - Cx; // Bx = 3.0 * cx - 6.0 * bx
+ Ax = ax - Bx - Cx; // Ax = ax - 3.0 * cx + 3.0 * bx
+
+ Cy = by + by + by; // Cy = 3.0 * by
+ By = cy + cy + cy - Cy - Cy; // By = 3.0 * cy - 6.0 * by
+ Ay = ay - By - Cy; // Ay = ay - 3.0 * cy + 3.0 * by
+
+ Ax3 = Ax + Ax + Ax;
+ Bx2 = Bx + Bx;
+ }
+
+ int cross(double res[], int rc, double py1, double py2) {
+ int cross = 0;
+ for (int i = 0; i < rc; i++) {
+ double t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : (cx != bx ? cx - bx : ax - cx)) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != cx ? ax - cx : (cx != bx ? cx - bx : bx)) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ double ry = t * (t * (t * Ay + By) + Cy);
+ // ry = t * t * t * Ay + t * t * By + t * Cy
+ if (ry > py2) {
+ double rxt = t * (t * Ax3 + Bx2) + Cx;
+ // rxt = 3.0 * t * t * Ax + 2.0 * t * Bx + Cx
+ if (rxt > -DELTA && rxt < DELTA) {
+ rxt = t * (Ax3 + Ax3) + Bx2;
+ // rxt = 6.0 * t * Ax + 2.0 * Bx
+ if (rxt < -DELTA || rxt > DELTA) {
+ // Inflection point
+ continue;
+ }
+ rxt = ax;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } //for
+
+ return cross;
+ }
+
+ int solvePoint(double res[], double px) {
+ double eqn[] = {-px, Cx, Bx, Ax};
+ return solveCubic(eqn, res);
+ }
+
+ int solveExtremX(double res[]) {
+ double eqn[] = {Cx, Bx2, Ax3};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtremY(double res[]) {
+ double eqn[] = {Cy, By + By, Ay + Ay + Ay};
+ return solveQuad(eqn, res);
+ }
+
+ int addBound(double bound[], int bc, double res[], int rc, double minX, double maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ double t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ double rx = t * (t * (t * Ax + Bx) + Cx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * (t * Ay + By) + Cy);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross line.
+ */
+ public static int crossLine(double x1, double y1, double x2, double y2, double x, double y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < x2) ||
+ (x > x1 && x > x2) ||
+ (y > y1 && y > y2) ||
+ (x1 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < y2) {
+ } else {
+ // INSIDE
+ if ((y2 - y1) * (x - x1) / (x2 - x1) <= y - y1) {
+ // INSIDE-UP
+ return 0;
+ }
+ }
+
+ // START
+ if (x == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // END
+ if (x == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ // INSIDE-DOWN
+ return x1 < x2 ? 1 : -1;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross quard curve
+ */
+ public static int crossQuad(double x1, double y1, double cx, double cy, double x2, double y2, double x, double y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx && x < x2) ||
+ (x > x1 && x > cx && x > x2) ||
+ (y > y1 && y > cy && y > y2) ||
+ (x1 == cx && cx == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ double px = x - x1;
+ double py = y - y1;
+ double res[] = new double[3];
+ int rc = c.solvePoint(res, px);
+
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross cubic curve
+ */
+ public static int crossCubic(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2, double x, double y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx1 && x < cx2 && x < x2) ||
+ (x > x1 && x > cx1 && x > cx2 && x > x2) ||
+ (y > y1 && y > cy1 && y > cy2 && y > y2) ||
+ (x1 == cx1 && cx1 == cx2 && cx2 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy1 && y < cy2 && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ double px = x - x1;
+ double py = y - y1;
+ double res[] = new double[3];
+ int rc = c.solvePoint(res, px);
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross path
+ */
+ public static int crossPath(PathIterator p, double x, double y) {
+ int cross = 0;
+ double mx, my, cx, cy;
+ mx = my = cx = cy = 0.0;
+ double coords[] = new double[6];
+
+ while (!p.isDone()) {
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ cross += crossLine(cx, cy, cx = coords[0], cy = coords[1], x, y);
+ break;
+ case PathIterator.SEG_QUADTO:
+ cross += crossQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], x, y);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ cross += crossCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], x, y);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ cross += crossLine(cx, cy, cx = mx, cy = my, x, y);
+ }
+ break;
+ }
+ p.next();
+ }
+ if (cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross shape
+ */
+ public static int crossShape(Shape s, double x, double y) {
+ if (!s.getBounds2D().contains(x, y)) {
+ return 0;
+ }
+ return crossPath(s.getPathIterator(null), x, y);
+ }
+
+ /**
+ * Returns true if value enough small
+ */
+ public static boolean isZero(double val) {
+ return -DELTA < val && val < DELTA;
+ }
+
+ /**
+ * Sort bound array
+ */
+ static void sortBound(double bound[], int bc) {
+ for(int i = 0; i < bc - 4; i += 4) {
+ int k = i;
+ for(int j = i + 4; j < bc; j += 4) {
+ if (bound[k] > bound[j]) {
+ k = j;
+ }
+ }
+ if (k != i) {
+ double tmp = bound[i];
+ bound[i] = bound[k];
+ bound[k] = tmp;
+ tmp = bound[i + 1];
+ bound[i + 1] = bound[k + 1];
+ bound[k + 1] = tmp;
+ tmp = bound[i + 2];
+ bound[i + 2] = bound[k + 2];
+ bound[k + 2] = tmp;
+ tmp = bound[i + 3];
+ bound[i + 3] = bound[k + 3];
+ bound[k + 3] = tmp;
+ }
+ }
+ }
+
+ /**
+ * Returns are bounds intersect or not intersect rectangle
+ */
+ static int crossBound(double bound[], int bc, double py1, double py2) {
+
+ // LEFT/RIGHT
+ if (bc == 0) {
+ return 0;
+ }
+
+ // Check Y coordinate
+ int up = 0;
+ int down = 0;
+ for(int i = 2; i < bc; i += 4) {
+ if (bound[i] < py1) {
+ up++;
+ continue;
+ }
+ if (bound[i] > py2) {
+ down++;
+ continue;
+ }
+ return CROSSING;
+ }
+
+ // UP
+ if (down == 0) {
+ return 0;
+ }
+
+ if (up != 0) {
+ // bc >= 2
+ sortBound(bound, bc);
+ boolean sign = bound[2] > py2;
+ for(int i = 6; i < bc; i += 4) {
+ boolean sign2 = bound[i] > py2;
+ if (sign != sign2 && bound[i + 1] != bound[i - 3]) {
+ return CROSSING;
+ }
+ sign = sign2;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross line or the are intersect
+ */
+ public static int intersectLine(double x1, double y1, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < y2) {
+ } else {
+
+ // INSIDE
+ if (x1 == x2) {
+ return CROSSING;
+ }
+
+ // Build bound
+ double bx1, bx2;
+ if (x1 < x2) {
+ bx1 = x1 < rx1 ? rx1 : x1;
+ bx2 = x2 < rx2 ? x2 : rx2;
+ } else {
+ bx1 = x2 < rx1 ? rx1 : x2;
+ bx2 = x1 < rx2 ? x1 : rx2;
+ }
+ double k = (y2 - y1) / (x2 - x1);
+ double by1 = k * (bx1 - x1) + y1;
+ double by2 = k * (bx2 - x1) + y1;
+
+ // BOUND-UP
+ if (by1 < ry1 && by2 < ry1) {
+ return 0;
+ }
+
+ // BOUND-DOWN
+ if (by1 > ry2 && by2 > ry2) {
+ } else {
+ return CROSSING;
+ }
+ }
+
+ // EMPTY
+ if (x1 == x2) {
+ return 0;
+ }
+
+ // CURVE-START
+ if (rx1 == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // CURVE-END
+ if (rx1 == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross quad curve or the are intersect
+ */
+ public static int intersectQuad(double x1, double y1, double cx, double cy, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+ // LEFT/RIGHT/UP ------------------------------------------------------
+ if ((rx2 < x1 && rx2 < cx && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN ---------------------------------------------------------------
+ if (ry2 < y1 && ry2 < cy && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE -------------------------------------------------------------
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ double px1 = rx1 - x1;
+ double py1 = ry1 - y1;
+ double px2 = rx2 - x1;
+ double py2 = ry2 - y1;
+
+ double res1[] = new double[3];
+ double res2[] = new double[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // INSIDE-LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ // Build bound --------------------------------------------------------
+ double minX = px1 - DELTA;
+ double maxX = px2 + DELTA;
+ double bound[] = new double[28];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extremal points`
+ rc2 = c.solveExtrem(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 4;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 5;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross cubic curve or the are intersect
+ */
+ public static int intersectCubic(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < cx1 && rx2 < cx2 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx1 && rx1 > cx2 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy1 && ry1 > cy2 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < cy1 && ry2 < cy2 && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ double px1 = rx1 - x1;
+ double py1 = ry1 - y1;
+ double px2 = rx2 - x1;
+ double py2 = ry2 - y1;
+
+ double res1[] = new double[3];
+ double res2[] = new double[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ double minX = px1 - DELTA;
+ double maxX = px2 + DELTA;
+
+ // Build bound --------------------------------------------------------
+ double bound[] = new double[40];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extrimal points
+ rc2 = c.solveExtremX(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ rc2 = c.solveExtremY(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 4);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 6;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 7;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross path or the are intersect
+ */
+ public static int intersectPath(PathIterator p, double x, double y, double w, double h) {
+
+ int cross = 0;
+ int count;
+ double mx, my, cx, cy;
+ mx = my = cx = cy = 0.0;
+ double coords[] = new double[6];
+
+ double rx1 = x;
+ double ry1 = y;
+ double rx2 = x + w;
+ double ry2 = y + h;
+
+ while (!p.isDone()) {
+ count = 0;
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ count = intersectLine(cx, cy, cx = coords[0], cy = coords[1], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_QUADTO:
+ count = intersectQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ count = intersectCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ cx = mx;
+ cy = my;
+ break;
+ }
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ p.next();
+ }
+ if (cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross shape or the are intersect
+ */
+ public static int intersectShape(Shape s, double x, double y, double w, double h) {
+ if (!s.getBounds2D().intersects(x, y, w, h)) {
+ return 0;
+ }
+ return intersectPath(s.getPathIterator(null), x, y, w, h);
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for non zero path rule
+ */
+ public static boolean isInsideNonZero(int cross) {
+ return cross != 0;
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for even-odd path rule
+ */
+ public static boolean isInsideEvenOdd(int cross) {
+ return (cross & 1) != 0;
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/GLVolatileImage.java b/awt/org/apache/harmony/awt/gl/GLVolatileImage.java
new file mode 100644
index 0000000..177be23
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/GLVolatileImage.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.image.*;
+
+import org.apache.harmony.awt.gl.Surface;
+
+public abstract class GLVolatileImage extends VolatileImage {
+
+ public abstract Surface getImageSurface();
+}
diff --git a/awt/org/apache/harmony/awt/gl/ICompositeContext.java b/awt/org/apache/harmony/awt/gl/ICompositeContext.java
new file mode 100644
index 0000000..fc5631f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/ICompositeContext.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.render.NativeImageBlitter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent implementation of the CompositeContext interface
+ */
+public class ICompositeContext implements CompositeContext {
+ Composite composite;
+ ColorModel srcCM, dstCM;
+ ImageSurface srcSurf, dstSurf;
+
+ public ICompositeContext(Composite comp, ColorModel src, ColorModel dst){
+ composite = comp;
+ srcCM = src;
+ dstCM = dst;
+ }
+
+ public void dispose() {
+ srcSurf.dispose();
+ dstSurf.dispose();
+ }
+
+ public void compose(Raster srcIn, Raster dstIn, WritableRaster dstOut) {
+
+ if(!srcCM.isCompatibleRaster(srcIn)) {
+ // awt.48=The srcIn raster is incompatible with src ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.48")); //$NON-NLS-1$
+ }
+
+ if(!dstCM.isCompatibleRaster(dstIn)) {
+ // awt.49=The dstIn raster is incompatible with dst ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.49")); //$NON-NLS-1$
+ }
+
+ if(dstIn != dstOut){
+ if(!dstCM.isCompatibleRaster(dstOut)) {
+ // awt.4A=The dstOut raster is incompatible with dst ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4A")); //$NON-NLS-1$
+ }
+ dstOut.setDataElements(0, 0, dstIn);
+ }
+ WritableRaster src;
+ if(srcIn instanceof WritableRaster){
+ src = (WritableRaster) srcIn;
+ }else{
+ src = srcIn.createCompatibleWritableRaster();
+ src.setDataElements(0, 0, srcIn);
+ }
+ srcSurf = new ImageSurface(srcCM, src);
+ dstSurf = new ImageSurface(dstCM, dstOut);
+
+ int w = Math.min(srcIn.getWidth(), dstOut.getWidth());
+ int h = Math.min(srcIn.getHeight(), dstOut.getHeight());
+
+ NativeImageBlitter.getInstance().blit(0, 0, srcSurf, 0, 0, dstSurf,
+ w, h, composite, null, null);
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/ImageSurface.java b/awt/org/apache/harmony/awt/gl/ImageSurface.java
new file mode 100644
index 0000000..6368dd8
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/ImageSurface.java
@@ -0,0 +1,323 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 10.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BandedSampleModel;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent Surface for different types of Images (BufferedImage,
+ * OffscreenImage and so on)
+ */
+public class ImageSurface extends Surface implements DataBufferListener {
+
+ boolean nativeDrawable = true;
+ int surfaceType;
+ int csType;
+ ColorModel cm;
+ WritableRaster raster;
+ Object data;
+
+ boolean needToRefresh = true;
+ boolean dataTaken = false;
+
+ private long cachedDataPtr; // Pointer for cached Image Data
+ private boolean alphaPre; // Cached Image Data alpha premultiplied
+
+ public ImageSurface(ColorModel cm, WritableRaster raster){
+ this(cm, raster, Surface.getType(cm, raster));
+ }
+
+ public ImageSurface(ColorModel cm, WritableRaster raster, int type){
+ if (!cm.isCompatibleRaster(raster)) {
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+ this.cm = cm;
+ this.raster = raster;
+ surfaceType = type;
+
+ data = AwtImageBackdoorAccessor.getInstance().
+ getData(raster.getDataBuffer());
+ ColorSpace cs = cm.getColorSpace();
+ transparency = cm.getTransparency();
+ width = raster.getWidth();
+ height = raster.getHeight();
+
+ // For the moment we can build natively only images which have
+ // sRGB, Linear_RGB, Linear_Gray Color Space and type different
+ // from BufferedImage.TYPE_CUSTOM
+ if(cs == LUTColorConverter.sRGB_CS){
+ csType = sRGB_CS;
+ }else if(cs == LUTColorConverter.LINEAR_RGB_CS){
+ csType = Linear_RGB_CS;
+ }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
+ csType = Linear_Gray_CS;
+ }else{
+ csType = Custom_CS;
+ nativeDrawable = false;
+ }
+
+ if(type == BufferedImage.TYPE_CUSTOM){
+ nativeDrawable = false;
+ }
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ return cm;
+ }
+
+ @Override
+ public WritableRaster getRaster() {
+ return raster;
+ }
+
+ @Override
+ public long getSurfaceDataPtr() {
+ if(surfaceDataPtr == 0L && nativeDrawable){
+ createSufaceStructure();
+ }
+ return surfaceDataPtr;
+ }
+
+ @Override
+ public Object getData(){
+ return data;
+ }
+
+ @Override
+ public boolean isNativeDrawable(){
+ return nativeDrawable;
+ }
+
+ @Override
+ public int getSurfaceType() {
+ return surfaceType;
+ }
+
+ /**
+ * Creates native Surface structure which used for native blitting
+ */
+ private void createSufaceStructure(){
+ int cmType = 0;
+ int numComponents = cm.getNumComponents();
+ boolean hasAlpha = cm.hasAlpha();
+ boolean isAlphaPre = cm.isAlphaPremultiplied();
+ int transparency = cm.getTransparency();
+ int bits[] = cm.getComponentSize();
+ int pixelStride = cm.getPixelSize();
+ int masks[] = null;
+ int colorMap[] = null;
+ int colorMapSize = 0;
+ int transpPixel = -1;
+ boolean isGrayPallete = false;
+ SampleModel sm = raster.getSampleModel();
+ int smType = 0;
+ int dataType = sm.getDataType();
+ int scanlineStride = 0;
+ int bankIndeces[] = null;
+ int bandOffsets[] = null;
+ int offset = raster.getDataBuffer().getOffset();
+
+ if(cm instanceof DirectColorModel){
+ cmType = DCM;
+ DirectColorModel dcm = (DirectColorModel) cm;
+ masks = dcm.getMasks();
+ smType = SPPSM;
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ scanlineStride = sppsm.getScanlineStride();
+
+ }else if(cm instanceof IndexColorModel){
+ cmType = ICM;
+ IndexColorModel icm = (IndexColorModel) cm;
+ colorMapSize = icm.getMapSize();
+ colorMap = new int[colorMapSize];
+ icm.getRGBs(colorMap);
+ transpPixel = icm.getTransparentPixel();
+ isGrayPallete = Surface.isGrayPallete(icm);
+
+ if(sm instanceof MultiPixelPackedSampleModel){
+ smType = MPPSM;
+ MultiPixelPackedSampleModel mppsm =
+ (MultiPixelPackedSampleModel) sm;
+ scanlineStride = mppsm.getScanlineStride();
+ }else if(sm instanceof ComponentSampleModel){
+ smType = CSM;
+ ComponentSampleModel csm =
+ (ComponentSampleModel) sm;
+ scanlineStride = csm.getScanlineStride();
+ }else{
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+
+ }else if(cm instanceof ComponentColorModel){
+ cmType = CCM;
+ if(sm instanceof ComponentSampleModel){
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ scanlineStride = csm.getScanlineStride();
+ bankIndeces = csm.getBankIndices();
+ bandOffsets = csm.getBandOffsets();
+ if(sm instanceof PixelInterleavedSampleModel){
+ smType = PISM;
+ }else if(sm instanceof BandedSampleModel){
+ smType = BSM;
+ }else{
+ smType = CSM;
+ }
+ }else{
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+
+ }else{
+ surfaceDataPtr = 0L;
+ return;
+ }
+ surfaceDataPtr = createSurfStruct(surfaceType, width, height, cmType, csType, smType, dataType,
+ numComponents, pixelStride, scanlineStride, bits, masks, colorMapSize,
+ colorMap, transpPixel, isGrayPallete, bankIndeces, bandOffsets,
+ offset, hasAlpha, isAlphaPre, transparency);
+ }
+
+ @Override
+ public void dispose() {
+ if(surfaceDataPtr != 0L){
+ dispose(surfaceDataPtr);
+ surfaceDataPtr = 0L;
+ }
+ }
+
+ public long getCachedData(boolean alphaPre){
+ if(nativeDrawable){
+ if(cachedDataPtr == 0L || needToRefresh || this.alphaPre != alphaPre){
+ cachedDataPtr = updateCache(getSurfaceDataPtr(), data, alphaPre);
+ this.alphaPre = alphaPre;
+ validate();
+ }
+ }
+ return cachedDataPtr;
+ }
+
+ private native long createSurfStruct(int surfaceType, int width, int height,
+ int cmType, int csType, int smType, int dataType,
+ int numComponents, int pixelStride, int scanlineStride,
+ int bits[], int masks[], int colorMapSize, int colorMap[],
+ int transpPixel, boolean isGrayPalette, int bankIndeces[],
+ int bandOffsets[], int offset, boolean hasAlpha, boolean isAlphaPre,
+ int transparency);
+
+ private native void dispose(long structPtr);
+
+ private native void setImageSize(long structPtr, int width, int height);
+
+ private native long updateCache(long structPtr, Object data, boolean alphaPre);
+
+ /**
+ * Supposes that new raster is compatible with an old one
+ * @param r
+ */
+ public void setRaster(WritableRaster r) {
+ raster = r;
+ data = AwtImageBackdoorAccessor.getInstance().getData(r.getDataBuffer());
+ if (surfaceDataPtr != 0) {
+ setImageSize(surfaceDataPtr, r.getWidth(), r.getHeight());
+ }
+ this.width = r.getWidth();
+ this.height = r.getHeight();
+ }
+
+ @Override
+ public long lock() {
+ // TODO
+ return 0;
+ }
+
+ @Override
+ public void unlock() {
+ //TODO
+ }
+
+ @Override
+ public Surface getImageSurface() {
+ return this;
+ }
+
+ public void dataChanged() {
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ public void dataTaken() {
+ dataTaken = true;
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ public void dataReleased(){
+ dataTaken = false;
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ @Override
+ public void invalidate(){
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ @Override
+ public void validate(){
+ if(!needToRefresh) {
+ return;
+ }
+ if(!dataTaken){
+ needToRefresh = false;
+ AwtImageBackdoorAccessor ba = AwtImageBackdoorAccessor.getInstance();
+ ba.validate(raster.getDataBuffer());
+ }
+
+ }
+
+ @Override
+ public boolean invalidated(){
+ return needToRefresh;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/MultiRectArea.java b/awt/org/apache/harmony/awt/gl/MultiRectArea.java
new file mode 100644
index 0000000..c4267f3
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/MultiRectArea.java
@@ -0,0 +1,836 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class MultiRectArea implements Shape {
+
+ /**
+ * If CHECK is true validation check active
+ */
+ private static final boolean CHECK = false;
+
+ boolean sorted = true;
+
+ /**
+ * Rectangle buffer
+ */
+ public int[] rect;
+
+ /**
+ * Bounding box
+ */
+ Rectangle bounds;
+
+ /**
+ * Result rectangle array
+ */
+ Rectangle[] rectangles;
+
+ /**
+ * LineCash provides creating MultiRectArea line by line. Used in JavaShapeRasterizer.
+ */
+ public static class LineCash extends MultiRectArea {
+
+ int lineY;
+ int bottomCount;
+ int[] bottom;
+
+ public LineCash(int size) {
+ super();
+ bottom = new int[size];
+ bottomCount = 0;
+ }
+
+ public void setLine(int y) {
+ lineY = y;
+ }
+
+ public void skipLine() {
+ lineY++;
+ bottomCount = 0;
+ }
+
+ public void addLine(int[] points, int pointCount) {
+ int bottomIndex = 0;
+ int pointIndex = 0;
+ int rectIndex = 0;
+ int pointX1 = 0;
+ int pointX2 = 0;
+ int bottomX1 = 0;
+ int bottomX2 = 0;
+ boolean appendRect = false;
+ boolean deleteRect = false;
+ int lastCount = bottomCount;
+
+ while (bottomIndex < lastCount || pointIndex < pointCount) {
+
+ appendRect = false;
+ deleteRect = false;
+
+ if (bottomIndex < lastCount) {
+ rectIndex = bottom[bottomIndex];
+ bottomX1 = rect[rectIndex];
+ bottomX2 = rect[rectIndex + 2];
+ } else {
+ appendRect = true;
+ }
+
+ if (pointIndex < pointCount) {
+ pointX1 = points[pointIndex];
+ pointX2 = points[pointIndex + 1];
+ } else {
+ deleteRect = true;
+ }
+
+ if (!deleteRect && !appendRect) {
+ if (pointX1 == bottomX1 && pointX2 == bottomX2) {
+ rect[rectIndex + 3] = rect[rectIndex + 3] + 1;
+ pointIndex += 2;
+ bottomIndex++;
+ continue;
+ }
+ deleteRect = pointX2 >= bottomX1;
+ appendRect = pointX1 <= bottomX2;
+ }
+
+ if (deleteRect) {
+ if (bottomIndex < bottomCount - 1) {
+ System.arraycopy(bottom, bottomIndex + 1, bottom, bottomIndex, bottomCount - bottomIndex - 1);
+ rectIndex -= 4;
+ }
+ bottomCount--;
+ lastCount--;
+ }
+
+ if (appendRect) {
+ int i = rect[0];
+ bottom[bottomCount++] = i;
+ rect = MultiRectAreaOp.checkBufSize(rect, 4);
+ rect[i++] = pointX1;
+ rect[i++] = lineY;
+ rect[i++] = pointX2;
+ rect[i++] = lineY;
+ pointIndex += 2;
+ }
+ }
+ lineY++;
+
+ invalidate();
+ }
+
+ }
+
+ /**
+ * RectCash provides simple creating MultiRectArea
+ */
+ public static class RectCash extends MultiRectArea {
+
+ int[] cash;
+
+ public RectCash() {
+ super();
+ cash = new int[MultiRectAreaOp.RECT_CAPACITY];
+ cash[0] = 1;
+ }
+
+ public void addRectCashed(int x1, int y1, int x2, int y2) {
+ addRect(x1, y1, x2, y2);
+ invalidate();
+/*
+ // Exclude from cash unnecessary rectangles
+ int i = 1;
+ while(i < cash[0]) {
+ if (rect[cash[i] + 3] >= y1 - 1) {
+ if (i > 1) {
+ System.arraycopy(cash, i, cash, 1, cash[0] - i);
+ }
+ break;
+ }
+ i++;
+ }
+ cash[0] -= i - 1;
+
+ // Find in cash rectangle to concatinate
+ i = 1;
+ while(i < cash[0]) {
+ int index = cash[i];
+ if (rect[index + 3] != y1 - 1) {
+ break;
+ }
+ if (rect[index] == x1 && rect[index + 2] == x2) {
+ rect[index + 3] += y2 - y1 + 1;
+
+ int pos = i + 1;
+ while(pos < cash[0]) {
+ if (rect[index + 3] <= rect[cash[i] + 3]) {
+ System.arraycopy(cash, i + 1, cash, i, pos - i);
+ break;
+ }
+ i++;
+ }
+ cash[pos - 1] = index;
+
+ invalidate();
+ return;
+ }
+ i++;
+ }
+
+ // Add rectangle to buffer
+ int index = rect[0];
+ rect = MultiRectAreaOp.checkBufSize(rect, 4);
+ rect[index + 0] = x1;
+ rect[index + 1] = y1;
+ rect[index + 2] = x2;
+ rect[index + 3] = y2;
+
+ // Add rectangle to cash
+ int length = cash[0];
+ cash = MultiRectAreaOp.checkBufSize(cash, 1);
+ while(i < length) {
+ if (y2 <= rect[cash[i] + 3]) {
+ System.arraycopy(cash, i, cash, i + 1, length - i);
+ break;
+ }
+ i++;
+ }
+ cash[i] = index;
+ invalidate();
+*/
+ }
+
+ public void addRectCashed(int[] rect, int rectOff, int rectLength) {
+ for(int i = rectOff; i < rectOff + rectLength;) {
+ addRect(rect[i++], rect[i++], rect[i++], rect[i++]);
+// addRectCashed(rect[i++], rect[i++], rect[i++], rect[i++]);
+ }
+ }
+
+ }
+
+ /**
+ * MultiRectArea path iterator
+ */
+ class Iterator implements PathIterator {
+
+ int type;
+ int index;
+ int pos;
+
+ int[] rect;
+ AffineTransform t;
+
+ Iterator(MultiRectArea mra, AffineTransform t) {
+ rect = new int[mra.rect[0] - 1];
+ System.arraycopy(mra.rect, 1, rect, 0, rect.length);
+ this.t = t;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return pos >= rect.length;
+ }
+
+ public void next() {
+ if (index == 4) {
+ pos += 4;
+ }
+ index = (index + 1) % 5;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iiterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = 0;
+
+ switch(index) {
+ case 0 :
+ type = SEG_MOVETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 1];
+ break;
+ case 1:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 1];
+ break;
+ case 2:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 3];
+ break;
+ case 3:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 3];
+ break;
+ case 4:
+ type = SEG_CLOSE;
+ break;
+ }
+
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iiterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = 0;
+
+ switch(index) {
+ case 0 :
+ type = SEG_MOVETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 1];
+ break;
+ case 1:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 1];
+ break;
+ case 2:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 3];
+ break;
+ case 3:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 3];
+ break;
+ case 4:
+ type = SEG_CLOSE;
+ break;
+ }
+
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Constructs a new empty MultiRectArea
+ */
+ public MultiRectArea() {
+ rect = MultiRectAreaOp.createBuf(0);
+ }
+
+ public MultiRectArea(boolean sorted) {
+ this();
+ this.sorted = sorted;
+ }
+
+ /**
+ * Constructs a new MultiRectArea as a copy of another one
+ */
+ public MultiRectArea(MultiRectArea mra) {
+ if (mra == null) {
+ rect = MultiRectAreaOp.createBuf(0);
+ } else {
+ rect = new int[mra.rect.length];
+ System.arraycopy(mra.rect, 0, rect, 0, mra.rect.length);
+ check(this, "MultiRectArea(MRA)"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Constructs a new MultiRectArea consists of single rectangle
+ */
+ public MultiRectArea(Rectangle r) {
+ rect = MultiRectAreaOp.createBuf(0);
+ if (r != null && !r.isEmpty()) {
+ rect[0] = 5;
+ rect[1] = r.x;
+ rect[2] = r.y;
+ rect[3] = r.x + r.width - 1;
+ rect[4] = r.y + r.height - 1;
+ }
+ check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructs a new MultiRectArea consists of single rectangle
+ */
+ public MultiRectArea(int x0, int y0, int x1, int y1) {
+ rect = MultiRectAreaOp.createBuf(0);
+ if (x1 >= x0 && y1 >= y0) {
+ rect[0] = 5;
+ rect[1] = x0;
+ rect[2] = y0;
+ rect[3] = x1;
+ rect[4] = y1;
+ }
+ check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructs a new MultiRectArea and append rectangle from buffer
+ */
+ public MultiRectArea(Rectangle[] buf) {
+ this();
+ for (Rectangle element : buf) {
+ add(element);
+ }
+ }
+
+ /**
+ * Constructs a new MultiRectArea and append rectangle from array
+ */
+ public MultiRectArea(ArrayList<Rectangle> buf) {
+ this();
+ for(int i = 0; i < buf.size(); i++) {
+ add(buf.get(i));
+ }
+ }
+
+ /**
+ * Sort rectangle buffer
+ */
+ void resort() {
+ int[] buf = new int[4];
+ for(int i = 1; i < rect[0]; i += 4) {
+ int k = i;
+ int x1 = rect[k];
+ int y1 = rect[k + 1];
+ for(int j = i + 4; j < rect[0]; j += 4) {
+ int x2 = rect[j];
+ int y2 = rect[j + 1];
+ if (y1 > y2 || (y1 == y2 && x1 > x2)) {
+ x1 = x2;
+ y1 = y2;
+ k = j;
+ }
+ }
+ if (k != i) {
+ System.arraycopy(rect, i, buf, 0, 4);
+ System.arraycopy(rect, k, rect, i, 4);
+ System.arraycopy(buf, 0, rect, k, 4);
+ }
+ }
+ invalidate();
+ }
+
+ /**
+ * Tests equals with another object
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof MultiRectArea) {
+ MultiRectArea mra = (MultiRectArea) obj;
+ for(int i = 0; i < rect[0]; i++) {
+ if (rect[i] != mra.rect[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks validation of MultiRectArea object
+ */
+ static MultiRectArea check(MultiRectArea mra, String msg) {
+ if (CHECK && mra != null) {
+ if (MultiRectArea.checkValidation(mra.getRectangles(), mra.sorted) != -1) {
+ // awt.4C=Invalid MultiRectArea in method {0}
+ new RuntimeException(Messages.getString("awt.4C", msg)); //$NON-NLS-1$
+ }
+ }
+ return mra;
+ }
+
+ /**
+ * Checks validation of MultiRectArea object
+ */
+ public static int checkValidation(Rectangle[] r, boolean sorted) {
+
+ // Check width and height
+ for(int i = 0; i < r.length; i++) {
+ if (r[i].width <= 0 || r[i].height <= 0) {
+ return i;
+ }
+ }
+
+ // Check order
+ if (sorted) {
+ for(int i = 1; i < r.length; i++) {
+ if (r[i - 1].y > r[i].y) {
+ return i;
+ }
+ if (r[i - 1].y == r[i].y) {
+ if (r[i - 1].x > r[i].x) {
+ return i;
+ }
+ }
+ }
+ }
+
+ // Check override
+ for(int i = 0; i < r.length; i++) {
+ for(int j = i + 1; j < r.length; j++) {
+ if (r[i].intersects(r[j])) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Assigns rectangle from another buffer
+ */
+ protected void setRect(int[] buf, boolean copy) {
+ if (copy) {
+ rect = new int[buf.length];
+ System.arraycopy(buf, 0, rect, 0, buf.length);
+ } else {
+ rect = buf;
+ }
+ invalidate();
+ }
+
+ /**
+ * Union with another MultiRectArea object
+ */
+ public void add(MultiRectArea mra) {
+ setRect(union(this, mra).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Intersect with another MultiRectArea object
+ */
+ public void intersect(MultiRectArea mra) {
+ setRect(intersect(this, mra).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Subtract another MultiRectArea object
+ */
+ public void substract(MultiRectArea mra) {
+ setRect(subtract(this, mra).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Union with Rectangle object
+ */
+ public void add(Rectangle rect) {
+ setRect(union(this, new MultiRectArea(rect)).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Intersect with Rectangle object
+ */
+ public void intersect(Rectangle rect) {
+ setRect(intersect(this, new MultiRectArea(rect)).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Subtract rectangle object
+ */
+ public void substract(Rectangle rect) {
+ setRect(subtract(this, new MultiRectArea(rect)).rect, false);
+ }
+
+ /**
+ * Union two MutliRectareArea objects
+ */
+ public static MultiRectArea intersect(MultiRectArea src1, MultiRectArea src2) {
+ MultiRectArea res = check(MultiRectAreaOp.Intersection.getResult(src1, src2), "intersect(MRA,MRA)"); //$NON-NLS-1$
+ return res;
+ }
+
+ /**
+ * Intersect two MultiRectArea objects
+ */
+ public static MultiRectArea union(MultiRectArea src1, MultiRectArea src2) {
+ MultiRectArea res = check(new MultiRectAreaOp.Union().getResult(src1, src2), "union(MRA,MRA)"); //$NON-NLS-1$
+ return res;
+ }
+
+ /**
+ * Subtract two MultiRectArea objects
+ */
+ public static MultiRectArea subtract(MultiRectArea src1, MultiRectArea src2) {
+ MultiRectArea res = check(MultiRectAreaOp.Subtraction.getResult(src1, src2), "subtract(MRA,MRA)"); //$NON-NLS-1$
+ return res;
+ }
+
+ /**
+ * Print MultiRectArea object to output stream
+ */
+ public static void print(MultiRectArea mra, String msg) {
+ if (mra == null) {
+ System.out.println(msg + "=null"); //$NON-NLS-1$
+ } else {
+ Rectangle[] rects = mra.getRectangles();
+ System.out.println(msg + "(" + rects.length + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ for (Rectangle element : rects) {
+ System.out.println(
+ element.x + "," + //$NON-NLS-1$
+ element.y + "," + //$NON-NLS-1$
+ (element.x + element.width - 1) + "," + //$NON-NLS-1$
+ (element.y + element.height - 1));
+ }
+ }
+ }
+
+ /**
+ * Translate MultiRectArea object by (x, y)
+ */
+ public void translate(int x, int y) {
+ for(int i = 1; i < rect[0];) {
+ rect[i++] += x;
+ rect[i++] += y;
+ rect[i++] += x;
+ rect[i++] += y;
+ }
+
+ if (bounds != null && !bounds.isEmpty()) {
+ bounds.translate(x, y);
+ }
+
+ if (rectangles != null) {
+ for (Rectangle element : rectangles) {
+ element.translate(x, y);
+ }
+ }
+ }
+
+ /**
+ * Add rectangle to the buffer without any checking
+ */
+ public void addRect(int x1, int y1, int x2, int y2) {
+ int i = rect[0];
+ rect = MultiRectAreaOp.checkBufSize(rect, 4);
+ rect[i++] = x1;
+ rect[i++] = y1;
+ rect[i++] = x2;
+ rect[i++] = y2;
+ }
+
+ /**
+ * Tests is MultiRectArea empty
+ */
+ public boolean isEmpty() {
+ return rect[0] == 1;
+ }
+
+ void invalidate() {
+ bounds = null;
+ rectangles = null;
+ }
+
+ /**
+ * Returns bounds of MultiRectArea object
+ */
+ public Rectangle getBounds() {
+ if (bounds != null) {
+ return bounds;
+ }
+
+ if (isEmpty()) {
+ return bounds = new Rectangle();
+ }
+
+ int x1 = rect[1];
+ int y1 = rect[2];
+ int x2 = rect[3];
+ int y2 = rect[4];
+
+ for(int i = 5; i < rect[0]; i += 4) {
+ int rx1 = rect[i + 0];
+ int ry1 = rect[i + 1];
+ int rx2 = rect[i + 2];
+ int ry2 = rect[i + 3];
+ if (rx1 < x1) {
+ x1 = rx1;
+ }
+ if (rx2 > x2) {
+ x2 = rx2;
+ }
+ if (ry1 < y1) {
+ y1 = ry1;
+ }
+ if (ry2 > y2) {
+ y2 = ry2;
+ }
+ }
+
+ return bounds = new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ }
+
+ /**
+ * Recturn rectangle count in the buffer
+ */
+ public int getRectCount() {
+ return (rect[0] - 1) / 4;
+ }
+
+ /**
+ * Returns Rectangle array
+ */
+ public Rectangle[] getRectangles() {
+ if (rectangles != null) {
+ return rectangles;
+ }
+
+ rectangles = new Rectangle[(rect[0] - 1) / 4];
+ int j = 0;
+ for(int i = 1; i < rect[0]; i += 4) {
+ rectangles[j++] = new Rectangle(
+ rect[i],
+ rect[i + 1],
+ rect[i + 2] - rect[i] + 1,
+ rect[i + 3] - rect[i + 1] + 1);
+ }
+ return rectangles;
+ }
+
+ /**
+ * Returns Bounds2D
+ */
+ public Rectangle2D getBounds2D() {
+ return getBounds();
+ }
+
+ /**
+ * Tests does point lie inside MultiRectArea object
+ */
+ public boolean contains(double x, double y) {
+ for(int i = 1; i < rect[0]; i+= 4) {
+ if (rect[i] <= x && x <= rect[i + 2] && rect[i + 1] <= y && y <= rect[i + 3]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests does Point2D lie inside MultiRectArea object
+ */
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ /**
+ * Tests does rectangle lie inside MultiRectArea object
+ */
+ public boolean contains(double x, double y, double w, double h) {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Tests does Rectangle2D lie inside MultiRectArea object
+ */
+ public boolean contains(Rectangle2D r) {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Tests does rectangle intersect MultiRectArea object
+ */
+ public boolean intersects(double x, double y, double w, double h) {
+ Rectangle r = new Rectangle();
+ r.setRect(x, y, w, h);
+ return intersects(r);
+ }
+
+ /**
+ * Tests does Rectangle2D intersect MultiRectArea object
+ */
+ public boolean intersects(Rectangle2D r) {
+ if (r == null || r.isEmpty()) {
+ return false;
+ }
+ for(int i = 1; i < rect[0]; i+= 4) {
+ if (r.intersects(rect[i], rect[i+1], rect[i + 2]-rect[i]+1, rect[i + 3]-rect[i + 1]+1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns path iterator
+ */
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new Iterator(this, t);
+ }
+
+ /**
+ * Returns path iterator
+ */
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ /**
+ * Returns MultiRectArea object converted to string
+ */
+ @Override
+ public String toString() {
+ int cnt = getRectCount();
+ StringBuffer sb = new StringBuffer((cnt << 5) + 128);
+ sb.append(getClass().getName()).append(" ["); //$NON-NLS-1$
+ for(int i = 1; i < rect[0]; i += 4) {
+ sb.append(i > 1 ? ", [" : "[").append(rect[i]).append(", ").append(rect[i + 1]). //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ append(", ").append(rect[i + 2] - rect[i] + 1).append(", "). //$NON-NLS-1$ //$NON-NLS-2$
+ append(rect[i + 3] - rect[i + 1] + 1).append("]"); //$NON-NLS-1$
+ }
+ return sb.append("]").toString(); //$NON-NLS-1$
+ }
+
+}
+
diff --git a/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java b/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
new file mode 100644
index 0000000..c75e203
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
@@ -0,0 +1,837 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Rectangle;
+
+public class MultiRectAreaOp {
+
+ /**
+ * Rectangle buffer capacity
+ */
+ public static final int RECT_CAPACITY = 16;
+
+ /**
+ * If number of rectangle in MultiRectArea object less than MAX_SIMPLE simple algorithm applies
+ */
+ private static final int MAX_SIMPLE = 8;
+
+ /**
+ * Create buffer
+ */
+ public static int[] createBuf(int capacity) {
+ if (capacity == 0) {
+ capacity = RECT_CAPACITY;
+ }
+ int[] buf = new int[capacity];
+ buf[0] = 1;
+ return buf;
+ }
+
+ /**
+ * Checks buffer size and reallocate if necessary
+ */
+ public static int[] checkBufSize(int[] buf, int capacity) {
+ if (buf[0] + capacity >= buf.length) {
+ int length = buf[0] + (capacity > RECT_CAPACITY ? capacity : RECT_CAPACITY);
+ int[] tmp = new int[length];
+ System.arraycopy(buf, 0, tmp, 0, buf[0]);
+ buf = tmp;
+ }
+ buf[0] += capacity;
+ return buf;
+ }
+
+ /**
+ * Region class provides basic functionlity for MultiRectArea objects to make logical operations
+ */
+ static class Region {
+
+ int[] region;
+ int[] active;
+ int[] bottom;
+ int index;
+
+ public Region(int[] region) {
+ this.region = region;
+ active = new int[RECT_CAPACITY];
+ bottom = new int[RECT_CAPACITY];
+ active[0] = 1;
+ bottom[0] = 1;
+ index = 1;
+ }
+
+ void addActive(int index) {
+ int length = active[0];
+ active = checkBufSize(active, 4);
+ int i = 1;
+
+ while(i < length) {
+ if (region[index] < active[i]) {
+ // Insert
+ System.arraycopy(active, i, active, i + 4, length - i);
+ length = i;
+ break;
+ }
+ i += 4;
+ }
+ System.arraycopy(region, index, active, length, 4);
+
+ }
+
+ void findActive(int top, int bottom) {
+ while(index < region[0]) {
+ if (region[index + 1] > bottom) { // y1 > bottom
+ return;
+ }
+ if (region[index + 3] >= top) { // y2 >= top
+ addActive(index);
+ }
+ index += 4;
+ }
+ }
+
+ void deleteActive(int bottom) {
+ int length = active[0];
+ for(int i = 1; i < length;) {
+ if (active[i + 3] == bottom) {
+ length -= 4;
+ if (i < length) {
+ System.arraycopy(active, i + 4, active, i, length - i);
+ }
+ } else {
+ i += 4;
+ }
+ }
+ active[0] = length;
+ }
+
+ void deleteActive() {
+ int length = active[0];
+ for(int i = length - 4; i > 0; i -= 4) {
+ if (active[i + 1] > active[i + 3]) {
+ length -= 4;
+ if (i < length) {
+ System.arraycopy(active, i + 4, active, i, length - i);
+ }
+ }
+ }
+ active[0] = length;
+ }
+
+ void createLevel(int[] level) {
+ int levelCount = 1;
+ int topIndex = 1;
+ int i = 1;
+ while(i < region[0]) {
+
+ int top = region[i + 1];
+ int bottom = region[i + 3] + 1;
+ int j = topIndex;
+
+ addTop: {
+ while(j < levelCount) {
+ if (level[j] == top) {
+ break addTop;
+ }
+ if (level[j] > top) {
+ System.arraycopy(level, j, level, j + 1, levelCount - j);
+ break;
+ }
+ j++;
+ }
+
+ level[j] = top;
+ levelCount++;
+ topIndex = j;
+ }
+
+ addBottom: {
+ while(j < levelCount) {
+ if (level[j] == bottom) {
+ break addBottom;
+ }
+ if (level[j] > bottom) {
+ System.arraycopy(level, j, level, j + 1, levelCount - j);
+ break;
+ }
+ j++;
+ };
+
+ level[j] = bottom;
+ levelCount++;
+ }
+
+ i += 4;
+ }
+ level[0] = levelCount;
+ }
+
+ static void sortOrdered(int[] src1, int[] src2, int[] dst) {
+ int length1 = src1[0];
+ int length2 = src2[0];
+ int count = 1;
+ int i1 = 1;
+ int i2 = 1;
+ int v1 = src1[1];
+ int v2 = src2[1];
+ while(true) {
+
+ LEFT: {
+ while(i1 < length1) {
+ v1 = src1[i1];
+ if (v1 >= v2) {
+ break LEFT;
+ }
+ dst[count++] = v1;
+ i1++;
+ }
+ while(i2 < length2) {
+ dst[count++] = src2[i2++];
+ }
+ dst[0] = count;
+ return;
+ }
+
+ RIGHT: {
+ while(i2 < length2) {
+ v2 = src2[i2];
+ if (v2 >= v1) {
+ break RIGHT;
+ }
+ dst[count++] = v2;
+ i2++;
+ }
+ while(i1 < length1) {
+ dst[count++] = src1[i1++];
+ }
+ dst[0] = count;
+ return;
+ }
+
+ if (v1 == v2) {
+ dst[count++] = v1;
+ i1++;
+ i2++;
+ if (i1 < length1) {
+ v1 = src1[i1];
+ }
+ if (i2 < length2 - 1) {
+ v2 = src2[i2];
+ }
+ }
+ }
+ // UNREACHABLE
+ }
+
+ }
+
+ /**
+ * Intersection class provides intersection of two MultiRectAre aobjects
+ */
+ static class Intersection {
+
+ static void intersectRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) {
+
+ Region d1 = new Region(reg1);
+ Region d2 = new Region(reg2);
+
+ int[] level = new int[height1 + height2];
+ int[] level1 = new int[height1];
+ int[] level2 = new int[height2];
+ d1.createLevel(level1);
+ d2.createLevel(level2);
+ Region.sortOrdered(level1, level2, level);
+
+ int top;
+ int bottom = level[1] - 1;
+ for(int i = 2; i < level[0]; i++) {
+
+ top = bottom + 1;
+ bottom = level[i] - 1;
+
+ d1.findActive(top, bottom);
+ d2.findActive(top, bottom);
+
+ int i1 = 1;
+ int i2 = 1;
+
+ while(i1 < d1.active[0] && i2 < d2.active[0]) {
+
+ int x11 = d1.active[i1];
+ int x12 = d1.active[i1 + 2];
+ int x21 = d2.active[i2];
+ int x22 = d2.active[i2 + 2];
+
+ if (x11 <= x21) {
+ if (x12 >= x21) {
+ if (x12 <= x22) {
+ dst.addRectCashed(x21, top, x12, bottom);
+ i1 += 4;
+ } else {
+ dst.addRectCashed(x21, top, x22, bottom);
+ i2 += 4;
+ }
+ } else {
+ i1 += 4;
+ }
+ } else {
+ if (x22 >= x11) {
+ if (x22 <= x12) {
+ dst.addRectCashed(x11, top, x22, bottom);
+ i2 += 4;
+ } else {
+ dst.addRectCashed(x11, top, x12, bottom);
+ i1 += 4;
+ }
+ } else {
+ i2 += 4;
+ }
+ }
+ }
+
+ d1.deleteActive(bottom);
+ d2.deleteActive(bottom);
+ }
+ }
+
+ static int[] simpleIntersect(MultiRectArea src1, MultiRectArea src2) {
+ int[] rect1 = src1.rect;
+ int[] rect2 = src2.rect;
+ int[] rect = createBuf(0);
+
+ int k = 1;
+ for(int i = 1; i < rect1[0];) {
+
+ int x11 = rect1[i++];
+ int y11 = rect1[i++];
+ int x12 = rect1[i++];
+ int y12 = rect1[i++];
+
+ for(int j = 1; j < rect2[0];) {
+
+ int x21 = rect2[j++];
+ int y21 = rect2[j++];
+ int x22 = rect2[j++];
+ int y22 = rect2[j++];
+
+ if (x11 <= x22 && x12 >= x21 &&
+ y11 <= y22 && y12 >= y21)
+ {
+ rect = checkBufSize(rect, 4);
+ rect[k++] = x11 > x21 ? x11 : x21;
+ rect[k++] = y11 > y21 ? y11 : y21;
+ rect[k++] = x12 > x22 ? x22 : x12;
+ rect[k++] = y12 > y22 ? y22 : y12;
+ }
+ }
+ }
+
+ rect[0] = k;
+ return rect;
+ }
+
+ public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+ if (src1 == null || src2 == null || src1.isEmpty() || src2.isEmpty()) {
+ return new MultiRectArea();
+ }
+
+ MultiRectArea.RectCash dst = new MultiRectArea.RectCash();
+
+ if (!src1.sorted || !src2.sorted ||
+ src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE)
+ {
+ dst.setRect(simpleIntersect(src1, src2), false);
+ } else {
+ Rectangle bounds1 = src1.getBounds();
+ Rectangle bounds2 = src2.getBounds();
+ Rectangle bounds3 = bounds1.intersection(bounds2);
+ if (bounds3.width > 0 && bounds3.height > 0) {
+ intersectRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2);
+ }
+ }
+
+ return dst;
+ }
+
+ }
+
+ /**
+ * Union class provides union of two MultiRectAre aobjects
+ */
+ static class Union {
+
+ int rx1, rx2;
+ int top, bottom;
+ MultiRectArea.RectCash dst;
+
+ boolean next(Region d, int index) {
+ int x1 = d.active[index];
+ int x2 = d.active[index + 2];
+ boolean res = false;
+
+ if (x2 < rx1 - 1) {
+ res = true;
+ dst.addRectCashed(x1, top, x2, bottom);
+ } else
+ if (x1 > rx2 + 1) {
+ res = false;
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ rx1 = x1;
+ rx2 = x2;
+ } else {
+ res = x2 <= rx2;
+ rx1 = Math.min(x1, rx1);
+ rx2 = Math.max(x2, rx2);
+ }
+
+ // Top
+ if (d.active[index + 1] < top) {
+ dst.addRectCashed(x1, d.active[index + 1], x2, top - 1);
+ }
+ // Bottom
+ if (d.active[index + 3] > bottom) {
+ d.active[index + 1] = bottom + 1;
+ }
+ return res;
+ }
+
+ void check(Region d, int index, boolean t) {
+ int x1 = d.active[index];
+ int x2 = d.active[index + 2];
+ // Top
+ if (d.active[index + 1] < top) {
+ dst.addRectCashed(x1, d.active[index + 1], x2, top - 1);
+ }
+ if (t) {
+ dst.addRectCashed(x1, top, x2, bottom);
+ }
+ // Bottom
+ if (d.active[index + 3] > bottom) {
+ d.active[index + 1] = bottom + 1;
+ }
+ }
+
+ void unionRegions(int[] reg1, int[] reg2, int height1, int height2) {
+ Region d1 = new Region(reg1);
+ Region d2 = new Region(reg2);
+
+ int[] level = new int[height1 + height2];
+ int[] level1 = new int[height1];
+ int[] level2 = new int[height2];
+ d1.createLevel(level1);
+ d2.createLevel(level2);
+ Region.sortOrdered(level1, level2, level);
+
+ bottom = level[1] - 1;
+ for(int i = 2; i < level[0]; i++) {
+
+ top = bottom + 1;
+ bottom = level[i] - 1;
+
+ d1.findActive(top, bottom);
+ d2.findActive(top, bottom);
+
+ int i1 = 1;
+ int i2 = 1;
+ boolean res1, res2;
+
+ if (d1.active[0] > 1) {
+ check(d1, 1, false);
+ rx1 = d1.active[1];
+ rx2 = d1.active[3];
+ i1 += 4;
+ res1 = false;
+ res2 = true;
+ } else
+ if (d2.active[0] > 1) {
+ check(d2, 1, false);
+ rx1 = d2.active[1];
+ rx2 = d2.active[3];
+ i2 += 4;
+ res1 = true;
+ res2 = false;
+ } else {
+ continue;
+ }
+
+ outer:
+ while(true) {
+
+ while (res1) {
+ if (i1 >= d1.active[0]) {
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ while(i2 < d2.active[0]) {
+ check(d2, i2, true);
+ i2 += 4;
+ }
+ break outer;
+ }
+ res1 = next(d1, i1);
+ i1 += 4;
+ }
+
+ while (res2) {
+ if (i2 >= d2.active[0]) {
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ while(i1 < d1.active[0]) {
+ check(d1, i1, true);
+ i1 += 4;
+ }
+ break outer;
+ }
+ res2 = next(d2, i2);
+ i2 += 4;
+ }
+
+ res1 = true;
+ res2 = true;
+ } // while
+
+ d1.deleteActive(bottom);
+ d2.deleteActive(bottom);
+
+ }
+ }
+
+ static void simpleUnion(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) {
+ if (src1.getRectCount() < src2.getRectCount()) {
+ simpleUnion(src2, src1, dst);
+ } else {
+ Subtraction.simpleSubtract(src1, src2, dst);
+ int pos = dst.rect[0];
+ int size = src2.rect[0] - 1;
+ dst.rect = checkBufSize(dst.rect, size);
+ System.arraycopy(src2.rect,1, dst.rect, pos, size);
+ dst.resort();
+ }
+ }
+
+ MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+ if (src1 == null || src1.isEmpty()) {
+ return new MultiRectArea(src2);
+ }
+
+ if (src2 == null || src2.isEmpty()) {
+ return new MultiRectArea(src1);
+ }
+
+ dst = new MultiRectArea.RectCash();
+
+ if (!src1.sorted || !src2.sorted ||
+ src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE)
+ {
+ simpleUnion(src1, src2, dst);
+ } else {
+ Rectangle bounds1 = src1.getBounds();
+ Rectangle bounds2 = src2.getBounds();
+ Rectangle bounds3 = bounds1.intersection(bounds2);
+
+ if (bounds3.width < 0 || bounds3.height < 0) {
+ if (bounds1.y + bounds1.height < bounds2.y) {
+ dst.setRect(addVerRegion(src1.rect, src2.rect), false);
+ } else
+ if (bounds2.y + bounds2.height < bounds1.y) {
+ dst.setRect(addVerRegion(src2.rect, src1.rect), false);
+ } else
+ if (bounds1.x < bounds2.x) {
+ dst.setRect(addHorRegion(src1.rect, src2.rect), false);
+ } else {
+ dst.setRect(addHorRegion(src2.rect, src1.rect), false);
+ }
+ } else {
+ unionRegions(src1.rect, src2.rect, bounds1.height + 2, bounds2.height + 2);
+ }
+ }
+
+ return dst;
+ }
+
+ int[] addVerRegion(int[] top, int[] bottom) {
+ int length = top[0] + bottom[0] - 1;
+ int[] dst = new int[length];
+ dst[0] = length;
+ System.arraycopy(top, 1, dst, 1, top[0] - 1);
+ System.arraycopy(bottom, 1, dst, top[0], bottom[0] - 1);
+ return dst;
+ }
+
+ int[] addHorRegion(int[] left, int[] right) {
+ int count1 = left[0];
+ int count2 = right[0];
+ int[] dst = new int[count1 + count2 + 1];
+ int count = 1;
+ int index1 = 1;
+ int index2 = 1;
+
+ int top1 = left[2];
+ int top2 = right[2];
+ int pos1, pos2;
+
+ while(true) {
+
+ if (index1 >= count1) {
+ System.arraycopy(right, index2, dst, count, count2 - index2);
+ count += count2 - index2;
+ break;
+ }
+ if (index2 >= count2) {
+ System.arraycopy(left, index1, dst, count, count1 - index1);
+ count += count1 - index1;
+ break;
+ }
+
+ if (top1 < top2) {
+ pos1 = index1;
+ do {
+ index1 += 4;
+ } while (index1 < count1 && (top1 = left[index1 + 1]) < top2);
+ System.arraycopy(left, pos1, dst, count, index1 - pos1);
+ count += index1 - pos1;
+ continue;
+ }
+
+ if (top1 > top2) {
+ pos2 = index2;
+ do {
+ index2 += 4;
+ } while (index2 < count2 && (top2 = right[index2 + 1]) < top1);
+ System.arraycopy(right, pos2, dst, count, index2 - pos2);
+ count += index2 - pos2;
+ continue;
+ }
+
+ int top = top1;
+ pos1 = index1;
+ pos2 = index2;
+ do {
+ index1 += 4;
+ } while(index1 < count1 && (top1 = left[index1 + 1]) == top);
+ do {
+ index2 += 4;
+ } while(index2 < count2 && (top2 = right[index2 + 1]) == top);
+
+ System.arraycopy(left, pos1, dst, count, index1 - pos1);
+ count += index1 - pos1;
+ System.arraycopy(right, pos2, dst, count, index2 - pos2);
+ count += index2 - pos2;
+ }
+
+ dst[0] = count;
+ return dst;
+ }
+
+ }
+
+ /**
+ * Subtraction class provides subtraction of two MultiRectAre aobjects
+ */
+ static class Subtraction {
+
+ static void subtractRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) {
+ Region d1 = new Region(reg1);
+ Region d2 = new Region(reg2);
+
+ int[] level = new int[height1 + height2];
+ int[] level1 = new int[height1];
+ int[] level2 = new int[height2];
+ d1.createLevel(level1);
+ d2.createLevel(level2);
+ Region.sortOrdered(level1, level2, level);
+
+ int top;
+ int bottom = level[1] - 1;
+ for(int i = 2; i < level[0]; i++) {
+
+ top = bottom + 1;
+ bottom = level[i] - 1;
+
+ d1.findActive(top, bottom);
+ if (d1.active[0] == 1) {
+ d2.deleteActive(bottom);
+ continue;
+ }
+
+ d2.findActive(top, bottom);
+
+ int i1 = 1;
+ int i2 = 1;
+
+ int rx1 = 0;
+ int rx2 = 0;
+
+ boolean next = true;
+
+ while(true) {
+
+ if (next) {
+ next = false;
+ if (i1 >= d1.active[0]) {
+ break;
+ }
+ // Bottom
+ d1.active[i1 + 1] = bottom + 1;
+ rx1 = d1.active[i1];
+ rx2 = d1.active[i1 + 2];
+ i1 += 4;
+ }
+
+ if (i2 >= d2.active[0]) {
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ for(int j = i1; j < d1.active[0]; j += 4) {
+ dst.addRectCashed(d1.active[j], top, d1.active[j + 2], bottom);
+ d1.active[j + 1] = bottom + 1;
+ }
+ break;
+ }
+
+ int x1 = d2.active[i2];
+ int x2 = d2.active[i2 + 2];
+
+ if (rx1 < x1) {
+ if (rx2 >= x1) {
+ if (rx2 <= x2) {
+ // [-----------]
+ // [-------------]
+ dst.addRectCashed(rx1, top, x1 - 1, bottom);
+ next = true;
+ } else {
+ // [-----------------]
+ // [------]
+ dst.addRectCashed(rx1, top, x1 - 1, bottom);
+ rx1 = x2 + 1;
+ i2 += 4;
+ }
+ } else {
+ // [-----]
+ // [----]
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ next = true;
+ }
+ } else {
+ if (rx1 <= x2) {
+ if (rx2 <= x2) {
+ // [------]
+ // [-----------]
+ next = true;
+ } else {
+ // [------------]
+ // [---------]
+ rx1 = x2 + 1;
+ i2 += 4;
+ }
+ } else {
+ // [----]
+ // [-----]
+ i2 += 4;
+ }
+ }
+
+ }
+ d1.deleteActive();
+ d2.deleteActive(bottom);
+ }
+ }
+
+ static void subtractRect(int x11, int y11, int x12, int y12, int[] rect, int index, MultiRectArea dst) {
+
+ for(int i = index; i < rect[0]; i += 4) {
+ int x21 = rect[i + 0];
+ int y21 = rect[i + 1];
+ int x22 = rect[i + 2];
+ int y22 = rect[i + 3];
+
+ if (x11 <= x22 && x12 >= x21 && y11 <= y22 && y12 >= y21) {
+ int top, bottom;
+ if (y11 < y21) {
+ subtractRect(x11, y11, x12, y21 - 1, rect, i + 4, dst);
+ top = y21;
+ } else {
+ top = y11;
+ }
+ if (y12 > y22) {
+ subtractRect(x11, y22 + 1, x12, y12, rect, i + 4, dst);
+ bottom = y22;
+ } else {
+ bottom = y12;
+ }
+ if (x11 < x21) {
+ subtractRect(x11, top, x21 - 1, bottom, rect, i + 4, dst);
+ }
+ if (x12 > x22) {
+ subtractRect(x22 + 1, top, x12, bottom, rect, i + 4, dst);
+ }
+ return;
+ }
+ }
+ dst.addRect(x11, y11, x12, y12);
+ }
+
+ static void simpleSubtract(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) {
+ for(int i = 1; i < src1.rect[0]; i += 4) {
+ subtractRect(
+ src1.rect[i + 0],
+ src1.rect[i + 1],
+ src1.rect[i + 2],
+ src1.rect[i + 3],
+ src2.rect,
+ 1,
+ dst);
+ }
+ dst.resort();
+ }
+
+ public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+ if (src1 == null || src1.isEmpty()) {
+ return new MultiRectArea();
+ }
+
+ if (src2 == null || src2.isEmpty()) {
+ return new MultiRectArea(src1);
+ }
+
+ MultiRectArea.RectCash dst = new MultiRectArea.RectCash();
+
+ if (!src1.sorted || !src2.sorted ||
+ src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE)
+ {
+ simpleSubtract(src1, src2, dst);
+ } else {
+ Rectangle bounds1 = src1.getBounds();
+ Rectangle bounds2 = src2.getBounds();
+ Rectangle bounds3 = bounds1.intersection(bounds2);
+
+ if (bounds3.width > 0 && bounds3.height > 0) {
+ subtractRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2);
+ } else {
+ dst.setRect(src1.rect, true);
+ }
+ }
+
+ return dst;
+ }
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/Surface.java b/awt/org/apache/harmony/awt/gl/Surface.java
new file mode 100644
index 0000000..8b0ae38
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/Surface.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 10.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Image;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+
+
+/**
+ * This class is super class for others types of Surfaces.
+ * Surface is storing data and data format description, that are using
+ * in blitting operations
+ */
+public abstract class Surface implements Transparency{
+
+ // Color Space Types
+ public static final int sRGB_CS = 1;
+ public static final int Linear_RGB_CS = 2;
+ public static final int Linear_Gray_CS = 3;
+ public static final int Custom_CS = 0;
+
+ // Color Model Types
+ public static final int DCM = 1; // Direct Color Model
+ public static final int ICM = 2; // Index Color Model
+ public static final int CCM = 3; // Component Color Model
+
+ // Sample Model Types
+ public static final int SPPSM = 1; // Single Pixel Packed Sample Model
+ public static final int MPPSM = 2; // Multi Pixel Packed Sample Model
+ public static final int CSM = 3; // Component Sample Model
+ public static final int PISM = 4; // Pixel Interleaved Sample Model
+ public static final int BSM = 5; // Banded Sample Model
+
+ // Surface Types
+ private static final int ALPHA_MASK = 0xff000000;
+ private static final int RED_MASK = 0x00ff0000;
+ private static final int GREEN_MASK = 0x0000ff00;
+ private static final int BLUE_MASK = 0x000000ff;
+ private static final int RED_BGR_MASK = 0x000000ff;
+ private static final int GREEN_BGR_MASK = 0x0000ff00;
+ private static final int BLUE_BGR_MASK = 0x00ff0000;
+ private static final int RED_565_MASK = 0xf800;
+ private static final int GREEN_565_MASK = 0x07e0;
+ private static final int BLUE_565_MASK = 0x001f;
+ private static final int RED_555_MASK = 0x7c00;
+ private static final int GREEN_555_MASK = 0x03e0;
+ private static final int BLUE_555_MASK = 0x001f;
+
+ static{
+ //???AWT
+ /*
+ System.loadLibrary("gl"); //$NON-NLS-1$
+ initIDs();
+ */
+ }
+
+
+ protected long surfaceDataPtr; // Pointer for Native Surface data
+ protected int transparency = OPAQUE;
+ protected int width;
+ protected int height;
+
+ /**
+ * This list contains caches with the data of this surface that are valid at the moment.
+ * Surface should clear this list when its data is updated.
+ * Caches may check if they are still valid using isCacheValid method.
+ * When cache gets data from the surface, it should call addValidCache method of the surface.
+ */
+ private final ArrayList<Object> validCaches = new ArrayList<Object>();
+
+ public abstract ColorModel getColorModel();
+ public abstract WritableRaster getRaster();
+ public abstract int getSurfaceType(); // Syrface type. It is equal
+ // BufferedImge type
+ /**
+ * Lock Native Surface data
+ */
+ public abstract long lock();
+
+ /**
+ * Unlock Native Surface data
+ */
+ public abstract void unlock();
+
+ /**
+ * Dispose Native Surface data
+ */
+ public abstract void dispose();
+ public abstract Surface getImageSurface();
+
+ public long getSurfaceDataPtr(){
+ return surfaceDataPtr;
+ }
+
+ public final boolean isCaheValid(Object cache) {
+ return validCaches.contains(cache);
+ }
+
+ public final void addValidCache(Object cache) {
+ validCaches.add(cache);
+ }
+
+ protected final void clearValidCaches() {
+ validCaches.clear();
+ }
+
+ /**
+ * Returns could or coldn't the Surface be blit by Native blitter
+ * @return - true if the Surface could be blit by Native blitter,
+ * false in other case
+ */
+ public boolean isNativeDrawable(){
+ return true;
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+
+ public int getWidth(){
+ return width;
+ }
+
+ public int getHeight(){
+ return height;
+ }
+
+ /**
+ * If Surface has Raster, this method returns data array of Raster's DataBuffer
+ * @return - data array
+ */
+ public Object getData(){
+ return null;
+ }
+
+ public boolean invalidated(){
+ return true;
+ }
+
+ public void validate(){}
+
+ public void invalidate(){}
+
+ /**
+ * Computation type of BufferedImage or Surface
+ * @param cm - ColorModel
+ * @param raster - WritableRaste
+ * @return - type of BufferedImage
+ */
+ public static int getType(ColorModel cm, WritableRaster raster){
+ int transferType = cm.getTransferType();
+ boolean hasAlpha = cm.hasAlpha();
+ ColorSpace cs = cm.getColorSpace();
+ int csType = cs.getType();
+ SampleModel sm = raster.getSampleModel();
+
+ if(csType == ColorSpace.TYPE_RGB){
+ if(cm instanceof DirectColorModel){
+ DirectColorModel dcm = (DirectColorModel) cm;
+ switch (transferType) {
+ case DataBuffer.TYPE_INT:
+ if (dcm.getRedMask() == RED_MASK &&
+ dcm.getGreenMask() == GREEN_MASK &&
+ dcm.getBlueMask() == BLUE_MASK) {
+ if (!hasAlpha) {
+ return BufferedImage.TYPE_INT_RGB;
+ }
+ if (dcm.getAlphaMask() == ALPHA_MASK) {
+ if (dcm.isAlphaPremultiplied()) {
+ return BufferedImage.TYPE_INT_ARGB_PRE;
+ }
+ return BufferedImage.TYPE_INT_ARGB;
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ } else if (dcm.getRedMask() == RED_BGR_MASK &&
+ dcm.getGreenMask() == GREEN_BGR_MASK &&
+ dcm.getBlueMask() == BLUE_BGR_MASK) {
+ if (!hasAlpha) {
+ return BufferedImage.TYPE_INT_BGR;
+ }
+ } else {
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ case DataBuffer.TYPE_USHORT:
+ if (dcm.getRedMask() == RED_555_MASK &&
+ dcm.getGreenMask() == GREEN_555_MASK &&
+ dcm.getBlueMask() == BLUE_555_MASK && !hasAlpha) {
+ return BufferedImage.TYPE_USHORT_555_RGB;
+ } else if (dcm.getRedMask() == RED_565_MASK &&
+ dcm.getGreenMask() == GREEN_565_MASK &&
+ dcm.getBlueMask() == BLUE_565_MASK) {
+ return BufferedImage.TYPE_USHORT_565_RGB;
+ }
+ default:
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ }else if(cm instanceof IndexColorModel){
+ IndexColorModel icm = (IndexColorModel) cm;
+ int pixelBits = icm.getPixelSize();
+ if(transferType == DataBuffer.TYPE_BYTE){
+ if(sm instanceof MultiPixelPackedSampleModel && !hasAlpha &&
+ pixelBits < 5){
+ return BufferedImage.TYPE_BYTE_BINARY;
+ }else if(pixelBits == 8){
+ return BufferedImage.TYPE_BYTE_INDEXED;
+ }
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }else if(cm instanceof ComponentColorModel){
+ ComponentColorModel ccm = (ComponentColorModel) cm;
+ if(transferType == DataBuffer.TYPE_BYTE &&
+ sm instanceof ComponentSampleModel){
+ ComponentSampleModel csm =
+ (ComponentSampleModel) sm;
+ int[] offsets = csm.getBandOffsets();
+ int[] bits = ccm.getComponentSize();
+ boolean isCustom = false;
+ for (int i = 0; i < bits.length; i++) {
+ if (bits[i] != 8 ||
+ offsets[i] != offsets.length - 1 - i) {
+ isCustom = true;
+ break;
+ }
+ }
+ if (!isCustom) {
+ if (!ccm.hasAlpha()) {
+ return BufferedImage.TYPE_3BYTE_BGR;
+ } else if (ccm.isAlphaPremultiplied()) {
+ return BufferedImage.TYPE_4BYTE_ABGR_PRE;
+ } else {
+ return BufferedImage.TYPE_4BYTE_ABGR;
+ }
+ }
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
+ if(cm instanceof ComponentColorModel &&
+ cm.getNumComponents() == 1){
+ int bits[] = cm.getComponentSize();
+ if(transferType == DataBuffer.TYPE_BYTE &&
+ bits[0] == 8){
+ return BufferedImage.TYPE_BYTE_GRAY;
+ }else if(transferType == DataBuffer.TYPE_USHORT &&
+ bits[0] == 16){
+ return BufferedImage.TYPE_USHORT_GRAY;
+ }else{
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }
+
+ public static Surface getImageSurface(Image image){
+ return AwtImageBackdoorAccessor.getInstance().getImageSurface(image);
+ }
+
+ @Override
+ protected void finalize() throws Throwable{
+ dispose();
+ }
+
+ public static boolean isGrayPallete(IndexColorModel icm){
+ return AwtImageBackdoorAccessor.getInstance().isGrayPallete(icm);
+ }
+
+ /**
+ * Initialization of Native data
+ *
+ */
+ //???AWT: private static native void initIDs();
+}
diff --git a/awt/org/apache/harmony/awt/gl/TextRenderer.java b/awt/org/apache/harmony/awt/gl/TextRenderer.java
new file mode 100644
index 0000000..f57952d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/TextRenderer.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Graphics2D;
+import java.awt.font.GlyphVector;
+
+public abstract class TextRenderer {
+
+ /**
+ * Draws string on specified Graphics at desired position.
+ *
+ * @param g specified Graphics2D object
+ * @param str String object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ */
+ public abstract void drawString(Graphics2D g, String str, float x, float y);
+
+ /**
+ * Draws string on specified Graphics at desired position.
+ *
+ * @param g specified Graphics2D object
+ * @param str String object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ */
+ public void drawString(Graphics2D g, String str, int x, int y){
+ drawString(g, str, (float)x, (float)y);
+ }
+
+ /**
+ * Draws GlyphVector on specified Graphics at desired position.
+ *
+ * @param g specified Graphics2D object
+ * @param glyphVector GlyphVector object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ */
+ public abstract void drawGlyphVector(Graphics2D g, GlyphVector glyphVector, float x, float y);
+}
diff --git a/awt/org/apache/harmony/awt/gl/XORComposite.java b/awt/org/apache/harmony/awt/gl/XORComposite.java
new file mode 100644
index 0000000..e27e1d3
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/XORComposite.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 21.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+
+public class XORComposite implements Composite {
+
+ Color xorcolor;
+
+ public XORComposite(Color xorcolor){
+ this.xorcolor = xorcolor;
+ }
+
+ public CompositeContext createContext(ColorModel srcCM, ColorModel dstCM,
+ RenderingHints hints) {
+
+ return new ICompositeContext(this, srcCM, dstCM);
+ }
+
+ public Color getXORColor(){
+ return xorcolor;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorConverter.java b/awt/org/apache/harmony/awt/gl/color/ColorConverter.java
new file mode 100644
index 0000000..c98e114
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ColorConverter.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * This class combines ColorScaler, ICC_Transform and NativeImageFormat functionality
+ * in the workflows for different types of input/output pixel data.
+ */
+public class ColorConverter {
+ private ColorScaler scaler = new ColorScaler();
+
+ public void loadScalingData(ColorSpace cs) {
+ scaler.loadScalingData(cs);
+ }
+
+ /**
+ * Translates pixels, stored in source buffered image and writes the data
+ * to the destination image.
+ * @param t - ICC transform
+ * @param src - source image
+ * @param dst - destination image
+ */
+ public void translateColor(ICC_Transform t,
+ BufferedImage src, BufferedImage dst) {
+ NativeImageFormat srcIF = NativeImageFormat.createNativeImageFormat(src);
+ NativeImageFormat dstIF = NativeImageFormat.createNativeImageFormat(dst);
+
+ if (srcIF != null && dstIF != null) {
+ t.translateColors(srcIF, dstIF);
+ return;
+ }
+
+ srcIF = createImageFormat(src);
+ dstIF = createImageFormat(dst);
+
+ short srcChanData[] = (short[]) srcIF.getChannelData();
+ short dstChanData[] = (short[]) dstIF.getChannelData();
+
+ ColorModel srcCM = src.getColorModel();
+ int nColorChannels = srcCM.getNumColorComponents();
+ scaler.loadScalingData(srcCM.getColorSpace()); // input scaling data
+ ColorModel dstCM = dst.getColorModel();
+
+ // Prepare array for alpha channel
+ float alpha[] = null;
+ boolean saveAlpha = srcCM.hasAlpha() && dstCM.hasAlpha();
+ if (saveAlpha) {
+ alpha = new float[src.getWidth()*src.getHeight()];
+ }
+
+ WritableRaster wr = src.getRaster();
+ int srcDataPos = 0, alphaPos = 0;
+ float normalizedVal[];
+ for (int row=0, nRows = srcIF.getNumRows(); row<nRows; row++) {
+ for (int col=0, nCols = srcIF.getNumCols(); col<nCols; col++) {
+ normalizedVal = srcCM.getNormalizedComponents(
+ wr.getDataElements(col, row, null),
+ null, 0);
+ // Save alpha channel
+ if (saveAlpha) {
+ // We need nColorChannels'th element cause it's nChannels - 1
+ alpha[alphaPos++] = normalizedVal[nColorChannels];
+ }
+ scaler.scale(normalizedVal, srcChanData, srcDataPos);
+ srcDataPos += nColorChannels;
+ }
+ }
+
+ t.translateColors(srcIF, dstIF);
+
+ nColorChannels = dstCM.getNumColorComponents();
+ boolean fillAlpha = dstCM.hasAlpha();
+ scaler.loadScalingData(dstCM.getColorSpace()); // output scaling data
+ float dstPixel[] = new float[dstCM.getNumComponents()];
+ int dstDataPos = 0;
+ alphaPos = 0;
+ wr = dst.getRaster();
+
+ for (int row=0, nRows = dstIF.getNumRows(); row<nRows; row++) {
+ for (int col=0, nCols = dstIF.getNumCols(); col<nCols; col++) {
+ scaler.unscale(dstPixel, dstChanData, dstDataPos);
+ dstDataPos += nColorChannels;
+ if (fillAlpha) {
+ if (saveAlpha) {
+ dstPixel[nColorChannels] = alpha[alphaPos++];
+ } else {
+ dstPixel[nColorChannels] = 1f;
+ }
+ }
+ wr.setDataElements(col, row,
+ dstCM.getDataElements(dstPixel, 0 , null));
+ }
+ }
+ }
+
+ /**
+ * Translates pixels, stored in the float data buffer.
+ * Each pixel occupies separate array. Input pixels passed in the buffer
+ * are replaced by output pixels and then the buffer is returned
+ * @param t - ICC transform
+ * @param buffer - data buffer
+ * @param srcCS - source color space
+ * @param dstCS - destination color space
+ * @param nPixels - number of pixels
+ * @return translated pixels
+ */
+ public float[][] translateColor(ICC_Transform t,
+ float buffer[][],
+ ColorSpace srcCS,
+ ColorSpace dstCS,
+ int nPixels) {
+ // Scale source data
+ if (srcCS != null) { // if it is null use old scaling data
+ scaler.loadScalingData(srcCS);
+ }
+ int nSrcChannels = t.getNumInputChannels();
+ short srcShortData[] = new short[nPixels*nSrcChannels];
+ for (int i=0, srcDataPos = 0; i<nPixels; i++) {
+ scaler.scale(buffer[i], srcShortData, srcDataPos);
+ srcDataPos += nSrcChannels;
+ }
+
+ // Apply transform
+ short dstShortData[] = this.translateColor(t, srcShortData, null);
+
+ int nDstChannels = t.getNumOutputChannels();
+ int bufferSize = buffer[0].length;
+ if (bufferSize < nDstChannels + 1) { // Re-allocate buffer if needed
+ for (int i=0; i<nPixels; i++) {
+ // One extra element reserved for alpha
+ buffer[i] = new float[nDstChannels + 1];
+ }
+ }
+
+ // Unscale destination data
+ if (dstCS != null) { // if it is null use old scaling data
+ scaler.loadScalingData(dstCS);
+ }
+ for (int i=0, dstDataPos = 0; i<nPixels; i++) {
+ scaler.unscale(buffer[i], dstShortData, dstDataPos);
+ dstDataPos += nDstChannels;
+ }
+
+ return buffer;
+ }
+
+ /**
+ * Translates pixels stored in a raster.
+ * All data types are supported
+ * @param t - ICC transform
+ * @param src - source pixels
+ * @param dst - destination pixels
+ */
+ public void translateColor(ICC_Transform t, Raster src, WritableRaster dst) {
+ try{
+ NativeImageFormat srcFmt = NativeImageFormat.createNativeImageFormat(src);
+ NativeImageFormat dstFmt = NativeImageFormat.createNativeImageFormat(dst);
+
+ if (srcFmt != null && dstFmt != null) {
+ t.translateColors(srcFmt, dstFmt);
+ return;
+ }
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Go ahead and rescale the source image
+ scaler.loadScalingData(src, t.getSrc());
+ short srcData[] = scaler.scale(src);
+
+ short dstData[] = translateColor(t, srcData, null);
+
+ scaler.loadScalingData(dst, t.getDst());
+ scaler.unscale(dstData, dst);
+ }
+
+ /**
+ * Translates pixels stored in an array of shorts.
+ * Samples are stored one-by-one, i.e. array structure is like following: RGBRGBRGB...
+ * The number of pixels is (size of the array) / (number of components).
+ * @param t - ICC transform
+ * @param src - source pixels
+ * @param dst - destination pixels
+ * @return destination pixels, stored in the array, passed in dst
+ */
+ public short[] translateColor(ICC_Transform t, short src[], short dst[]) {
+ NativeImageFormat srcFmt = createImageFormat(t, src, 0, true);
+ NativeImageFormat dstFmt = createImageFormat(t, dst, srcFmt.getNumCols(), false);
+
+ t.translateColors(srcFmt, dstFmt);
+
+ return (short[]) dstFmt.getChannelData();
+ }
+
+
+ /**
+ * Creates NativeImageFormat from buffered image.
+ * @param bi - buffered image
+ * @return created NativeImageFormat
+ */
+ private NativeImageFormat createImageFormat(BufferedImage bi) {
+ int nRows = bi.getHeight();
+ int nCols = bi.getWidth();
+ int nComps = bi.getColorModel().getNumColorComponents();
+ short imgData[] = new short[nRows*nCols*nComps];
+ return new NativeImageFormat(
+ imgData, nComps, nRows, nCols);
+ }
+
+ /**
+ * Creates one-row NativeImageFormat, using either nCols if it is positive,
+ * or arr.length to determine the number of pixels
+ *
+ * @param t - transform
+ * @param arr - short array or null if nCols is positive
+ * @param nCols - number of pixels in the array or 0 if array is not null
+ * @param in - is it an input or output array
+ * @return one-row NativeImageFormat
+ */
+ private NativeImageFormat createImageFormat(
+ ICC_Transform t, short arr[], int nCols, boolean in
+ ) {
+ int nComponents = in ? t.getNumInputChannels() : t.getNumOutputChannels();
+
+ if (arr == null || arr.length < nCols*nComponents) {
+ arr = new short[nCols*nComponents];
+ }
+
+ if (nCols == 0)
+ nCols = arr.length / nComponents;
+
+ return new NativeImageFormat(arr, nComponents, 1, nCols);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorScaler.java b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
new file mode 100644
index 0000000..a1cc169
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+/**
+ * This class provides functionality for scaling color data when
+ * ranges of the source and destination color values differs.
+ */
+public class ColorScaler {
+ private static final float MAX_SHORT = 0xFFFF;
+ private static final float MAX_SIGNED_SHORT = 0x7FFF;
+
+ private static final float MAX_XYZ = 1f + (32767f/32768f);
+
+ // Cached values for scaling color data
+ private float[] channelMinValues = null;
+ private float[] channelMulipliers = null; // for scale
+ private float[] invChannelMulipliers = null; // for unscale
+
+ int nColorChannels = 0;
+
+ // For scaling rasters, false if transfer type is double or float
+ boolean isTTypeIntegral = false;
+
+ /**
+ * Loads scaling data for raster. Note, if profile pf is null,
+ * for non-integral data types multipliers are not initialized.
+ * @param r - raster
+ * @param pf - profile which helps to determine the ranges of the color data
+ */
+ public void loadScalingData(Raster r, ICC_Profile pf) {
+ boolean isSrcTTypeIntegral =
+ r.getTransferType() != DataBuffer.TYPE_FLOAT &&
+ r.getTransferType() != DataBuffer.TYPE_DOUBLE;
+ if (isSrcTTypeIntegral)
+ loadScalingData(r.getSampleModel());
+ else if (pf != null)
+ loadScalingData(pf);
+ }
+
+ /**
+ * Use this method only for integral transfer types.
+ * Extracts min/max values from the sample model
+ * @param sm - sample model
+ */
+ public void loadScalingData(SampleModel sm) {
+ // Supposing integral transfer type
+ isTTypeIntegral = true;
+
+ nColorChannels = sm.getNumBands();
+
+ channelMinValues = new float[nColorChannels];
+ channelMulipliers = new float[nColorChannels];
+ invChannelMulipliers = new float[nColorChannels];
+
+ boolean isSignedShort =
+ (sm.getTransferType() == DataBuffer.TYPE_SHORT);
+
+ float maxVal;
+ for (int i=0; i<nColorChannels; i++) {
+ channelMinValues[i] = 0;
+ if (isSignedShort) {
+ channelMulipliers[i] = MAX_SHORT / MAX_SIGNED_SHORT;
+ invChannelMulipliers[i] = MAX_SIGNED_SHORT / MAX_SHORT;
+ } else {
+ maxVal = ((1 << sm.getSampleSize(i)) - 1);
+ channelMulipliers[i] = MAX_SHORT / maxVal;
+ invChannelMulipliers[i] = maxVal / MAX_SHORT;
+ }
+ }
+ }
+
+ /**
+ * Use this method only for double of float transfer types.
+ * Extracts scaling data from the color space signature
+ * and other tags, stored in the profile
+ * @param pf - ICC profile
+ */
+ public void loadScalingData(ICC_Profile pf) {
+ // Supposing double or float transfer type
+ isTTypeIntegral = false;
+
+ nColorChannels = pf.getNumComponents();
+
+ // Get min/max values directly from the profile
+ // Very much like fillMinMaxValues in ICC_ColorSpace
+ float maxValues[] = new float[nColorChannels];
+ float minValues[] = new float[nColorChannels];
+
+ switch (pf.getColorSpaceType()) {
+ case ColorSpace.TYPE_XYZ:
+ minValues[0] = 0;
+ minValues[1] = 0;
+ minValues[2] = 0;
+ maxValues[0] = MAX_XYZ;
+ maxValues[1] = MAX_XYZ;
+ maxValues[2] = MAX_XYZ;
+ break;
+ case ColorSpace.TYPE_Lab:
+ minValues[0] = 0;
+ minValues[1] = -128;
+ minValues[2] = -128;
+ maxValues[0] = 100;
+ maxValues[1] = 127;
+ maxValues[2] = 127;
+ break;
+ default:
+ for (int i=0; i<nColorChannels; i++) {
+ minValues[i] = 0;
+ maxValues[i] = 1;
+ }
+ }
+
+ channelMinValues = minValues;
+ channelMulipliers = new float[nColorChannels];
+ invChannelMulipliers = new float[nColorChannels];
+
+ for (int i = 0; i < nColorChannels; i++) {
+ channelMulipliers[i] =
+ MAX_SHORT / (maxValues[i] - channelMinValues[i]);
+
+ invChannelMulipliers[i] =
+ (maxValues[i] - channelMinValues[i]) / MAX_SHORT;
+ }
+ }
+
+ /**
+ * Extracts scaling data from the color space
+ * @param cs - color space
+ */
+ public void loadScalingData(ColorSpace cs) {
+ nColorChannels = cs.getNumComponents();
+
+ channelMinValues = new float[nColorChannels];
+ channelMulipliers = new float[nColorChannels];
+ invChannelMulipliers = new float[nColorChannels];
+
+ for (int i = 0; i < nColorChannels; i++) {
+ channelMinValues[i] = cs.getMinValue(i);
+
+ channelMulipliers[i] =
+ MAX_SHORT / (cs.getMaxValue(i) - channelMinValues[i]);
+
+ invChannelMulipliers[i] =
+ (cs.getMaxValue(i) - channelMinValues[i]) / MAX_SHORT;
+ }
+ }
+
+ /**
+ * Scales and normalizes the whole raster and returns the result
+ * in the float array
+ * @param r - source raster
+ * @return scaled and normalized raster data
+ */
+ public float[][] scaleNormalize(Raster r) {
+ int width = r.getWidth();
+ int height = r.getHeight();
+ float result[][] = new float[width*height][nColorChannels];
+ float normMultipliers[] = new float[nColorChannels];
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ // Change max value from MAX_SHORT to 1f
+ for (int i=0; i<nColorChannels; i++) {
+ normMultipliers[i] = channelMulipliers[i] / MAX_SHORT;
+ }
+
+ int sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = r.getSample(row, col, chan);
+ result[pos][chan] = (sample * normMultipliers[chan]);
+ }
+ pos++;
+ }
+ }
+ } else { // Just get the samples...
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ result[pos][chan] = r.getSampleFloat(row, col, chan);
+ }
+ pos++;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Unscale the whole float array and put the result
+ * in the raster
+ * @param r - destination raster
+ * @param data - input pixels
+ */
+ public void unscaleNormalized(WritableRaster r, float data[][]) {
+ int width = r.getWidth();
+ int height = r.getHeight();
+ float normMultipliers[] = new float[nColorChannels];
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ // Change max value from MAX_SHORT to 1f
+ for (int i=0; i<nColorChannels; i++) {
+ normMultipliers[i] = invChannelMulipliers[i] * MAX_SHORT;
+ }
+
+ int sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = (int) (data[pos][chan] * normMultipliers[chan] + 0.5f);
+ r.setSample(row, col, chan, sample);
+ }
+ pos++;
+ }
+ }
+ } else { // Just set the samples...
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ r.setSample(row, col, chan, data[pos][chan]);
+ }
+ pos++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Scales the whole raster to short and returns the result
+ * in the array
+ * @param r - source raster
+ * @return scaled and normalized raster data
+ */
+ public short[] scale(Raster r) {
+ int width = r.getWidth();
+ int height = r.getHeight();
+ short result[] = new short[width*height*nColorChannels];
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ int sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = r.getSample(row, col, chan);
+ result[pos++] =
+ (short) (sample * channelMulipliers[chan] + 0.5f);
+ }
+ }
+ }
+ } else {
+ float sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = r.getSampleFloat(row, col, chan);
+ result[pos++] = (short) ((sample - channelMinValues[chan])
+ * channelMulipliers[chan] + 0.5f);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Unscales the whole data array and puts obtained values to the raster
+ * @param data - input data
+ * @param wr - destination raster
+ */
+ public void unscale(short[] data, WritableRaster wr) {
+ int width = wr.getWidth();
+ int height = wr.getHeight();
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ int sample;
+ for (int row=wr.getMinX(); row<width; row++) {
+ for (int col=wr.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = (int) ((data[pos++] & 0xFFFF) *
+ invChannelMulipliers[chan] + 0.5f);
+ wr.setSample(row, col, chan, sample);
+ }
+ }
+ }
+ } else {
+ float sample;
+ for (int row=wr.getMinX(); row<width; row++) {
+ for (int col=wr.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = (data[pos++] & 0xFFFF) *
+ invChannelMulipliers[chan] + channelMinValues[chan];
+ wr.setSample(row, col, chan, sample);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Scales one pixel and puts obtained values to the chanData
+ * @param pixelData - input pixel
+ * @param chanData - output buffer
+ * @param chanDataOffset - output buffer offset
+ */
+ public void scale(float[] pixelData, short[] chanData, int chanDataOffset) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ chanData[chanDataOffset + chan] =
+ (short) ((pixelData[chan] - channelMinValues[chan]) *
+ channelMulipliers[chan] + 0.5f);
+ }
+ }
+
+ /**
+ * Unscales one pixel and puts obtained values to the pixelData
+ * @param pixelData - output pixel
+ * @param chanData - input buffer
+ * @param chanDataOffset - input buffer offset
+ */
+ public void unscale(float[] pixelData, short[] chanData, int chanDataOffset) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ pixelData[chan] = (chanData[chanDataOffset + chan] & 0xFFFF)
+ * invChannelMulipliers[chan] + channelMinValues[chan];
+ }
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java b/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
new file mode 100644
index 0000000..2f7e519
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+
+/**
+ * Includes utility methods for reading ICC profile data.
+ * Created to provide public access to ICC_Profile methods
+ * for classes outside of java.awt.color
+ */
+public class ICC_ProfileHelper {
+ /**
+ * Utility method.
+ * Gets integer value from the byte array
+ * @param byteArray - byte array
+ * @param idx - byte offset
+ * @return integer value
+ */
+ public static int getIntFromByteArray(byte[] byteArray, int idx) {
+ return (byteArray[idx] & 0xFF)|
+ ((byteArray[idx+1] & 0xFF) << 8) |
+ ((byteArray[idx+2] & 0xFF) << 16)|
+ ((byteArray[idx+3] & 0xFF) << 24);
+ }
+
+ /**
+ * Utility method.
+ * Gets big endian integer value from the byte array
+ * @param byteArray - byte array
+ * @param idx - byte offset
+ * @return integer value
+ */
+ public static int getBigEndianFromByteArray(byte[] byteArray, int idx) {
+ return ((byteArray[idx] & 0xFF) << 24) |
+ ((byteArray[idx+1] & 0xFF) << 16) |
+ ((byteArray[idx+2] & 0xFF) << 8) |
+ ( byteArray[idx+3] & 0xFF);
+ }
+
+ /**
+ * Utility method.
+ * Gets short value from the byte array
+ * @param byteArray - byte array
+ * @param idx - byte offset
+ * @return short value
+ */
+ public static short getShortFromByteArray(byte[] byteArray, int idx) {
+ return (short) ((byteArray[idx] & 0xFF) |
+ ((byteArray[idx+1] & 0xFF) << 8));
+ }
+
+ /**
+ * Used in ICC_Transform class to check the rendering intent of the profile
+ * @param profile - ICC profile
+ * @return rendering intent
+ */
+ public static int getRenderingIntent(ICC_Profile profile) {
+ return getIntFromByteArray(
+ profile.getData(ICC_Profile.icSigHead), // pf header
+ ICC_Profile.icHdrRenderingIntent
+ );
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java b/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
new file mode 100644
index 0000000..27646c4
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+
+import org.apache.harmony.awt.gl.color.NativeCMM;
+
+/**
+ * This class encapsulates native ICC transform object, is responsible for its
+ * creation, destruction and passing its handle to the native CMM.
+ */
+public class ICC_Transform {
+ private long transformHandle;
+ private int numInputChannels;
+ private int numOutputChannels;
+ private ICC_Profile src;
+ private ICC_Profile dst;
+
+
+ /**
+ * @return Returns the number of input channels.
+ */
+ public int getNumInputChannels() {
+ return numInputChannels;
+ }
+
+ /**
+ * @return Returns the number of output channels.
+ */
+ public int getNumOutputChannels() {
+ return numOutputChannels;
+ }
+
+ /**
+ * @return Returns the dst.
+ */
+ public ICC_Profile getDst() {
+ return dst;
+ }
+
+ /**
+ * @return Returns the src.
+ */
+ public ICC_Profile getSrc() {
+ return src;
+ }
+
+ /**
+ * Constructs a multiprofile ICC transform
+ * @param profiles - list of ICC profiles
+ * @param renderIntents - only hints for CMM
+ */
+ public ICC_Transform(ICC_Profile[] profiles, int[] renderIntents) {
+ int numProfiles = profiles.length;
+
+ long[] profileHandles = new long[numProfiles];
+ for (int i=0; i<numProfiles; i++) {
+ profileHandles[i] = NativeCMM.getHandle(profiles[i]);
+ }
+
+ transformHandle = NativeCMM.cmmCreateMultiprofileTransform(
+ profileHandles,
+ renderIntents);
+
+ src = profiles[0];
+ dst = profiles[numProfiles-1];
+ numInputChannels = src.getNumComponents();
+ numOutputChannels = dst.getNumComponents();
+ }
+
+ /**
+ * This constructor is able to set intents by default
+ * @param profiles - list of ICC profiles
+ */
+ public ICC_Transform(ICC_Profile[] profiles) {
+ int numProfiles = profiles.length;
+ int[] renderingIntents = new int[numProfiles];
+
+ // Default is perceptual
+ int currRenderingIntent = ICC_Profile.icPerceptual;
+
+ // render as colorimetric for output device
+ if (profiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+ currRenderingIntent = ICC_Profile.icRelativeColorimetric;
+ }
+
+ // get the transforms from each profile
+ for (int i = 0; i < numProfiles; i++) {
+ // first or last profile cannot be abstract
+ // if profile is abstract, the only possible way is
+ // use AToB0Tag (perceptual), see ICC spec
+ if (i != 0 &&
+ i != numProfiles - 1 &&
+ profiles[i].getProfileClass() == ICC_Profile.CLASS_ABSTRACT
+ ) {
+ currRenderingIntent = ICC_Profile.icPerceptual;
+ }
+
+ renderingIntents[i] = currRenderingIntent;
+ // use current rendering intent
+ // to select LUT from the next profile (chaining)
+ currRenderingIntent =
+ ICC_ProfileHelper.getRenderingIntent(profiles[i]);
+ }
+
+ // Get the profile handles and go ahead
+ long[] profileHandles = new long[numProfiles];
+ for (int i=0; i<numProfiles; i++) {
+ profileHandles[i] = NativeCMM.getHandle(profiles[i]);
+ }
+
+ transformHandle = NativeCMM.cmmCreateMultiprofileTransform(
+ profileHandles,
+ renderingIntents);
+
+ src = profiles[0];
+ dst = profiles[numProfiles-1];
+ numInputChannels = src.getNumComponents();
+ numOutputChannels = dst.getNumComponents();
+ }
+
+ @Override
+ protected void finalize() {
+ if (transformHandle != 0) {
+ NativeCMM.cmmDeleteTransform(transformHandle);
+ }
+ }
+
+ /**
+ * Invokes native color conversion
+ * @param src - source image format
+ * @param dst - destination image format
+ */
+ public void translateColors(NativeImageFormat src, NativeImageFormat dst) {
+ NativeCMM.cmmTranslateColors(transformHandle, src, dst);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java b/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
new file mode 100644
index 0000000..5ea6d25
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 02.11.2004
+ *
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+
+public class LUTColorConverter {
+
+ private static byte from8lRGBtosRGB_LUT[];
+
+ private static byte from16lRGBtosRGB_LUT[];
+
+ private static byte fromsRGBto8lRGB_LUT[];
+
+ private static short fromsRGBto16lRGB_LUT[];
+
+ private static byte fromsRGBto8sRGB_LUTs[][];
+
+ public static ColorSpace LINEAR_RGB_CS;
+
+ public static ColorSpace LINEAR_GRAY_CS;
+
+ public static ColorSpace sRGB_CS;
+
+ public LUTColorConverter() {
+ }
+
+ /*
+ * This class prepared and returned lookup tables for conversion color
+ * values from Linear RGB Color Space to sRGB and vice versa.
+ * Conversion is producing according to sRGB Color Space definition.
+ * "A Standard Default Color Space for the Internet - sRGB",
+ * Michael Stokes (Hewlett-Packard), Matthew Anderson (Microsoft),
+ * Srinivasan Chandrasekar (Microsoft), Ricardo Motta (Hewlett-Packard)
+ * Version 1.10, November 5, 1996
+ * This document is available: http://www.w3.org/Graphics/Color/sRGB
+ */
+ public static byte[] getFrom8lRGBtosRGB_LUT() {
+ if (from8lRGBtosRGB_LUT == null) {
+ from8lRGBtosRGB_LUT = new byte[256];
+ float v;
+ for (int i = 0; i < 256; i++) {
+ v = (float)i / 255;
+ v = (v <= 0.04045f) ? v / 12.92f :
+ (float) Math.pow((v + 0.055) / 1.055, 2.4);
+ from8lRGBtosRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+ }
+ }
+ return from8lRGBtosRGB_LUT;
+ }
+
+ public static byte[] getFrom16lRGBtosRGB_LUT() {
+ if (from16lRGBtosRGB_LUT == null) {
+ from16lRGBtosRGB_LUT = new byte[65536];
+ float v;
+ for (int i = 0; i < 65536; i++) {
+ v = (float) i / 65535;
+ v = (v <= 0.04045f) ? v / 12.92f :
+ (float) Math.pow((v + 0.055) / 1.055, 2.4);
+ from16lRGBtosRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+ }
+ }
+ return from16lRGBtosRGB_LUT;
+ }
+
+ public static byte[] getFromsRGBto8lRGB_LUT() {
+ if (fromsRGBto8lRGB_LUT == null) {
+ fromsRGBto8lRGB_LUT = new byte[256];
+ float v;
+ for (int i = 0; i < 256; i++) {
+ v = (float) i / 255;
+ v = (v <= 0.0031308f) ? v * 12.92f :
+ ((float) Math.pow(v, 1.0 / 2.4)) * 1.055f - 0.055f;
+ fromsRGBto8lRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+ }
+ }
+ return fromsRGBto8lRGB_LUT;
+ }
+
+ public static short[] getFromsRGBto16lRGB_LUT() {
+ if (fromsRGBto16lRGB_LUT == null) {
+ fromsRGBto16lRGB_LUT = new short[256];
+ float v;
+ for (int i = 0; i < 256; i++) {
+ v = (float) i / 255;
+ v = (v <= 0.0031308f) ? v * 12.92f :
+ ((float) Math.pow(v, 1.0 / 2.4)) * 1.055f - 0.055f;
+ fromsRGBto16lRGB_LUT[i] = (short) Math.round(v * 65535.0f);
+ }
+ }
+ return fromsRGBto16lRGB_LUT;
+ }
+
+ public static byte[] getsRGBLUT(int bits) {
+ if (bits < 1) return null;
+ int idx = bits -1;
+ if(fromsRGBto8sRGB_LUTs == null) fromsRGBto8sRGB_LUTs = new byte[16][];
+
+ if(fromsRGBto8sRGB_LUTs[idx] == null){
+ fromsRGBto8sRGB_LUTs[idx] = createLUT(bits);
+ }
+ return fromsRGBto8sRGB_LUTs[idx];
+ }
+
+ private static byte[] createLUT(int bits) {
+ int lutSize = (1 << bits);
+ byte lut[] = new byte[lutSize];
+ for (int i = 0; i < lutSize; i++) {
+ lut[i] = (byte) (255.0f / (lutSize - 1) + 0.5f);
+ }
+ return lut;
+ }
+
+ public static boolean is_LINEAR_RGB_CS(ColorSpace cs) {
+ return (cs == LINEAR_RGB_CS);
+ }
+
+ public static boolean is_LINEAR_GRAY_CS(ColorSpace cs) {
+ return (cs == LINEAR_GRAY_CS);
+ }
+
+ public static boolean is_sRGB_CS(ColorSpace cs) {
+ return (cs == sRGB_CS);
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/NativeCMM.java b/awt/org/apache/harmony/awt/gl/color/NativeCMM.java
new file mode 100644
index 0000000..7f8c7e6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/NativeCMM.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+
+/**
+ * This class is a wrapper for the native CMM library
+ */
+public class NativeCMM {
+
+ /**
+ * Storage for profile handles, since they are private
+ * in ICC_Profile, but we need access to them.
+ */
+ private static HashMap<ICC_Profile, Long> profileHandles = new HashMap<ICC_Profile, Long>();
+
+ private static boolean isCMMLoaded;
+
+ public static void addHandle(ICC_Profile key, long handle) {
+ profileHandles.put(key, new Long(handle));
+ }
+
+ public static void removeHandle(ICC_Profile key) {
+ profileHandles.remove(key);
+ }
+
+ public static long getHandle(ICC_Profile key) {
+ return profileHandles.get(key).longValue();
+ }
+
+ /* ICC profile management */
+ public static native long cmmOpenProfile(byte[] data);
+ public static native void cmmCloseProfile(long profileID);
+ public static native int cmmGetProfileSize(long profileID);
+ public static native void cmmGetProfile(long profileID, byte[] data);
+ public static native int cmmGetProfileElementSize(long profileID, int signature);
+ public static native void cmmGetProfileElement(long profileID, int signature,
+ byte[] data);
+ public static native void cmmSetProfileElement(long profileID, int tagSignature,
+ byte[] data);
+
+
+ /* ICC transforms */
+ public static native long cmmCreateMultiprofileTransform(
+ long[] profileHandles,
+ int[] renderingIntents
+ );
+ public static native void cmmDeleteTransform(long transformHandle);
+ public static native void cmmTranslateColors(long transformHandle,
+ NativeImageFormat src,
+ NativeImageFormat dest);
+
+ static void loadCMM() {
+ if (!isCMMLoaded) {
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ System.loadLibrary("lcmm"); //$NON-NLS-1$
+ return null;
+ }
+ } );
+ isCMMLoaded = true;
+ }
+ }
+
+ /* load native CMM library */
+ static {
+ loadCMM();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java b/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
new file mode 100644
index 0000000..9594047
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
@@ -0,0 +1,642 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class converts java color/sample models to the LCMS pixel formats.
+ * It also encapsulates all the information about the image format, which native CMM
+ * needs to have in order to read/write data.
+ *
+ * At present planar formats (multiple bands) are not supported
+ * and they are handled as a common (custom) case.
+ * Samples other than 1 - 7 bytes and multiple of 8 bits are
+ * also handled as custom (and won't be supported in the nearest future).
+ */
+class NativeImageFormat {
+ //////////////////////////////////////////////
+ // LCMS Pixel types
+ private static final int PT_ANY = 0; // Don't check colorspace
+ // 1 & 2 are reserved
+ private static final int PT_GRAY = 3;
+ private static final int PT_RGB = 4;
+ // Skipping other since we don't use them here
+ ///////////////////////////////////////////////
+
+ // Conversion of predefined BufferedImage formats to LCMS formats
+ private static final int INT_RGB_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ extraSh(1)|
+ channelsSh(3)|
+ bytesSh(1)|
+ doswapSh(1)|
+ swapfirstSh(1);
+
+ private static final int INT_ARGB_LCMS_FMT = INT_RGB_LCMS_FMT;
+
+ private static final int INT_BGR_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ extraSh(1)|
+ channelsSh(3)|
+ bytesSh(1);
+
+ private static final int THREE_BYTE_BGR_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ channelsSh(3)|
+ bytesSh(1)|
+ doswapSh(1);
+
+ private static final int FOUR_BYTE_ABGR_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ extraSh(1)|
+ channelsSh(3)|
+ bytesSh(1)|
+ doswapSh(1);
+
+ private static final int BYTE_GRAY_LCMS_FMT =
+ colorspaceSh(PT_GRAY)|
+ channelsSh(1)|
+ bytesSh(1);
+
+ private static final int USHORT_GRAY_LCMS_FMT =
+ colorspaceSh(PT_GRAY)|
+ channelsSh(1)|
+ bytesSh(2);
+
+ // LCMS format packed into 32 bit value. For description
+ // of this format refer to LCMS documentation.
+ private int cmmFormat = 0;
+
+ // Dimensions
+ private int rows = 0;
+ private int cols = 0;
+
+ // Scanline may contain some padding in the end
+ private int scanlineStride = -1;
+
+ private Object imageData;
+ // It's possible to have offset from the beginning of the array
+ private int dataOffset;
+
+ // Has the image alpha channel? If has - here its band band offset goes
+ private int alphaOffset = -1;
+
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ static {
+ NativeCMM.loadCMM();
+ initIDs();
+ }
+
+ ////////////////////////////////////
+ // LCMS image format encoders
+ ////////////////////////////////////
+ private static int colorspaceSh(int s) {
+ return (s << 16);
+ }
+
+ private static int swapfirstSh(int s) {
+ return (s << 14);
+ }
+
+ private static int flavorSh(int s) {
+ return (s << 13);
+ }
+
+ private static int planarSh(int s) {
+ return (s << 12);
+ }
+
+ private static int endianSh(int s) {
+ return (s << 11);
+ }
+
+ private static int doswapSh(int s) {
+ return (s << 10);
+ }
+
+ private static int extraSh(int s) {
+ return (s << 7);
+ }
+
+ private static int channelsSh(int s) {
+ return (s << 3);
+ }
+
+ private static int bytesSh(int s) {
+ return s;
+ }
+ ////////////////////////////////////
+ // End of LCMS image format encoders
+ ////////////////////////////////////
+
+ // Accessors
+ Object getChannelData() {
+ return imageData;
+ }
+
+ int getNumCols() {
+ return cols;
+ }
+
+ int getNumRows() {
+ return rows;
+ }
+
+ // Constructors
+ public NativeImageFormat() {
+ }
+
+ /**
+ * Simple image layout for common case with
+ * not optimized workflow.
+ *
+ * For hifi colorspaces with 5+ color channels imgData
+ * should be <code>byte</code> array.
+ *
+ * For common colorspaces with up to 4 color channels it
+ * should be <code>short</code> array.
+ *
+ * Alpha channel is handled by caller, not by CMS.
+ *
+ * Color channels are in their natural order (not BGR but RGB).
+ *
+ * @param imgData - array of <code>byte</code> or <code>short</code>
+ * @param nChannels - number of channels
+ * @param nRows - number of scanlines in the image
+ * @param nCols - number of pixels in one row of the image
+ */
+ public NativeImageFormat(Object imgData, int nChannels, int nRows, int nCols) {
+ if (imgData instanceof short[]) {
+ cmmFormat |= bytesSh(2);
+ }
+ else if (imgData instanceof byte[]) {
+ cmmFormat |= bytesSh(1);
+ }
+ else
+ // awt.47=First argument should be byte or short array
+ throw new IllegalArgumentException(Messages.getString("awt.47")); //$NON-NLS-1$
+
+ cmmFormat |= channelsSh(nChannels);
+
+ rows = nRows;
+ cols = nCols;
+
+ imageData = imgData;
+
+ dataOffset = 0;
+ }
+
+ /**
+ * Deduces image format from the buffered image type
+ * or color and sample models.
+ * @param bi - image
+ * @return image format object
+ */
+ public static NativeImageFormat createNativeImageFormat(BufferedImage bi) {
+ NativeImageFormat fmt = new NativeImageFormat();
+
+ switch (bi.getType()) {
+ case BufferedImage.TYPE_INT_RGB: {
+ fmt.cmmFormat = INT_RGB_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE: {
+ fmt.cmmFormat = INT_ARGB_LCMS_FMT;
+ fmt.alphaOffset = 3;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_BGR: {
+ fmt.cmmFormat = INT_BGR_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ fmt.cmmFormat = THREE_BYTE_BGR_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ case BufferedImage.TYPE_4BYTE_ABGR: {
+ fmt.cmmFormat = FOUR_BYTE_ABGR_LCMS_FMT;
+ fmt.alphaOffset = 0;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ fmt.cmmFormat = BYTE_GRAY_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY: {
+ fmt.cmmFormat = USHORT_GRAY_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_BINARY:
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_INDEXED: {
+ // A bunch of unsupported formats
+ return null;
+ }
+
+ default:
+ break; // Try to look at sample model and color model
+ }
+
+
+ if (fmt.cmmFormat == 0) {
+ ColorModel cm = bi.getColorModel();
+ SampleModel sm = bi.getSampleModel();
+
+ if (sm instanceof ComponentSampleModel) {
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ fmt.cmmFormat = getFormatFromComponentModel(csm, cm.hasAlpha());
+ fmt.scanlineStride = calculateScanlineStrideCSM(csm, bi.getRaster());
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, cm.hasAlpha());
+ fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, bi.getRaster());
+ }
+
+ if (cm.hasAlpha())
+ fmt.alphaOffset = calculateAlphaOffset(sm, bi.getRaster());
+ }
+
+ if (fmt.cmmFormat == 0)
+ return null;
+
+ if (!fmt.setImageData(bi.getRaster().getDataBuffer())) {
+ return null;
+ }
+
+ fmt.rows = bi.getHeight();
+ fmt.cols = bi.getWidth();
+
+ fmt.dataOffset = bi.getRaster().getDataBuffer().getOffset();
+
+ return fmt;
+ }
+
+ /**
+ * Deduces image format from the raster sample model.
+ * @param r - raster
+ * @return image format object
+ */
+ public static NativeImageFormat createNativeImageFormat(Raster r) {
+ NativeImageFormat fmt = new NativeImageFormat();
+ SampleModel sm = r.getSampleModel();
+
+ // Assume that there's no alpha
+ if (sm instanceof ComponentSampleModel) {
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ fmt.cmmFormat = getFormatFromComponentModel(csm, false);
+ fmt.scanlineStride = calculateScanlineStrideCSM(csm, r);
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, false);
+ fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, r);
+ }
+
+ if (fmt.cmmFormat == 0)
+ return null;
+
+ fmt.cols = r.getWidth();
+ fmt.rows = r.getHeight();
+ fmt.dataOffset = r.getDataBuffer().getOffset();
+
+ if (!fmt.setImageData(r.getDataBuffer()))
+ return null;
+
+ return fmt;
+ }
+
+ /**
+ * Obtains LCMS format from the component sample model
+ * @param sm - sample model
+ * @param hasAlpha - true if there's an alpha channel
+ * @return LCMS format
+ */
+ private static int getFormatFromComponentModel(ComponentSampleModel sm, boolean hasAlpha) {
+ // Multiple data arrays (banks) not supported
+ int bankIndex = sm.getBankIndices()[0];
+ for (int i=1; i < sm.getNumBands(); i++) {
+ if (sm.getBankIndices()[i] != bankIndex) {
+ return 0;
+ }
+ }
+
+ int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands();
+ int extra = hasAlpha ? 1 : 0;
+ int bytes = 1;
+ switch (sm.getDataType()) {
+ case DataBuffer.TYPE_BYTE:
+ bytes = 1; break;
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ bytes = 2; break;
+ case DataBuffer.TYPE_INT:
+ bytes = 4; break;
+ case DataBuffer.TYPE_DOUBLE:
+ bytes = 0; break;
+ default:
+ return 0; // Unsupported data type
+ }
+
+ int doSwap = 0;
+ int swapFirst = 0;
+ boolean knownFormat = false;
+
+ int i;
+
+ // "RGBA"
+ for (i=0; i < sm.getNumBands(); i++) {
+ if (sm.getBandOffsets()[i] != i) break;
+ }
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+
+ // "ARGB"
+ if (!knownFormat) {
+ for (i=0; i < sm.getNumBands()-1; i++) {
+ if (sm.getBandOffsets()[i] != i+1) break;
+ }
+ if (sm.getBandOffsets()[i] == 0) i++;
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "BGRA"
+ if (!knownFormat) {
+ for (i=0; i < sm.getNumBands()-1; i++) {
+ if (sm.getBandOffsets()[i] != sm.getNumBands() - 2 - i) break;
+ }
+ if (sm.getBandOffsets()[i] == sm.getNumBands()-1) i++;
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "ABGR"
+ if (!knownFormat) {
+ for (i=0; i < sm.getNumBands(); i++) {
+ if (sm.getBandOffsets()[i] != sm.getNumBands() - 1 - i) break;
+ }
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+ }
+
+ // XXX - Planar formats are not supported yet
+ if (!knownFormat)
+ return 0;
+
+ return
+ channelsSh(channels) |
+ bytesSh(bytes) |
+ extraSh(extra) |
+ doswapSh(doSwap) |
+ swapfirstSh(swapFirst);
+ }
+
+ /**
+ * Obtains LCMS format from the single pixel packed sample model
+ * @param sm - sample model
+ * @param hasAlpha - true if there's an alpha channel
+ * @return LCMS format
+ */
+ private static int getFormatFromSPPSampleModel(SinglePixelPackedSampleModel sm,
+ boolean hasAlpha) {
+ // Can we extract bytes?
+ int mask = sm.getBitMasks()[0] >>> sm.getBitOffsets()[0];
+ if (!(mask == 0xFF || mask == 0xFFFF || mask == 0xFFFFFFFF))
+ return 0;
+
+ // All masks are same?
+ for (int i = 1; i < sm.getNumBands(); i++) {
+ if ((sm.getBitMasks()[i] >>> sm.getBitOffsets()[i]) != mask)
+ return 0;
+ }
+
+ int pixelSize = 0;
+ // Check if data type is supported
+ if (sm.getDataType() == DataBuffer.TYPE_USHORT)
+ pixelSize = 2;
+ else if (sm.getDataType() == DataBuffer.TYPE_INT)
+ pixelSize = 4;
+ else
+ return 0;
+
+
+ int bytes = 0;
+ switch (mask) {
+ case 0xFF:
+ bytes = 1;
+ break;
+ case 0xFFFF:
+ bytes = 2;
+ break;
+ case 0xFFFFFFFF:
+ bytes = 4;
+ break;
+ default: return 0;
+ }
+
+
+ int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands();
+ int extra = hasAlpha ? 1 : 0;
+ extra += pixelSize/bytes - sm.getNumBands(); // Unused bytes?
+
+ // Form an ArrayList containing offset for each band
+ ArrayList<Integer> offsetsLst = new ArrayList<Integer>();
+ for (int k=0; k < sm.getNumBands(); k++) {
+ offsetsLst.add(new Integer(sm.getBitOffsets()[k]/(bytes*8)));
+ }
+
+ // Add offsets for unused space
+ for (int i=0; i<pixelSize/bytes; i++) {
+ if (offsetsLst.indexOf(new Integer(i)) < 0)
+ offsetsLst.add(new Integer(i));
+ }
+
+ int offsets[] = new int[pixelSize/bytes];
+ for (int i=0; i<offsetsLst.size(); i++) {
+ offsets[i] = offsetsLst.get(i).intValue();
+ }
+
+ int doSwap = 0;
+ int swapFirst = 0;
+ boolean knownFormat = false;
+
+ int i;
+
+ // "RGBA"
+ for (i=0; i < pixelSize; i++) {
+ if (offsets[i] != i) break;
+ }
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+
+ // "ARGB"
+ if (!knownFormat) {
+ for (i=0; i < pixelSize-1; i++) {
+ if (offsets[i] != i+1) break;
+ }
+ if (offsets[i] == 0) i++;
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "BGRA"
+ if (!knownFormat) {
+ for (i=0; i < pixelSize-1; i++) {
+ if (offsets[i] != pixelSize - 2 - i) break;
+ }
+ if (offsets[i] == pixelSize-1) i++;
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "ABGR"
+ if (!knownFormat) {
+ for (i=0; i < pixelSize; i++) {
+ if (offsets[i] != pixelSize - 1 - i) break;
+ }
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+ }
+
+ // XXX - Planar formats are not supported yet
+ if (!knownFormat)
+ return 0;
+
+ return
+ channelsSh(channels) |
+ bytesSh(bytes) |
+ extraSh(extra) |
+ doswapSh(doSwap) |
+ swapfirstSh(swapFirst);
+ }
+
+ /**
+ * Obtains data array from the DataBuffer object
+ * @param db - data buffer
+ * @return - true if successful
+ */
+ private boolean setImageData(DataBuffer db) {
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ imageData = dbAccess.getData(db);
+ } catch (IllegalArgumentException e) {
+ return false; // Unknown data buffer type
+ }
+
+ return true;
+ }
+
+ /**
+ * Calculates scanline stride in bytes
+ * @param csm - component sample model
+ * @param r - raster
+ * @return scanline stride in bytes
+ */
+ private static int calculateScanlineStrideCSM(ComponentSampleModel csm, Raster r) {
+ if (csm.getScanlineStride() != csm.getPixelStride()*csm.getWidth()) {
+ int dataTypeSize = DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+ return csm.getScanlineStride()*dataTypeSize;
+ }
+ return -1;
+ }
+
+ /**
+ * Calculates scanline stride in bytes
+ * @param sppsm - sample model
+ * @param r - raster
+ * @return scanline stride in bytes
+ */
+ private static int calculateScanlineStrideSPPSM(SinglePixelPackedSampleModel sppsm, Raster r) {
+ if (sppsm.getScanlineStride() != sppsm.getWidth()) {
+ int dataTypeSize = DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+ return sppsm.getScanlineStride()*dataTypeSize;
+ }
+ return -1;
+ }
+
+ /**
+ * Calculates byte offset of the alpha channel from the beginning of the pixel data
+ * @param sm - sample model
+ * @param r - raster
+ * @return byte offset of the alpha channel
+ */
+ private static int calculateAlphaOffset(SampleModel sm, Raster r) {
+ if (sm instanceof ComponentSampleModel) {
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ int dataTypeSize =
+ DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+ return
+ csm.getBandOffsets()[csm.getBandOffsets().length - 1] * dataTypeSize;
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ return sppsm.getBitOffsets()[sppsm.getBitOffsets().length - 1] / 8;
+ } else {
+ return -1; // No offset, don't copy alpha
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFont.java b/awt/org/apache/harmony/awt/gl/font/AndroidFont.java
new file mode 100644
index 0000000..e8ad1bb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFont.java
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.util.Hashtable;
+import java.util.Locale;
+
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.Glyph;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Linux platform font peer implementation based on Xft and FreeType libraries.
+ */
+public class AndroidFont extends FontPeerImpl {
+
+ // Pairs of [begin, end],[..].. unicode ranges values
+ private int[] fontUnicodeRanges;
+
+ // table with loaded cached Glyphs
+ private Hashtable glyphs = new Hashtable();
+
+ // X11 display value
+ private long display = 0;
+
+ // X11 screen value
+ private int screen = 0;
+
+ public AndroidFont(String fontName, int fontStyle, int fontSize) {
+ /*
+ * Workaround : to initialize awt platform-dependent fields and libraries.
+ */
+ Toolkit.getDefaultToolkit();
+ this.name = fontName;
+ this.size = fontSize;
+ this.style = fontStyle;
+
+ initAndroidFont();
+ }
+
+ /**
+ * Initializes some native dependent font information, e.g. number of glyphs,
+ * font metrics, italic angle etc.
+ */
+ public void initAndroidFont(){
+ this.nlm = new AndroidLineMetrics(this, null, " "); //$NON-NLS-1$
+ this.ascent = nlm.getLogicalAscent();
+ this.descent = nlm.getLogicalDescent();
+ this.height = nlm.getHeight();
+ this.leading = nlm.getLogicalLeading();
+ this.maxAdvance = nlm.getLogicalMaxCharWidth();
+
+ if (this.fontType == FontManager.FONT_TYPE_T1){
+ this.defaultChar = 1;
+ } else {
+ this.defaultChar = 0;
+ }
+
+ this.maxCharBounds = new Rectangle2D.Float(0, -nlm.getAscent(), nlm.getMaxCharWidth(), this.height);
+ }
+
+
+ public boolean canDisplay(char chr) {
+ // TODO: to improve performance there is a sence to implement get
+ // unicode ranges to check if char can be displayed without
+ // native calls in isGlyphExists() method
+
+ return isGlyphExists(chr);
+ }
+
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at) {
+
+ // Initialize baseline offsets
+ nlm.getBaselineOffsets();
+
+ LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone());
+ lm.setNumChars(str.length());
+
+ if ((at != null) && (!at.isIdentity())){
+ lm.scale((float)at.getScaleX(), (float)at.getScaleY());
+ }
+
+ return lm;
+ }
+
+ public String getPSName() {
+ return psName;
+ }
+
+ public String getFamily(Locale l) {
+ // TODO: implement localized family
+ if (fontType == FontManager.FONT_TYPE_TT){
+ return this.getFamily();
+ }
+
+ return this.fontFamilyName;
+ }
+
+ public String getFontName(Locale l) {
+ if ((pFont == 0) || (this.fontType == FontManager.FONT_TYPE_T1)){
+ return this.name;
+ }
+
+ return this.getFontName();
+ }
+
+
+ public int getMissingGlyphCode() {
+ return getDefaultGlyph().getGlyphCode();
+ }
+
+ public Glyph getGlyph(char index) {
+ Glyph result = null;
+
+ Object key = new Integer(index);
+ if (glyphs.containsKey(key)) {
+ result = (Glyph) glyphs.get(key);
+ } else {
+ if (this.addGlyph(index)) {
+ result = (Glyph) glyphs.get(key);
+ } else {
+ result = this.getDefaultGlyph();
+ }
+ }
+
+ return result;
+ }
+
+ public Glyph getDefaultGlyph() {
+ throw new RuntimeException("DefaultGlyphs not implemented!");
+ }
+
+ /**
+ * Disposes native font handle. If this font peer was created from InputStream
+ * temporary created font resource file is deleted.
+ */
+ public void dispose(){
+ String tempDirName;
+ if (pFont != 0){
+ pFont = 0;
+
+ if (isCreatedFromStream()) {
+ File fontFile = new File(getTempFontFileName());
+ tempDirName = fontFile.getParent();
+ fontFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Add glyph to cached Glyph objects in this LinuxFont object.
+ *
+ * @param uChar the specified character
+ * @return true if glyph of the specified character exists in this
+ * LinuxFont or this character is escape sequence character.
+ */
+ public boolean addGlyph(char uChar) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ /**
+ * Adds range of existing glyphs to this LinuxFont object
+ *
+ * @param uFirst the lowest range's bound, inclusive
+ * @param uLast the highest range's bound, exclusive
+ */
+ public void addGlyphs(char uFirst, char uLast) {
+
+ char index = uFirst;
+ if (uLast < uFirst) {
+ // awt.09=min range bound value is grater than max range bound
+ throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$
+ }
+ while (index < uLast) {
+ addGlyph(index);
+ index++;
+ }
+
+ }
+
+ /**
+ * Returns true if specified character has corresopnding glyph, false otherwise.
+ *
+ * @param uIndex specified char
+ */
+ public boolean isGlyphExists(char uIndex) {
+ throw new RuntimeException("DefaultGlyphs not implemented!");
+ }
+
+ /**
+ * Returns an array of unicode ranges that are supported by this LinuxFont.
+ */
+ public int[] getUnicodeRanges() {
+ int[] ranges = new int[fontUnicodeRanges.length];
+ System.arraycopy(fontUnicodeRanges, 0, ranges, 0,
+ fontUnicodeRanges.length);
+
+ return ranges;
+ }
+
+ /**
+ * Return Font object if it was successfully embedded in System
+ */
+ public static Font embedFont(String absolutePath){
+ throw new RuntimeException("embedFont not implemented!");
+ }
+
+ public String getFontName(){
+ if ((pFont != 0) && (faceName == null)){
+ if (this.fontType == FontManager.FONT_TYPE_T1){
+ faceName = getFamily();
+ }
+ }
+ return faceName;
+ }
+
+ public String getFamily() {
+ return fontFamilyName;
+ }
+
+ /**
+ * Returns initiated FontExtraMetrics instance of this WindowsFont.
+ */
+ public FontExtraMetrics getExtraMetrics(){
+ throw new RuntimeException("Not implemented!");
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java b/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
new file mode 100644
index 0000000..063a256
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.peer.FontPeer;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontProperty;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import android.util.Log;
+
+public class AndroidFontManager extends FontManager {
+
+ // set of all available faces supported by a system
+ String faces[];
+
+ // weight names according to xlfd structure
+ public static final String[] LINUX_WEIGHT_NAMES = {
+ "black", "bold", "demibold", "medium", "light" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ // slant names according to xlfd structure
+ public static final String[] LINUX_SLANT_NAMES = {
+ "i", "o", "r" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ };
+
+ /** Singleton AndroidFontManager instance */
+ public static final AndroidFontManager inst = new AndroidFontManager();
+
+ private AndroidFontManager() {
+ super();
+ faces = new String[] {/*"PLAIN",*/ "NORMAL", "BOLD", "ITALIC", "BOLDITALIC"};
+ initFontProperties();
+ }
+
+ public void initLCIDTable(){
+ throw new RuntimeException("Not implemented!");
+ }
+
+ /**
+ * Returns temporary File object to store data from InputStream.
+ * This File object saved to `~/.fonts/' folder that is included in the
+ * list of folders searched for font files, and this is where user-specific
+ * font files should be installed.
+ */
+ public File getTempFontFile()throws IOException{
+ File fontFile = File.createTempFile("jFont", ".ttf", new File(System.getProperty("user.home") +"/.fonts")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ fontFile.deleteOnExit();
+
+ return fontFile;
+ }
+
+ /**
+ * Initializes fProperties array field for the current system configuration font
+ * property file.
+ *
+ * RuntimeException is thrown if font property contains incorrect format of
+ * xlfd string.
+ *
+ * @return true is success, false if font property doesn't exist or doesn't
+ * contain roperties.
+ */
+ public boolean initFontProperties(){
+ File fpFile = getFontPropertyFile();
+ if (fpFile == null){
+ return false;
+ }
+
+ Properties props = getProperties(fpFile);
+ if (props == null){
+ return false;
+ }
+
+ for (int i=0; i < LOGICAL_FONT_NAMES.length; i++){
+ String lName = LOGICAL_FONT_NAMES[i];
+ for (int j=0; j < STYLE_NAMES.length; j++){
+ String styleName = STYLE_NAMES[j];
+ Vector propsVector = new Vector();
+
+ // Number of entries for a logical font
+ int numComp = 0;
+ // Is more entries for this style and logical font name left
+ boolean moreEntries = true;
+ String value = null;
+
+ while(moreEntries){
+ // Component Font Mappings property name
+ String property = FONT_MAPPING_KEYS[0].replaceAll("LogicalFontName", lName).replaceAll("StyleName", styleName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ value = props.getProperty(property);
+
+ // If the StyleName is omitted, it's assumed to be plain
+ if ((j == 0) && (value == null)){
+ property = FONT_MAPPING_KEYS[1].replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$
+ value = props.getProperty(property);
+ }
+
+ if (value != null){
+ String[] fields = parseXLFD(value);
+
+ if (fields == null){
+ // awt.08=xfld parse string error: {0}
+ throw new RuntimeException(Messages.getString("awt.08", value)); //$NON-NLS-1$
+ }
+
+ String fontName = fields[1];
+ String weight = fields[2];
+ String italic = fields[3];
+
+ int style = getBoldStyle(weight) | getItalicStyle(italic);
+ // Component Font Character Encodings property value
+ String encoding = props.getProperty(FONT_CHARACTER_ENCODING.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Exclusion Ranges property value
+ String exclString = props.getProperty(EXCLUSION_RANGES.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
+ int[] exclRange = parseIntervals(exclString);
+
+ FontProperty fp = new AndroidFontProperty(lName, styleName, null, fontName, value, style, exclRange, encoding);
+
+ propsVector.add(fp);
+ numComp++;
+ } else {
+ moreEntries = false;
+ }
+ }
+ fProperties.put(LOGICAL_FONT_NAMES[i] + "." + j, propsVector); //$NON-NLS-1$
+ }
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Returns style according to the xlfd weight string.
+ * If weight string is incorrect returned value is Font.PLAIN
+ *
+ * @param str weight name String
+ */
+ private int getBoldStyle(String str){
+ for (int i = 0; i < LINUX_WEIGHT_NAMES.length;i++){
+ if (str.equalsIgnoreCase(LINUX_WEIGHT_NAMES[i])){
+ return (i < 3) ? Font.BOLD : Font.PLAIN;
+ }
+ }
+ return Font.PLAIN;
+ }
+
+ /**
+ * Returns style according to the xlfd slant string.
+ * If slant string is incorrect returned value is Font.PLAIN
+ *
+ * @param str slant name String
+ */
+ private int getItalicStyle(String str){
+ for (int i = 0; i < LINUX_SLANT_NAMES.length;i++){
+ if (str.equalsIgnoreCase(LINUX_SLANT_NAMES[i])){
+ return (i < 2) ? Font.ITALIC : Font.PLAIN;
+ }
+ }
+ return Font.PLAIN;
+ }
+
+ /**
+ * Parse xlfd string and returns array of Strings with separate xlfd
+ * elements.<p>
+ *
+ * xlfd format:
+ * -Foundry-Family-Weight-Slant-Width-Style-PixelSize-PointSize-ResX-ResY-Spacing-AvgWidth-Registry-Encoding
+ * @param xlfd String parameter in xlfd format
+ */
+ public static String[] parseXLFD(String xlfd){
+ int fieldsCount = 14;
+ String fieldsDelim = "-"; //$NON-NLS-1$
+ String[] res = new String[fieldsCount];
+ if (!xlfd.startsWith(fieldsDelim)){
+ return null;
+ }
+
+ xlfd = xlfd.substring(1);
+ int i=0;
+ int pos;
+ for (i=0; i < fieldsCount-1; i++){
+ pos = xlfd.indexOf(fieldsDelim);
+ if (pos != -1){
+ res[i] = xlfd.substring(0, pos);
+ xlfd = xlfd.substring(pos + 1);
+ } else {
+ return null;
+ }
+ }
+ pos = xlfd.indexOf(fieldsDelim);
+
+ // check if no fields left
+ if(pos != -1){
+ return null;
+ }
+ res[fieldsCount-1] = xlfd;
+
+ return res;
+ }
+
+ public int getFaceIndex(String faceName){
+
+ for (int i = 0; i < faces.length; i++) {
+ if(faces[i].equals(faceName)){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public String[] getAllFamilies(){
+ if (allFamilies == null){
+ allFamilies = new String[]{"sans-serif", "serif", "monospace"};
+ }
+ return allFamilies;
+ }
+
+ public Font[] getAllFonts(){
+ Font[] fonts = new Font[faces.length];
+ for (int i =0; i < fonts.length;i++){
+ fonts[i] = new Font(faces[i], Font.PLAIN, 1);
+ }
+ return fonts;
+ }
+
+ public FontPeer createPhysicalFontPeer(String name, int style, int size) {
+ AndroidFont peer;
+ int familyIndex = getFamilyIndex(name);
+ if (familyIndex != -1){
+ // !! we use family names from the list with cached families because
+ // they are differ from the family names in xlfd structure, in xlfd
+ // family names mostly in lower case.
+ peer = new AndroidFont(getFamily(familyIndex), style, size);
+ peer.setFamily(getFamily(familyIndex));
+ return peer;
+ }
+ int faceIndex = getFaceIndex(name);
+ if (faceIndex != -1){
+
+ peer = new AndroidFont(name, style, size);
+ return peer;
+ }
+
+ return null;
+ }
+
+ public FontPeer createDefaultFont(int style, int size) {
+ Log.i("DEFAULT FONT", Integer.toString(style));
+ return new AndroidFont(DEFAULT_NAME, style, size);
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java b/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
new file mode 100644
index 0000000..0cfdc43
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ *
+ */
+package org.apache.harmony.awt.gl.font;
+
+/**
+ * Android FontProperty implementation, applicable for Linux formats of
+ * font property files.
+ */
+public class AndroidFontProperty extends FontProperty {
+
+ /** xlfd string that is applicable for Linux font.properties */
+ String xlfd;
+
+ /** logical name of the font corresponding to this FontProperty */
+ String logicalName;
+
+ /** style name of the font corresponding to this FontProperty */
+ String styleName;
+
+ public AndroidFontProperty(String _logicalName, String _styleName, String _fileName, String _name, String _xlfd, int _style, int[] exclusionRange, String _encoding){
+ this.logicalName = _logicalName;
+ this.styleName = _styleName;
+ this.name = _name;
+ this.encoding = _encoding;
+ this.exclRange = exclusionRange;
+ this.fileName = _fileName;
+ this.xlfd = _xlfd;
+ this.style = _style;
+ }
+
+ /**
+ * Returns logical name of the font corresponding to this FontProperty.
+ */
+ public String getLogicalName(){
+ return logicalName;
+ }
+
+ /**
+ * Returns style name of the font corresponding to this FontProperty.
+ */
+ public String getStyleName(){
+ return styleName;
+ }
+
+ /**
+ * Returns xlfd string of this FontProperty.
+ */
+ public String getXLFD(){
+ return xlfd;
+ }
+
+ public String toString(){
+ return new String(this.getClass().getName() +
+ "[name=" + name + //$NON-NLS-1$
+ ",fileName="+ fileName + //$NON-NLS-1$
+ ",Charset=" + encoding + //$NON-NLS-1$
+ ",exclRange=" + exclRange + //$NON-NLS-1$
+ ",xlfd=" + xlfd + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java b/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
new file mode 100644
index 0000000..4ce5aed
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
@@ -0,0 +1,219 @@
+package org.apache.harmony.awt.gl.font;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Font;
+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;
+
+import android.util.Log;
+import android.graphics.Path;
+
+public class AndroidGlyphVector extends GlyphVector {
+
+ // array of chars defined in constructor
+ public char[] charVector;
+
+ // array of Glyph objects, that describe information about glyphs
+ public Glyph[] vector;
+
+ // array of default positions of glyphs in GlyphVector
+ // without applying GlyphVector's transform
+ float[] defaultPositions;
+
+ // array of logical positions of glyphs in GlyphVector
+
+ float[] logicalPositions;
+
+ // array of visual (real) positions of glyphs in GlyphVector
+ public float[] visualPositions;
+
+ // FontRenderContext for this vector.
+ protected FontRenderContext vectorFRC;
+
+ // layout flags mask
+ protected int layoutFlags = 0;
+
+ // array of cached glyph outlines
+ protected Shape[] gvShapes;
+
+ FontPeerImpl peer;
+
+ // font corresponding to the GlyphVector
+ Font font;
+
+ // ascent of the font
+ float ascent;
+
+ // height of the font
+ float height;
+
+ // leading of the font
+ float leading;
+
+ // descent of the font
+ float descent;
+
+ // transform of the GlyphVector
+ AffineTransform transform;
+
+ @SuppressWarnings("deprecation")
+ public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt,
+ int flags) {
+ int len = chars.length;
+ this.font = fnt;
+ LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc);
+ this.ascent = lmImpl.getAscent();
+ this.height = lmImpl.getHeight();
+ this.leading = lmImpl.getLeading();
+ this.descent = lmImpl.getDescent();
+ this.charVector = chars;
+ this.vectorFRC = frc;
+ }
+
+ public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt) {
+ this(chars, frc, fnt, 0);
+ }
+
+ public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt) {
+ this(str.toCharArray(), frc, fnt, 0);
+ }
+
+ public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) {
+ this(str.toCharArray(), frc, fnt, flags);
+ }
+
+ @Override
+ public boolean equals(GlyphVector glyphVector) {
+ return false;
+ }
+
+ public char[] getGlyphs() {
+ return this.charVector;
+ }
+
+ @Override
+ public Font getFont() {
+ return this.font;
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return this.vectorFRC;
+ }
+
+ @Override
+ public int getGlyphCode(int glyphIndex) {
+ return charVector[glyphIndex];
+ }
+
+ @Override
+ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Shape getGlyphLogicalBounds(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public GlyphMetrics getGlyphMetrics(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ public Path getAndroidGlyphOutline(int glyphIndex) {
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ Path path = new Path();
+ char tmp[] = new char[1];
+ tmp[0] = charVector[glyphIndex];
+ ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(tmp), 0, 1, 0, 0, path);
+ return path;
+ }
+
+ @Override
+ public Shape getGlyphOutline(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Point2D getGlyphPosition(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] positionReturn) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public AffineTransform getGlyphTransform(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Shape getGlyphVisualBounds(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Rectangle2D getLogicalBounds() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public int getNumGlyphs() {
+ return charVector.length;
+ }
+
+ @Override
+ public Shape getOutline(float x, float y) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Shape getOutline() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ public Path getAndroidOutline() {
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ Path path = new Path();
+ ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(charVector), 0, charVector.length, 0, 0, path);
+ return path;
+ }
+
+ @Override
+ public Rectangle2D getVisualBounds() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void performDefaultLayout() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java b/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
new file mode 100644
index 0000000..f37be6d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.FontRenderContext;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+
+
+/**
+ *
+ * Linux implementation of LineMetrics class
+ */
+public class AndroidLineMetrics extends LineMetricsImpl {
+
+ /**
+ * Constructor
+ */
+ public AndroidLineMetrics( AndroidFont fnt,
+ FontRenderContext frc,
+ String str){
+ numChars = str.length();
+ baseLineIndex = 0;
+
+ ascent = fnt.ascent; // Ascent of the font
+ descent = -fnt.descent; // Descent of the font
+ leading = fnt.leading; // External leading
+
+ height = ascent + descent + leading; // Height of the font ( == (ascent + descent + leading))
+ underlineThickness = 0.0f;
+ underlineOffset = 0.0f;
+ strikethroughThickness = 0.0f;
+ strikethroughOffset = 0.0f;
+ maxCharWidth = 0.0f;
+
+ // TODO: Find out pixel metrics
+ /*
+ * positive metrics rounded to the smallest int that is bigger than value
+ * negative metrics rounded to the smallest int that is lesser than value
+ * thicknesses rounded to int ((int)round(value + 0.5))
+ *
+ */
+
+ lAscent = (int)Math.ceil(fnt.ascent);// // Ascent of the font
+ lDescent = -(int)Math.ceil(fnt.descent);// Descent of the font
+ lLeading = (int)Math.ceil(leading); // External leading
+
+ lHeight = lAscent + lDescent + lLeading; // Height of the font ( == (ascent + descent + leading))
+
+ lUnderlineThickness = Math.round(underlineThickness);//(int)metrics[11];
+
+ if (underlineOffset >= 0){
+ lUnderlineOffset = (int)Math.ceil(underlineOffset);
+ } else {
+ lUnderlineOffset = (int)Math.floor(underlineOffset);
+ }
+
+ lStrikethroughThickness = Math.round(strikethroughThickness); //(int)metrics[13];
+
+ if (strikethroughOffset >= 0){
+ lStrikethroughOffset = (int)Math.ceil(strikethroughOffset);
+ } else {
+ lStrikethroughOffset = (int)Math.floor(strikethroughOffset);
+ }
+
+ lMaxCharWidth = (int)Math.ceil(maxCharWidth); //(int)metrics[15];
+ units_per_EM = 0;
+
+ }
+
+ public float[] getBaselineOffsets() {
+ // TODO: implement baseline offsets for TrueType fonts
+ if (baselineOffsets == null){
+ float[] baselineData = null;
+
+ // Temporary workaround:
+ // Commented out native data initialization, since it can
+ // cause failures with opening files in multithreaded applications.
+ //
+ // TODO: support work with truetype data in multithreaded
+ // applications.
+
+ // If font TrueType data is taken from BASE table
+// if ((this.font.getFontHandle() != 0) && (font.getFontType() == FontManager.FONT_TYPE_TT)){
+// baselineData = LinuxNativeFont.getBaselineOffsetsNative(font.getFontHandle(), font.getSize(), ascent, descent, units_per_EM);
+// }
+//
+ baseLineIndex = 0;
+ baselineOffsets = new float[]{0, (-ascent+descent)/2, -ascent};
+ }
+
+ return baselineOffsets;
+ }
+
+ public int getBaselineIndex() {
+ if (baselineOffsets == null){
+ // get offsets and set correct index
+ getBaselineOffsets();
+ }
+ return baseLineIndex;
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java b/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
new file mode 100644
index 0000000..c0fb390
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.*;
+
+/**
+ * Date: May 14, 2005
+ * Time: 7:44:13 PM
+ *
+ * This class incapsulates text metrics specific for the text layout or
+ * for the separate text segment. Text segment is a text run with the constant direction
+ * and attributes like font, decorations, etc. BasicMetrics is also used to store
+ * calculated text metrics like advance, ascent or descent. this class is very similar to
+ * LineMetrics, but provides some additional info, constructors and is more transparent.
+ */
+public class BasicMetrics {
+ int baseLineIndex;
+
+ float ascent; // Ascent of the font
+ float descent; // Descent of the font
+ float leading; // External leading
+ float advance;
+
+ float italicAngle;
+ float superScriptOffset;
+
+ float underlineOffset;
+ float underlineThickness;
+
+ float strikethroughOffset;
+ float strikethroughThickness;
+
+ /**
+ * Constructs BasicMetrics from LineMetrics and font
+ * @param lm
+ * @param font
+ */
+ BasicMetrics(LineMetrics lm, Font font) {
+ ascent = lm.getAscent();
+ descent = lm.getDescent();
+ leading = lm.getLeading();
+
+ underlineOffset = lm.getUnderlineOffset();
+ underlineThickness = lm.getUnderlineThickness();
+
+ strikethroughOffset = lm.getStrikethroughOffset();
+ strikethroughThickness = lm.getStrikethroughThickness();
+
+ baseLineIndex = lm.getBaselineIndex();
+
+ italicAngle = font.getItalicAngle();
+ superScriptOffset = (float) font.getTransform().getTranslateY();
+ }
+
+ /**
+ * Constructs BasicMetrics from GraphicAttribute.
+ * It gets ascent and descent from the graphic attribute and
+ * computes reasonable defaults for other metrics.
+ * @param ga - graphic attribute
+ */
+ BasicMetrics(GraphicAttribute ga) {
+ ascent = ga.getAscent();
+ descent = ga.getDescent();
+ leading = 2;
+
+ baseLineIndex = ga.getAlignment();
+
+ italicAngle = 0;
+ superScriptOffset = 0;
+
+ underlineOffset = Math.max(descent/2, 1);
+
+ // Just suggested, should be cap_stem_width or something like that
+ underlineThickness = Math.max(ascent/13, 1);
+
+ strikethroughOffset = -ascent/2; // Something like middle of the line
+ strikethroughThickness = underlineThickness;
+ }
+
+ /**
+ * Copies metrics from the TextMetricsCalculator object.
+ * @param tmc - TextMetricsCalculator object
+ */
+ BasicMetrics(TextMetricsCalculator tmc) {
+ ascent = tmc.ascent;
+ descent = tmc.descent;
+ leading = tmc.leading;
+ advance = tmc.advance;
+ baseLineIndex = tmc.baselineIndex;
+ }
+
+ public float getAscent() {
+ return ascent;
+ }
+
+ public float getDescent() {
+ return descent;
+ }
+
+ public float getLeading() {
+ return leading;
+ }
+
+ public float getAdvance() {
+ return advance;
+ }
+
+ public int getBaseLineIndex() {
+ return baseLineIndex;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/CaretManager.java b/awt/org/apache/harmony/awt/gl/font/CaretManager.java
new file mode 100644
index 0000000..b18bdd5
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CaretManager.java
@@ -0,0 +1,530 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jun 14, 2005
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.TextHitInfo;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.*;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class provides functionality for creating caret and highlight shapes
+ * (bidirectional text is also supported, but, unfortunately, not tested yet).
+ */
+public class CaretManager {
+ private TextRunBreaker breaker;
+
+ public CaretManager(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ }
+
+ /**
+ * Checks if TextHitInfo is not out of the text range and throws the
+ * IllegalArgumentException if it is.
+ * @param info - text hit info
+ */
+ private void checkHit(TextHitInfo info) {
+ int idx = info.getInsertionIndex();
+
+ if (idx < 0 || idx > breaker.getCharCount()) {
+ // awt.42=TextHitInfo out of range
+ throw new IllegalArgumentException(Messages.getString("awt.42")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Calculates and returns visual position from the text hit info.
+ * @param hitInfo - text hit info
+ * @return visual index
+ */
+ private int getVisualFromHitInfo(TextHitInfo hitInfo) {
+ final int idx = hitInfo.getCharIndex();
+
+ if (idx >= 0 && idx < breaker.getCharCount()) {
+ int visual = breaker.getVisualFromLogical(idx);
+ // We take next character for (LTR char + TRAILING info) and (RTL + LEADING)
+ if (hitInfo.isLeadingEdge() ^ ((breaker.getLevel(idx) & 0x1) == 0x0)) {
+ visual++;
+ }
+ return visual;
+ } else if (idx < 0) {
+ return breaker.isLTR() ? 0: breaker.getCharCount();
+ } else {
+ return breaker.isLTR() ? breaker.getCharCount() : 0;
+ }
+ }
+
+ /**
+ * Calculates text hit info from the visual position
+ * @param visual - visual position
+ * @return text hit info
+ */
+ private TextHitInfo getHitInfoFromVisual(int visual) {
+ final boolean first = visual == 0;
+
+ if (!(first || visual == breaker.getCharCount())) {
+ int logical = breaker.getLogicalFromVisual(visual);
+ return (breaker.getLevel(logical) & 0x1) == 0x0 ?
+ TextHitInfo.leading(logical) : // LTR
+ TextHitInfo.trailing(logical); // RTL
+ } else if (first) {
+ return breaker.isLTR() ?
+ TextHitInfo.trailing(-1) :
+ TextHitInfo.leading(breaker.getCharCount());
+ } else { // Last
+ return breaker.isLTR() ?
+ TextHitInfo.leading(breaker.getCharCount()) :
+ TextHitInfo.trailing(-1);
+ }
+ }
+
+ /**
+ * Creates caret info. Required for the getCaretInfo
+ * methods of the TextLayout
+ * @param hitInfo - specifies caret position
+ * @return caret info, see TextLayout.getCaretInfo documentation
+ */
+ public float[] getCaretInfo(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+ float res[] = new float[2];
+
+ int visual = getVisualFromHitInfo(hitInfo);
+ float advance, angle;
+ TextRunSegment seg;
+
+ if (visual < breaker.getCharCount()) {
+ int logIdx = breaker.getLogicalFromVisual(visual);
+ int segmentIdx = breaker.logical2segment[logIdx];
+ seg = breaker.runSegments.get(segmentIdx);
+ advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx);
+ angle = seg.metrics.italicAngle;
+
+ } else { // Last character
+ int logIdx = breaker.getLogicalFromVisual(visual-1);
+ int segmentIdx = breaker.logical2segment[logIdx];
+ seg = breaker.runSegments.get(segmentIdx);
+ advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx+1);
+ }
+
+ angle = seg.metrics.italicAngle;
+
+ res[0] = advance;
+ res[1] = angle;
+
+ return res;
+ }
+
+ /**
+ * Returns the next position to the right from the current caret position
+ * @param hitInfo - current position
+ * @return next position to the right
+ */
+ public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+ int visual = getVisualFromHitInfo(hitInfo);
+
+ if (visual == breaker.getCharCount()) {
+ return null;
+ }
+
+ TextHitInfo newInfo;
+
+ while(visual <= breaker.getCharCount()) {
+ visual++;
+ newInfo = getHitInfoFromVisual(visual);
+
+ if (newInfo.getCharIndex() >= breaker.logical2segment.length) {
+ return newInfo;
+ }
+
+ if (hitInfo.getCharIndex() >= 0) { // Don't check for leftmost info
+ if (
+ breaker.logical2segment[newInfo.getCharIndex()] !=
+ breaker.logical2segment[hitInfo.getCharIndex()]
+ ) {
+ return newInfo; // We crossed segment boundary
+ }
+ }
+
+ TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo
+ .getCharIndex()]);
+ if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
+ return newInfo;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the next position to the left from the current caret position
+ * @param hitInfo - current position
+ * @return next position to the left
+ */
+ public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+ int visual = getVisualFromHitInfo(hitInfo);
+
+ if (visual == 0) {
+ return null;
+ }
+
+ TextHitInfo newInfo;
+
+ while(visual >= 0) {
+ visual--;
+ newInfo = getHitInfoFromVisual(visual);
+
+ if (newInfo.getCharIndex() < 0) {
+ return newInfo;
+ }
+
+ // Don't check for rightmost info
+ if (hitInfo.getCharIndex() < breaker.logical2segment.length) {
+ if (
+ breaker.logical2segment[newInfo.getCharIndex()] !=
+ breaker.logical2segment[hitInfo.getCharIndex()]
+ ) {
+ return newInfo; // We crossed segment boundary
+ }
+ }
+
+ TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo
+ .getCharIndex()]);
+ if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
+ return newInfo;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * For each visual caret position there are two hits. For the simple LTR text one is
+ * a trailing of the previous char and another is the leading of the next char. This
+ * method returns the opposite hit for the given hit.
+ * @param hitInfo - given hit
+ * @return opposite hit
+ */
+ public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+
+ int idx = hitInfo.getCharIndex();
+
+ int resIdx;
+ boolean resIsLeading;
+
+ if (idx >= 0 && idx < breaker.getCharCount()) { // Hit info in the middle
+ int visual = breaker.getVisualFromLogical(idx);
+
+ // Char is LTR + LEADING info
+ if (((breaker.getLevel(idx) & 0x1) == 0x0) ^ hitInfo.isLeadingEdge()) {
+ visual++;
+ if (visual == breaker.getCharCount()) {
+ if (breaker.isLTR()) {
+ resIdx = breaker.getCharCount();
+ resIsLeading = true;
+ } else {
+ resIdx = -1;
+ resIsLeading = false;
+ }
+ } else {
+ resIdx = breaker.getLogicalFromVisual(visual);
+ if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
+ resIsLeading = true;
+ } else {
+ resIsLeading = false;
+ }
+ }
+ } else {
+ visual--;
+ if (visual == -1) {
+ if (breaker.isLTR()) {
+ resIdx = -1;
+ resIsLeading = false;
+ } else {
+ resIdx = breaker.getCharCount();
+ resIsLeading = true;
+ }
+ } else {
+ resIdx = breaker.getLogicalFromVisual(visual);
+ if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
+ resIsLeading = false;
+ } else {
+ resIsLeading = true;
+ }
+ }
+ }
+ } else if (idx < 0) { // before "start"
+ if (breaker.isLTR()) {
+ resIdx = breaker.getLogicalFromVisual(0);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // LTR char?
+ } else {
+ resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // RTL char?
+ }
+ } else { // idx == breaker.getCharCount()
+ if (breaker.isLTR()) {
+ resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // LTR char?
+ } else {
+ resIdx = breaker.getLogicalFromVisual(0);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // RTL char?
+ }
+ }
+
+ return resIsLeading ? TextHitInfo.leading(resIdx) : TextHitInfo.trailing(resIdx);
+ }
+
+ public Line2D getCaretShape(TextHitInfo hitInfo, TextLayout layout) {
+ return getCaretShape(hitInfo, layout, true, false, null);
+ }
+
+ /**
+ * Creates a caret shape.
+ * @param hitInfo - hit where to place a caret
+ * @param layout - text layout
+ * @param useItalic - unused for now, was used to create
+ * slanted carets for italic text
+ * @param useBounds - true if the cared should fit into the provided bounds
+ * @param bounds - bounds for the caret
+ * @return caret shape
+ */
+ public Line2D getCaretShape(
+ TextHitInfo hitInfo, TextLayout layout,
+ boolean useItalic, boolean useBounds, Rectangle2D bounds
+ ) {
+ checkHit(hitInfo);
+
+ float x1, x2, y1, y2;
+
+ int charIdx = hitInfo.getCharIndex();
+
+ if (charIdx >= 0 && charIdx < breaker.getCharCount()) {
+ TextRunSegment segment = breaker.runSegments.get(breaker.logical2segment[charIdx]);
+ y1 = segment.metrics.descent;
+ y2 = - segment.metrics.ascent - segment.metrics.leading;
+
+ x1 = x2 = segment.getCharPosition(charIdx) + (hitInfo.isLeadingEdge() ?
+ 0 : segment.getCharAdvance(charIdx));
+ // Decided that straight cursor looks better even for italic fonts,
+ // especially combined with highlighting
+ /*
+ // Not graphics, need to check italic angle and baseline
+ if (layout.getBaseline() >= 0) {
+ if (segment.metrics.italicAngle != 0 && useItalic) {
+ x1 -= segment.metrics.italicAngle * segment.metrics.descent;
+ x2 += segment.metrics.italicAngle *
+ (segment.metrics.ascent + segment.metrics.leading);
+
+ float baselineOffset =
+ layout.getBaselineOffsets()[layout.getBaseline()];
+ y1 += baselineOffset;
+ y2 += baselineOffset;
+ }
+ }
+ */
+ } else {
+ y1 = layout.getDescent();
+ y2 = - layout.getAscent() - layout.getLeading();
+ x1 = x2 = ((breaker.getBaseLevel() & 0x1) == 0 ^ charIdx < 0) ?
+ layout.getAdvance() : 0;
+ }
+
+ if (useBounds) {
+ y1 = (float) bounds.getMaxY();
+ y2 = (float) bounds.getMinY();
+
+ if (x2 > bounds.getMaxX()) {
+ x1 = x2 = (float) bounds.getMaxX();
+ }
+ if (x1 < bounds.getMinX()) {
+ x1 = x2 = (float) bounds.getMinX();
+ }
+ }
+
+ return new Line2D.Float(x1, y1, x2, y2);
+ }
+
+ /**
+ * Creates caret shapes for the specified offset. On the boundaries where
+ * the text is changing its direction this method may return two shapes
+ * for the strong and the weak carets, in other cases it would return one.
+ * @param offset - offset in the text.
+ * @param bounds - bounds to fit the carets into
+ * @param policy - caret policy
+ * @param layout - text layout
+ * @return one or two caret shapes
+ */
+ public Shape[] getCaretShapes(
+ int offset, Rectangle2D bounds,
+ TextLayout.CaretPolicy policy, TextLayout layout
+ ) {
+ TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
+ TextHitInfo hit2 = getVisualOtherHit(hit1);
+
+ Shape caret1 = getCaretShape(hit1, layout);
+
+ if (getVisualFromHitInfo(hit1) == getVisualFromHitInfo(hit2)) {
+ return new Shape[] {caret1, null};
+ }
+ Shape caret2 = getCaretShape(hit2, layout);
+
+ TextHitInfo strongHit = policy.getStrongCaret(hit1, hit2, layout);
+ return strongHit.equals(hit1) ?
+ new Shape[] {caret1, caret2} :
+ new Shape[] {caret2, caret1};
+ }
+
+ /**
+ * Connects two carets to produce a highlight shape.
+ * @param caret1 - 1st caret
+ * @param caret2 - 2nd caret
+ * @return highlight shape
+ */
+ GeneralPath connectCarets(Line2D caret1, Line2D caret2) {
+ GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+ path.moveTo((float) caret1.getX1(), (float) caret1.getY1());
+ path.lineTo((float) caret2.getX1(), (float) caret2.getY1());
+ path.lineTo((float) caret2.getX2(), (float) caret2.getY2());
+ path.lineTo((float) caret1.getX2(), (float) caret1.getY2());
+
+ path.closePath();
+
+ return path;
+ }
+
+ /**
+ * Creates a highlight shape from given two hits. This shape
+ * will always be visually contiguous
+ * @param hit1 - 1st hit
+ * @param hit2 - 2nd hit
+ * @param bounds - bounds to fit the shape into
+ * @param layout - text layout
+ * @return highlight shape
+ */
+ public Shape getVisualHighlightShape(
+ TextHitInfo hit1, TextHitInfo hit2,
+ Rectangle2D bounds, TextLayout layout
+ ) {
+ checkHit(hit1);
+ checkHit(hit2);
+
+ Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
+ Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
+
+ return connectCarets(caret1, caret2);
+ }
+
+ /**
+ * Suppose that the user visually selected a block of text which has
+ * several different levels (mixed RTL and LTR), so, in the logical
+ * representation of the text this selection may be not contigous.
+ * This methods returns a set of logical ranges for the arbitrary
+ * visual selection represented by two hits.
+ * @param hit1 - 1st hit
+ * @param hit2 - 2nd hit
+ * @return logical ranges for the selection
+ */
+ public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) {
+ checkHit(hit1);
+ checkHit(hit2);
+
+ int visual1 = getVisualFromHitInfo(hit1);
+ int visual2 = getVisualFromHitInfo(hit2);
+
+ if (visual1 > visual2) {
+ int tmp = visual2;
+ visual2 = visual1;
+ visual1 = tmp;
+ }
+
+ // Max level is 255, so we don't need more than 512 entries
+ int results[] = new int[512];
+
+ int prevLogical, logical, runStart, numRuns = 0;
+
+ logical = runStart = prevLogical = breaker.getLogicalFromVisual(visual1);
+
+ // Get all the runs. We use the fact that direction is constant in all runs.
+ for (int i=visual1+1; i<=visual2; i++) {
+ logical = breaker.getLogicalFromVisual(i);
+ int diff = logical-prevLogical;
+
+ // Start of the next run encountered
+ if (diff > 1 || diff < -1) {
+ results[(numRuns)*2] = Math.min(runStart, prevLogical);
+ results[(numRuns)*2 + 1] = Math.max(runStart, prevLogical);
+ numRuns++;
+ runStart = logical;
+ }
+
+ prevLogical = logical;
+ }
+
+ // The last unsaved run
+ results[(numRuns)*2] = Math.min(runStart, logical);
+ results[(numRuns)*2 + 1] = Math.max(runStart, logical);
+ numRuns++;
+
+ int retval[] = new int[numRuns*2];
+ System.arraycopy(results, 0, retval, 0, numRuns*2);
+ return retval;
+ }
+
+ /**
+ * Creates a highlight shape from given two endpoints in the logical
+ * representation. This shape is not always visually contiguous
+ * @param firstEndpoint - 1st logical endpoint
+ * @param secondEndpoint - 2nd logical endpoint
+ * @param bounds - bounds to fit the shape into
+ * @param layout - text layout
+ * @return highlight shape
+ */
+ public Shape getLogicalHighlightShape(
+ int firstEndpoint, int secondEndpoint,
+ Rectangle2D bounds, TextLayout layout
+ ) {
+ GeneralPath res = new GeneralPath();
+
+ for (int i=firstEndpoint; i<=secondEndpoint; i++) {
+ int endRun = breaker.getLevelRunLimit(i, secondEndpoint);
+ TextHitInfo hit1 = TextHitInfo.leading(i);
+ TextHitInfo hit2 = TextHitInfo.trailing(endRun-1);
+
+ Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
+ Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
+
+ res.append(connectCarets(caret1, caret2), false);
+
+ i = endRun;
+ }
+
+ return res;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java b/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
new file mode 100644
index 0000000..4040a60
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
@@ -0,0 +1,954 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+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.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * GlyphVector implementation
+ */
+public class CommonGlyphVector extends GlyphVector {
+
+ // array of transforms of glyphs in GlyphVector
+ protected AffineTransform[] glsTransforms;
+
+ // array of chars defined in constructor
+ public char[] charVector;
+
+ // array of Glyph objects, that describe information about glyphs
+ public Glyph[] vector;
+
+ // array of default positions of glyphs in GlyphVector
+ // without applying GlyphVector's transform
+ float[] defaultPositions;
+
+ // array of logical positions of glyphs in GlyphVector
+
+ float[] logicalPositions;
+
+ // array of visual (real) positions of glyphs in GlyphVector
+ public float[] visualPositions;
+
+ // FontRenderContext for this vector.
+ protected FontRenderContext vectorFRC;
+
+ // layout flags mask
+ protected int layoutFlags = 0;
+
+ // array of cached glyph outlines
+ protected Shape[] gvShapes;
+
+ FontPeerImpl peer;
+
+ // font corresponding to the GlyphVector
+ Font font;
+
+ // ascent of the font
+ float ascent;
+
+ // height of the font
+ float height;
+
+ // leading of the font
+ float leading;
+
+ // descent of the font
+ float descent;
+
+ // transform of the GlyphVector
+ AffineTransform transform;
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ *
+ * @param chars an array of chars
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ * @param flags layout flags
+ */
+ @SuppressWarnings("deprecation")
+ public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt,
+ int flags) {
+ int len = chars.length;
+
+ this.font = fnt;
+ this.transform = fnt.getTransform();
+ this.peer = (FontPeerImpl) fnt.getPeer();
+
+ gvShapes = new Shape[len];
+
+ // !! As pointed in API documentation for the
+ // getGlyphPosisitions(int index,int numEntries, float[] positionReturn)
+ // and getGlyphPosition(int index) methods, if the index is equals to
+ // the number of glyphs the position after the last glyph must be
+ // returned, thus there are n+1 positions and last (n+1) position
+ // points to the end of GlyphVector.
+
+ logicalPositions = new float[(len+1)<<1];
+ visualPositions = new float[(len+1)<<1];
+ defaultPositions = new float[(len+1)<<1];
+
+ glsTransforms = new AffineTransform[len];
+
+ this.charVector = chars;
+ this.vectorFRC = frc;
+ //LineMetricsImpl lmImpl = (LineMetricsImpl)peer.getLineMetrics();
+
+ LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc);
+
+ this.ascent = lmImpl.getAscent();
+ this.height = lmImpl.getHeight();
+ this.leading = lmImpl.getLeading();
+ this.descent = lmImpl.getDescent();
+ this.layoutFlags = flags;
+
+ if ((flags & Font.LAYOUT_RIGHT_TO_LEFT) != 0){
+ char vector[] = new char[len];
+ for(int i=0; i < len; i++){
+ vector[i] = chars[len-i-1];
+ }
+ this.vector = peer.getGlyphs(vector);
+
+ } else {
+ this.vector = peer.getGlyphs(chars);
+ }
+
+ this.glsTransforms = new AffineTransform[len];
+
+ setDefaultPositions();
+ performDefaultLayout();
+ }
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ * Layout flags set to default.
+ *
+ * @param chars an array of chars
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ */
+ public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt) {
+ this(chars, frc, fnt, 0);
+ }
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ * Layout flags set to default.
+ *
+ * @param str specified string
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ */
+ public CommonGlyphVector(String str, FontRenderContext frc, Font fnt) {
+ this(str.toCharArray(), frc, fnt, 0);
+ }
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ *
+ * @param str specified string
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ * @param flags layout flags
+ */
+ public CommonGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) {
+ this(str.toCharArray(), frc, fnt, flags);
+ }
+
+ /**
+ * Set array of logical positions of the glyphs to
+ * default with their default advances and height.
+ */
+ void setDefaultPositions(){
+ int len = getNumGlyphs();
+
+ // First [x,y] is set into [0,0] position
+ // for this reason start index is 1
+ for (int i=1; i <= len; i++ ){
+ int idx = i << 1;
+ float advanceX = vector[i-1].getGlyphPointMetrics().getAdvanceX();
+ float advanceY = vector[i-1].getGlyphPointMetrics().getAdvanceY();
+
+ defaultPositions[idx] = defaultPositions[idx-2] + advanceX;
+ defaultPositions[idx+1] = defaultPositions[idx-1] + advanceY;
+
+ }
+ transform.transform(defaultPositions, 0, logicalPositions, 0, getNumGlyphs()+1);
+
+ }
+
+ /**
+ * Returnes the pixel bounds of this GlyphVector rendered at the
+ * specified x,y location with the given FontRenderContext.
+ *
+ * @param frc a FontRenderContext that is used
+ * @param x specified x coordinate value
+ * @param y specified y coordinate value
+ * @return a Rectangle that bounds pixels of this GlyphVector
+ */
+ @Override
+ public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {
+
+ double xM, yM, xm, ym;
+
+ double minX = 0;
+ double minY = 0;
+ double maxX = 0;
+ double maxY = 0;
+
+ for (int i = 0; i < this.getNumGlyphs(); i++) {
+ Rectangle glyphBounds = this.getGlyphPixelBounds(i, frc, 0, 0);
+ xm = glyphBounds.getMinX();
+ ym = glyphBounds.getMinY();
+ xM = glyphBounds.getMaxX();
+ yM = glyphBounds.getMaxY();
+
+ if (i == 0) {
+ minX = xm;
+ minY = ym;
+ maxX = xM;
+ maxY = yM;
+ }
+
+ if (minX > xm) {
+ minX = xm;
+ }
+ if (minY > ym) {
+ minY = ym;
+ }
+ if (maxX < xM) {
+ maxX = xM;
+ }
+ if (maxY < yM) {
+ maxY = yM;
+ }
+ }
+ return new Rectangle((int)(minX + x), (int)(minY + y), (int)(maxX - minX), (int)(maxY - minY));
+
+ }
+
+ /**
+ * Returns the visual bounds of this GlyphVector.
+ * The visual bounds is the bounds of the total outline of
+ * this GlyphVector.
+ * @return a Rectangle2D that id the visual bounds of this GlyphVector
+ */
+ @Override
+ public Rectangle2D getVisualBounds() {
+ float xM, yM, xm, ym;
+ float minX = 0;
+ float minY = 0;
+ float maxX = 0;
+ float maxY = 0;
+ boolean firstIteration = true;
+
+ for (int i = 0; i < this.getNumGlyphs(); i++) {
+ Rectangle2D bounds = this.getGlyphVisualBounds(i).getBounds2D();
+ if (bounds.getWidth() == 0){
+ continue;
+ }
+ xm = (float)bounds.getX();
+ ym = (float)bounds.getY();
+
+ xM = (float)(xm + bounds.getWidth());
+
+ yM = ym + (float) bounds.getHeight();
+
+ if (firstIteration) {
+ minX = xm;
+ minY = ym;
+ maxX = xM;
+ maxY = yM;
+ firstIteration = false;
+ } else {
+ if (minX > xm) {
+ minX = xm;
+ }
+ if (minY > ym) {
+ minY = ym;
+ }
+ if (maxX < xM) {
+ maxX = xM;
+ }
+ if (maxY < yM) {
+ maxY = yM;
+ }
+
+ }
+ }
+
+ return (this.getNumGlyphs() != 0) ? new Rectangle2D.Float(minX, minY,
+ (maxX - minX), (maxY - minY)) : null;
+ }
+
+ /**
+ * Sets new position to the specified glyph.
+ */
+ @Override
+ public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+ if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ float x = (float)newPos.getX();
+ float y = (float)newPos.getY();
+ int index = glyphIndex << 1;
+
+ if ((x != visualPositions[index]) || (y != visualPositions[index + 1])){
+ visualPositions[index] = x;
+ visualPositions[index+1] = y;
+ layoutFlags = layoutFlags | FLAG_HAS_POSITION_ADJUSTMENTS;
+ }
+
+ }
+
+ /**
+ * Returns the position of the specified glyph relative to the origin of
+ * this GlyphVector
+ * @return a Point2D that the origin of the glyph with specified index
+ */
+ @Override
+ public Point2D getGlyphPosition(int glyphIndex) {
+ if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ int index = glyphIndex << 1;
+ Point2D pos = new Point2D.Float(visualPositions[index], visualPositions[index+1]);
+
+ // For last position we don't have to transform !!
+ if(glyphIndex==vector.length){
+ return pos;
+ }
+
+ AffineTransform at = getGlyphTransform(glyphIndex);
+ if ((at == null) || (at.isIdentity())){
+ return pos;
+ }
+
+ pos.setLocation(pos.getX() + at.getTranslateX(), pos.getY() + at.getTranslateY());
+
+ return pos;
+ }
+
+ /**
+ * Sets new transform to the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ * @param trans AffineTransform of the glyph with specified index
+ */
+ @Override
+ public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
+ if ((glyphIndex >= vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ if ((trans == null) || (trans.isIdentity())) {
+ glsTransforms[glyphIndex] = null;
+ } else {
+ glsTransforms[glyphIndex] = new AffineTransform(trans);
+ layoutFlags = layoutFlags | FLAG_HAS_TRANSFORMS;
+ }
+ }
+
+ /**
+ * Returns the affine transform of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ * @return an AffineTransform of the glyph with specified index
+ */
+ @Override
+ public AffineTransform getGlyphTransform(int glyphIndex) {
+ if ((glyphIndex >= this.vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ return this.glsTransforms[glyphIndex];
+ }
+
+ /**
+ * Returns the metrics of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public GlyphMetrics getGlyphMetrics(int glyphIndex) {
+
+ if ((glyphIndex < 0) || ((glyphIndex) >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ // TODO: is there a sence in GlyphMetrics
+ // if certain glyph or Font has a transform??
+ return this.vector[glyphIndex].getGlyphMetrics();
+ }
+
+ /**
+ * Returns a justification information for the glyph with specified glyph
+ * index.
+ * @param glyphIndex index of a glyph which GlyphJustificationInfo is to be
+ * received
+ * @return a GlyphJustificationInfo object that contains glyph justification
+ * properties of the specified glyph
+ */
+ @Override
+ public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+ // TODO : Find out the source of Justification info
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Returns the FontRenderContext parameter of this GlyphVector.
+ */
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return this.vectorFRC;
+ }
+
+ /**
+ * Returns the visual bounds of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public Shape getGlyphVisualBounds(int glyphIndex) {
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ int idx = glyphIndex << 1;
+
+ AffineTransform fontTransform = this.transform;
+ double xOffs = fontTransform.getTranslateX();
+ double yOffs = fontTransform.getTranslateY();
+
+ if (vector[glyphIndex].getWidth() == 0){
+ return new Rectangle2D.Float((float)xOffs, (float)yOffs, 0, 0);
+ }
+
+ AffineTransform at = AffineTransform.getTranslateInstance(xOffs, yOffs);
+ AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+
+ if (transform.isIdentity() && ((glyphTransform == null) || glyphTransform.isIdentity())){
+ Rectangle2D blackBox = vector[glyphIndex].getGlyphMetrics().getBounds2D();
+ at.translate(visualPositions[idx], visualPositions[idx+1]);
+ return(at.createTransformedShape(blackBox));
+ }
+
+ GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex);
+ shape.transform(at);
+ return shape.getBounds2D();
+ }
+
+ /**
+ * Returnes the pixel bounds of the specified glyph within GlyphVector
+ * rendered at the specified x,y location.
+ *
+ * @param glyphIndex index of the glyph
+ * @param frc a FontRenderContext that is used
+ * @param x specified x coordinate value
+ * @param y specified y coordinate value
+ * @return a Rectangle that bounds pixels of the specified glyph
+ */
+ @Override
+ public Rectangle getGlyphPixelBounds(int glyphIndex, FontRenderContext frc,
+ float x, float y) {
+ // TODO : need to be implemented with FontRenderContext
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ int idx = glyphIndex << 1;
+
+ if (vector[glyphIndex].getWidth() == 0){
+ AffineTransform fontTransform = this.transform;
+ double xOffs = x + visualPositions[idx] + fontTransform.getTranslateX();
+ double yOffs = y + visualPositions[idx+1] + fontTransform.getTranslateY();
+ return new Rectangle((int)xOffs, (int)yOffs, 0, 0);
+ }
+
+ GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex);
+
+ AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+
+ if (frc != null){
+ at.concatenate(frc.getTransform());
+ }
+
+ shape.transform(at);
+
+ Rectangle bounds = shape.getBounds();
+ return new Rectangle((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth()-1, (int)bounds.getHeight()-1);
+ }
+
+ /**
+ * Returns a Shape that encloses specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public Shape getGlyphOutline(int glyphIndex) {
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ if (gvShapes[glyphIndex] == null) {
+ gvShapes[glyphIndex] = vector[glyphIndex].getShape();
+ }
+
+ GeneralPath gp = (GeneralPath)((GeneralPath)gvShapes[glyphIndex]).clone();
+
+ /* Applying GlyphVector font transform */
+ AffineTransform at = (AffineTransform)this.transform.clone();
+
+ /* Applying Glyph transform */
+ AffineTransform glyphAT = getGlyphTransform(glyphIndex);
+ if (glyphAT != null){
+ at.preConcatenate(glyphAT);
+ }
+
+ int idx = glyphIndex << 1;
+
+ gp.transform(at);
+ gp.transform(AffineTransform.getTranslateInstance(visualPositions[idx], visualPositions[idx+1]));
+ return gp;
+ }
+
+
+ /**
+ * Returns a Shape that is the outline representation of this GlyphVector
+ * rendered at the specified x,y coordinates.
+ *
+ * @param x specified x coordinate value
+ * @param y specified y coordinate value
+ * @return a Shape object that is the outline of this GlyphVector
+ * at the specified coordinates.
+ */
+ @Override
+ public Shape getOutline(float x, float y) {
+ GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+ for (int i = 0; i < this.vector.length; i++) {
+ GeneralPath outline = (GeneralPath)getGlyphOutline(i);
+
+ /* Applying translation to actual visual bounds */
+ outline.transform(AffineTransform.getTranslateInstance(x, y));
+ gp.append(outline, false);
+ }
+
+ return gp;
+ }
+
+ /**
+ * Returns a Shape that is the outline representation of this GlyphVector.
+ *
+ * @return a Shape object that is the outline of this GlyphVector
+ */
+ @Override
+ public Shape getOutline() {
+ return this.getOutline(0, 0);
+ }
+
+ /**
+ * Returns an array of glyphcodes for the specified glyphs.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param codeReturn the array that receives glyph codes' values
+ * @return an array that receives glyph codes' values
+ */
+ @Override
+ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+
+ if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if (numEntries < 0) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+
+ for (int i = beginGlyphIndex; i < beginGlyphIndex + numEntries; i++) {
+ codeReturn[i-beginGlyphIndex] = this.vector[i].getGlyphCode();
+ }
+
+ return codeReturn;
+ }
+
+ /**
+ * Returns an array of numEntries character indices for the specified glyphs.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param codeReturn the array that receives glyph codes' values
+ * @return an array that receives glyph char indices
+ */
+ @Override
+ public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ if ((beginGlyphIndex < 0) || (beginGlyphIndex >= this.getNumGlyphs())) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if ((numEntries < 0)
+ || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+
+ for (int i = 0; i < numEntries; i++) {
+ codeReturn[i] = this.getGlyphCharIndex(i + beginGlyphIndex);
+ }
+ return codeReturn;
+ }
+
+ /**
+ * Returns an array of numEntries glyphs positions from beginGlyphIndex
+ * glyph in Glyph Vector.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param positionReturn the array that receives glyphs' positions
+ * @return an array of floats that receives glyph char indices
+ */
+ @Override
+ public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] positionReturn) {
+
+ int len = (this.getNumGlyphs()+1) << 1;
+ beginGlyphIndex *= 2;
+ numEntries *= 2;
+
+ if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if (numEntries < 0) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ if (positionReturn == null) {
+ positionReturn = new float[numEntries];
+ }
+
+ System.arraycopy(visualPositions, beginGlyphIndex, positionReturn, 0, numEntries);
+
+ return positionReturn;
+ }
+
+ /**
+ * Set numEntries elements of the visualPositions array from beginGlyphIndex
+ * of numEntries glyphs positions from beginGlyphIndex glyph in Glyph Vector.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param setPositions the array of positions to set
+ */
+ public void setGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] setPositions) {
+
+ int len = (this.getNumGlyphs()+1) << 1;
+ beginGlyphIndex *= 2;
+ numEntries *= 2;
+
+ if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if (numEntries < 0) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ System.arraycopy(setPositions, 0, visualPositions, beginGlyphIndex, numEntries);
+ layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
+
+ }
+
+ /**
+ * Set elements of the visualPositions array.
+ *
+ * @param setPositions the array of positions to set
+ */
+ public void setGlyphPositions(float[] setPositions) {
+
+ int len = (this.getNumGlyphs()+1) << 1;
+ if (len != setPositions.length){
+ // awt.46=length of setPositions array differs from the length of positions array
+ throw new IllegalArgumentException(Messages.getString("awt.46")); //$NON-NLS-1$
+ }
+
+ System.arraycopy(setPositions, 0, visualPositions, 0, len);
+ layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
+
+ }
+
+
+ /**
+ * Returns glyph code of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public int getGlyphCode(int glyphIndex) {
+ if (glyphIndex >= this.vector.length || glyphIndex < 0) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ return this.vector[glyphIndex].getGlyphCode();
+ }
+
+ /**
+ * Returns character index of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public int getGlyphCharIndex(int glyphIndex) {
+
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ if ((this.layoutFlags & Font.LAYOUT_RIGHT_TO_LEFT) != 0) {
+ return this.charVector.length - glyphIndex - 1;
+ }
+
+ return glyphIndex;
+ }
+
+ /**
+ * Returns a character value of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ public char getGlyphChar(int glyphIndex) {
+
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ return this.charVector[glyphIndex];
+ }
+
+ /**
+ * Assigns default positions to each glyph in this GlyphVector.
+ */
+ @Override
+ public void performDefaultLayout() {
+
+ System.arraycopy(logicalPositions, 0, visualPositions, 0, logicalPositions.length);
+
+ // Set position changes flag to zero
+ clearLayoutFlags(GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
+ }
+
+ /**
+ * Returns the number of glyphs in this Glyph Vector
+ */
+ @Override
+ public int getNumGlyphs() {
+ return vector.length;
+ }
+
+ /**
+ * Returns the logical bounds of this GlyphVector
+ */
+ @Override
+ public Rectangle2D getLogicalBounds(){
+ // XXX: for transforms where an angle between basis vectors is not 90 degrees
+ // Rectanlge2D class doesn't fit as Logical bounds. For this reason we use
+ // only non-transformed bounds!!
+
+ float x = visualPositions[0];
+ float width = visualPositions[visualPositions.length-2];
+
+ double scaleY = transform.getScaleY();
+
+ Rectangle2D bounds = new Rectangle2D.Float(x, (float)((-this.ascent-this.leading)*scaleY), width, (float)(this.height*scaleY));
+ return bounds;
+ }
+
+
+ /**
+ * Checks whether given GlyphVector equals to this GlyphVector.
+ * @param glyphVector GlyphVector object to compare
+ */
+ @Override
+ public boolean equals(GlyphVector glyphVector){
+ if (glyphVector == this){
+ return true;
+ }
+
+ if (glyphVector != null) {
+
+ if (!(glyphVector.getFontRenderContext().equals(this.vectorFRC) &&
+ glyphVector.getFont().equals(this.font))){
+ return false;
+ }
+
+ try {
+ boolean eq = true;
+ for (int i = 0; i < getNumGlyphs(); i++) {
+
+ int idx = i*2;
+ eq = (((CommonGlyphVector)glyphVector).visualPositions[idx] == this.visualPositions[idx]) &&
+ (((CommonGlyphVector)glyphVector).visualPositions[idx+1] == this.visualPositions[idx+1]) &&
+ (glyphVector.getGlyphCharIndex(i) == this.getGlyphCharIndex(i));
+
+ if (eq){
+ AffineTransform trans = glyphVector.getGlyphTransform(i);
+ if (trans == null){
+ eq = (this.glsTransforms[i] == null);
+ }else{
+ eq = this.glsTransforms[i].equals(trans);
+ }
+ }
+
+ if (!eq){
+ return false;
+ }
+ }
+
+ return eq;
+ } catch (ClassCastException e) {
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns flags describing the state of the GlyphVector.
+ */
+ @Override
+ public int getLayoutFlags() {
+ return layoutFlags;
+ }
+
+ /**
+ * Returns char with the specified index.
+ *
+ * @param index specified index of the char
+ *
+ */
+ public char getChar(int index) {
+ return this.charVector[index];
+
+ }
+
+ /**
+ * Clear desired flags in layout flags describing the state.
+ *
+ * @param clearFlags flags mask to clear
+ */
+
+ private void clearLayoutFlags(int clearFlags){
+ layoutFlags &= ~clearFlags;
+ }
+
+ /**
+ * Returns the logical bounds of the specified glyph within this CommonGlyphVector.
+ *
+ * @param glyphIndex index of the glyph to get it's logical bounds
+ * @return logical bounds of the specified glyph
+ */
+ @Override
+ public Shape getGlyphLogicalBounds(int glyphIndex){
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())){
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ Glyph glyph = this.vector[glyphIndex];
+
+ float x0 = visualPositions[glyphIndex*2];
+ float y0 = visualPositions[glyphIndex*2+1];
+ float advanceX = glyph.getGlyphPointMetrics().getAdvanceX();
+
+ GeneralPath gp = new GeneralPath();
+ gp.moveTo(0, -ascent - leading);
+ gp.lineTo(advanceX ,-ascent - leading);
+ gp.lineTo(advanceX, descent);
+ gp.lineTo(0, descent);
+ gp.lineTo(0, -ascent - leading);
+ gp.closePath();
+
+ /* Applying GlyphVector font transform */
+ AffineTransform at = (AffineTransform)this.transform.clone();
+
+ /* Applying Glyph transform */
+ AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+ if (glyphTransform != null){
+ at.concatenate(glyphTransform);
+ }
+
+ /* Applying translation to actual visual bounds */
+ at.preConcatenate(AffineTransform.getTranslateInstance(x0, y0));
+ gp.transform(at);
+ return gp;
+ }
+
+ /**
+ * Returns the Font parameter of this GlyphVector
+ */
+ @Override
+ public Font getFont(){
+ return this.font;
+ }
+
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/font/CompositeFont.java b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java
new file mode 100644
index 0000000..70cb334
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.FontProperty;
+
+/**
+ * CompositeFont class is the implementation of logical font classes.
+ * Every logical font consists of several physical fonts that described
+ * in font.properties file according to the face name of this logical font.
+ */
+public class CompositeFont extends FontPeerImpl{
+
+ // a number of physical fonts that CompositeFont consist of
+ int numFonts;
+
+ // font family name
+ String family;
+
+ // font face name
+ String face;
+
+ String[] fontNames;
+
+ // an array of font properties applicable to this CompositeFont
+ FontProperty[] fontProperties;
+
+ // an array of font peers applicable to this CompositeFont
+ public FontPeerImpl[] fPhysicalFonts;
+
+ // missing glyph code field
+ int missingGlyphCode = -1;
+
+ // line metrics of this font
+ LineMetricsImpl nlm = null;
+
+ // cached num glyphs parameter of this font that is the sum of num glyphs of
+ // font peers composing this font
+ int cachedNumGlyphs = -1;
+ /**
+ * Creates CompositeFont object that is corresponding to the specified logical
+ * family name.
+ *
+ * @param familyName logical family name CompositeFont is to be created from
+ * @param faceName logical face name CompositeFont is to be created from
+ * @param _style style of the CompositeFont to be created
+ * @param _size size of the CompositeFont to be created
+ * @param fProperties an array of FontProperties describing physical fonts -
+ * parts of logical font
+ * @param physFonts an array of physical font peers related to the CompositeFont
+ * to be created
+ */
+ public CompositeFont(String familyName, String faceName, int _style, int _size, FontProperty[] fProperties, FontPeerImpl[] physFonts){
+ this.size = _size;
+ this.name = faceName;
+ this.family = familyName;
+ this.style = _style;
+ this.face = faceName;
+ this.psName = faceName;
+ this.fontProperties = fProperties;// !! Supposed that fProperties parameter != null
+ fPhysicalFonts = physFonts;
+ numFonts = fPhysicalFonts.length;
+ setDefaultLineMetrics("", null); //$NON-NLS-1$
+ this.uniformLM = false;
+ }
+
+ /**
+ * Returns the index of the FontPeer in array of physical fonts that is applicable
+ * for the given character. This font has to have the highest priority among fonts
+ * that can display this character and don't have exclusion range covering
+ * specified character. If there is no desired fonts -1 is returned.
+ *
+ * @param chr specified character
+ * @return index of the font from the array of physical fonts that will be used
+ * during processing of the specified character.
+ */
+ public int getCharFontIndex(char chr){
+ for (int i = 0; i < numFonts; i++){
+ if (fontProperties[i].isCharExcluded(chr)){
+ continue;
+ }
+ if (fPhysicalFonts[i].canDisplay(chr)){
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns the index of the FontPeer in array of physical fonts that is applicable
+ * for the given character. This font has to have the highest priority among fonts
+ * that can display this character and don't have exclusion range covering
+ * specified character. If there is no desired fonts default value is returned.
+ *
+ * @param chr specified character
+ * @param defaultValue default index that is returned if the necessary font couldn't be found.
+ * @return index of the font from the array of physical fonts that will be used
+ * during processing of the specified character.
+ */
+ public int getCharFontIndex(char chr, int defaultValue){
+ for (int i = 0; i < numFonts; i++){
+ if (fontProperties[i].isCharExcluded(chr)){
+ continue;
+ }
+ if (fPhysicalFonts[i].canDisplay(chr)){
+ return i;
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns true if one of the physical fonts composing this font CompositeFont
+ * can display specified character.
+ *
+ * @param chr specified character
+ */
+ @Override
+ public boolean canDisplay(char chr){
+ return (getCharFontIndex(chr) != -1);
+ }
+
+ /**
+ * Returns logical ascent (in pixels)
+ */
+ @Override
+ public int getAscent(){
+ return nlm.getLogicalAscent();
+ }
+
+ /**
+ * Returns LineMetrics instance scaled according to the specified transform.
+ *
+ * @param str specified String
+ * @param frc specified FontRenderContext
+ * @param at specified AffineTransform
+ */
+ @Override
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc , AffineTransform at){
+ LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone());
+ lm.setNumChars(str.length());
+
+ if ((at != null) && (!at.isIdentity())){
+ lm.scale((float)at.getScaleX(), (float)at.getScaleY());
+ }
+
+ return lm;
+ }
+
+ /**
+ * Returns cached LineMetrics instance for the null string or creates it if
+ * it wasn't cached yet.
+ */
+ @Override
+ public LineMetrics getLineMetrics(){
+ if (nlm == null){
+ setDefaultLineMetrics("", null); //$NON-NLS-1$
+ }
+
+ return this.nlm;
+ }
+
+ /**
+ * Creates LineMetrics instance and set cached LineMetrics field to it.
+ * Created LineMetrics has maximum values of the idividual metrics of all
+ * composing physical fonts. If there is only one physical font - it's
+ * LineMetrics object is returned.
+ *
+ * @param str specified String
+ * @param frc specified FontRenderContext
+ */
+ private void setDefaultLineMetrics(String str, FontRenderContext frc){
+ LineMetrics lm = fPhysicalFonts[0].getLineMetrics(str, frc, null);
+ float maxCharWidth = (float)fPhysicalFonts[0].getMaxCharBounds(frc).getWidth();
+
+ if (numFonts == 1) {
+ this.nlm = (LineMetricsImpl)lm;
+ return;
+ }
+
+ float[] baselineOffsets = lm.getBaselineOffsets();
+ int numChars = str.length();
+
+ // XXX: default value - common for all Fonts
+ int baseLineIndex = lm.getBaselineIndex();
+
+ float maxUnderlineThickness = lm.getUnderlineThickness();
+ float maxUnderlineOffset = lm.getUnderlineOffset();
+ float maxStrikethroughThickness = lm.getStrikethroughThickness();
+ float minStrikethroughOffset = lm.getStrikethroughOffset();
+ float maxLeading = lm.getLeading(); // External leading
+ float maxHeight = lm.getHeight(); // Height of the font ( == (ascent + descent + leading))
+ float maxAscent = lm.getAscent(); // Ascent of the font
+ float maxDescent = lm.getDescent(); // Descent of the font
+
+ for (int i = 1; i < numFonts; i++){
+ lm = fPhysicalFonts[i].getLineMetrics(str, frc, null);
+ if (maxUnderlineThickness < lm.getUnderlineThickness()){
+ maxUnderlineThickness = lm.getUnderlineThickness();
+ }
+
+ if (maxUnderlineOffset < lm.getUnderlineOffset()){
+ maxUnderlineOffset = lm.getUnderlineOffset();
+ }
+
+ if (maxStrikethroughThickness < lm.getStrikethroughThickness()){
+ maxStrikethroughThickness = lm.getStrikethroughThickness();
+ }
+
+ if (minStrikethroughOffset > lm.getStrikethroughOffset()){
+ minStrikethroughOffset = lm.getStrikethroughOffset();
+ }
+
+ if (maxLeading < lm.getLeading()){
+ maxLeading = lm.getLeading();
+ }
+
+ if (maxAscent < lm.getAscent()){
+ maxAscent = lm.getAscent();
+ }
+
+ if (maxDescent < lm.getDescent()){
+ maxDescent = lm.getDescent();
+ }
+
+ float width = (float)fPhysicalFonts[i].getMaxCharBounds(frc).getWidth();
+ if(maxCharWidth < width){
+ maxCharWidth = width;
+ }
+ for (int j =0; j < baselineOffsets.length; j++){
+ float[] offsets = lm.getBaselineOffsets();
+ if (baselineOffsets[j] > offsets[j]){
+ baselineOffsets[j] = offsets[j];
+ }
+ }
+
+ }
+ maxHeight = maxAscent + maxDescent + maxLeading;
+
+ this.nlm = new LineMetricsImpl(
+ numChars,
+ baseLineIndex,
+ baselineOffsets,
+ maxUnderlineThickness,
+ maxUnderlineOffset,
+ maxStrikethroughThickness,
+ minStrikethroughOffset,
+ maxLeading,
+ maxHeight,
+ maxAscent,
+ maxDescent,
+ maxCharWidth);
+
+ }
+
+ /**
+ * Returns the number of glyphs in this CompositeFont object.
+ */
+ @Override
+ public int getNumGlyphs(){
+ if (this.cachedNumGlyphs == -1){
+
+ this.cachedNumGlyphs = 0;
+
+ for (int i = 0; i < numFonts; i++){
+ this.cachedNumGlyphs += fPhysicalFonts[i].getNumGlyphs();
+ }
+ }
+
+ return this.cachedNumGlyphs;
+ }
+
+ /**
+ * Returns the italic angle of this object.
+ */
+ @Override
+ public float getItalicAngle(){
+ // !! only first physical font used to get this value
+ return fPhysicalFonts[0].getItalicAngle();
+ }
+
+ /**
+ * Returns rectangle that bounds the specified string in terms of composite line metrics.
+ *
+ * @param chars an array of chars
+ * @param start the initial offset in array of chars
+ * @param end the end offset in array of chars
+ * @param frc specified FontRenderContext
+ */
+ public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc){
+
+ LineMetrics lm = getLineMetrics();
+ float minY = -lm.getAscent();
+ float minX = 0;
+ float height = lm.getHeight();
+ float width = 0;
+
+ for (int i = start; i < end; i++){
+ width += charWidth(chars[i]);
+ }
+
+ Rectangle2D rect2D = new Rectangle2D.Float(minX, minY, width, height);
+ return rect2D;
+
+ }
+
+ /**
+ * Returns maximum rectangle that encloses all maximum char bounds of
+ * physical fonts composing this CompositeFont.
+ *
+ * @param frc specified FontRenderContext
+ */
+ @Override
+ public Rectangle2D getMaxCharBounds(FontRenderContext frc){
+
+ Rectangle2D rect2D = fPhysicalFonts[0].getMaxCharBounds(frc);
+ float minY = (float)rect2D.getY();
+ float maxWidth = (float)rect2D.getWidth();
+ float maxHeight = (float)rect2D.getHeight();
+ if (numFonts == 1){
+ return rect2D;
+ }
+
+ for (int i = 1; i < numFonts; i++){
+ if (fPhysicalFonts[i] != null){
+ rect2D = fPhysicalFonts[i].getMaxCharBounds(frc);
+ float y = (float)rect2D.getY();
+ float mWidth = (float)rect2D.getWidth();
+ float mHeight = (float)rect2D.getHeight();
+ if (y < minY){
+ minY = y;
+ }
+ if (mWidth > maxWidth){
+ maxHeight = mWidth;
+ }
+
+ if (mHeight > maxHeight){
+ maxHeight = mHeight;
+ }
+ }
+ }
+
+ rect2D = new Rectangle2D.Float(0, minY, maxWidth, maxHeight);
+
+ return rect2D;
+ }
+
+ /**
+ * Returns font name.
+ */
+ @Override
+ public String getFontName(){
+ return face;
+ }
+
+ /**
+ * Returns font postscript name.
+ */
+ @Override
+ public String getPSName(){
+ return psName;
+ }
+
+ /**
+ * Returns font family name.
+ */
+ @Override
+ public String getFamily(){
+ return family;
+ }
+
+ /**
+ * Returns the code of the missing glyph.
+ */
+ @Override
+ public int getMissingGlyphCode(){
+ // !! only first physical font used to get this value
+ return fPhysicalFonts[0].getMissingGlyphCode();
+ }
+
+ /**
+ * Returns Glyph object corresponding to the specified character.
+ *
+ * @param ch specified char
+ */
+ @Override
+ public Glyph getGlyph(char ch){
+ for (int i = 0; i < numFonts; i++){
+ if (fontProperties[i].isCharExcluded(ch)){
+ continue;
+ }
+
+ /* Control symbols considered to be supported by the font peer */
+ if ((ch < 0x20) || fPhysicalFonts[i].canDisplay(ch)){
+ return fPhysicalFonts[i].getGlyph(ch);
+ }
+ }
+ return getDefaultGlyph();
+ }
+
+ /**
+ * Returns width of the char with specified index.
+ *
+ * @param ind specified index of the character
+ */
+ @Override
+ public int charWidth(int ind){
+ return charWidth((char)ind);
+ }
+
+ /**
+ * Returns width of the specified char.
+ *
+ * @param c specified character
+ */
+ @Override
+ public int charWidth(char c){
+ Glyph gl = this.getGlyph(c);
+ return (int)gl.getGlyphPointMetrics().getAdvanceX();
+ }
+
+ /**
+ * Returns debug information about this class.
+ */
+ @Override
+ public String toString(){
+ return new String(this.getClass().getName() +
+ "[name=" + this.name + //$NON-NLS-1$
+ ",style="+ this.style + //$NON-NLS-1$
+ ",fps=" + this.fontProperties + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns Glyph object corresponding to the default glyph.
+ */
+ @Override
+ public Glyph getDefaultGlyph(){
+ // !! only first physical font used to get this value
+ return fPhysicalFonts[0].getDefaultGlyph();
+ }
+
+ /**
+ * Returns FontExtraMetrics object with extra metrics
+ * related to this CompositeFont.
+ */
+ @Override
+ public FontExtraMetrics getExtraMetrics(){
+ // Returns FontExtraMetrics instanse of the first physical
+ // Font from the array of fonts.
+ return fPhysicalFonts[0].getExtraMetrics();
+ }
+
+ /**
+ * Disposes CompositeFont object's resources.
+ */
+ @Override
+ public void dispose() {
+ // Nothing to dispose
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java b/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
new file mode 100644
index 0000000..047ba6d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ *
+ */
+package org.apache.harmony.awt.gl.font;
+
+/**
+ * Extra font metrics: sub/superscripts sizes, offsets, average char width.
+ */
+public class FontExtraMetrics {
+
+ /* !! Subscript/superscript metrics are undefined for Type1. As a possible
+ * solution we can use values for Type1, that are proportionate to TrueType
+ * ones:
+ * SubscriptSizeX == 0.7 * fontSize
+ * SubscriptSizeY == 0.65 * fontSize
+ * SubscriptOffsetX == 0;
+ * SubscriptOffsetY == 0.15 * fontSize;
+ * SuperscriptSizeX == 0.7 * fontSize
+ * SuperscriptSizeY == 0.65 * fontSize
+ * SuperscriptOffsetX == 0;
+ * SuperscriptOffsetY == 0.45 * fontSize
+ *
+ */
+
+ /*
+ * The average width of characters in the font.
+ */
+ private float lAverageCharWidth;
+
+ /*
+ * Horizontal size for subscripts.
+ */
+ private float lSubscriptSizeX;
+
+ /*
+ * Vertical size for subscripts.
+ */
+ private float lSubscriptSizeY;
+
+ /*
+ * Horizontal offset for subscripts, the offset from the character origin
+ * to the origin of the subscript character.
+ */
+ private float lSubscriptOffsetX;
+
+ /*
+ * Vertical offset for subscripts, the offset from the character origin
+ * to the origin of the subscript character.
+ */
+ private float lSubscriptOffsetY;
+
+ /*
+ * Horizontal size for superscripts.
+ */
+ private float lSuperscriptSizeX;
+
+ /*
+ * Vertical size for superscripts.
+ */
+ private float lSuperscriptSizeY;
+
+ /*
+ * Horizontal offset for superscripts, the offset from the character
+ * base line to the base line of the superscript character.
+ */
+ private float lSuperscriptOffsetX;
+
+ /*
+ * Vertical offset for superscripts, the offset from the character
+ * base line to the base line of the superscript character.
+ */
+ private float lSuperscriptOffsetY;
+
+ public FontExtraMetrics(){
+ // default constructor
+ }
+
+ public FontExtraMetrics(float[] metrics){
+ lAverageCharWidth = metrics[0];
+ lSubscriptSizeX = metrics[1];
+ lSubscriptSizeY = metrics[2];
+ lSubscriptOffsetX = metrics[3];
+ lSubscriptOffsetY = metrics[4];
+ lSuperscriptSizeX = metrics[5];
+ lSuperscriptSizeY = metrics[6];
+ lSuperscriptOffsetX = metrics[7];
+ lSuperscriptOffsetY = metrics[8];
+ }
+
+ public float getAverageCharWidth(){
+ return lAverageCharWidth;
+ }
+
+ public float getSubscriptSizeX(){
+ return lSubscriptSizeX;
+ }
+
+ public float getSubscriptSizeY(){
+ return lSubscriptSizeY;
+ }
+
+ public float getSubscriptOffsetX(){
+ return lSubscriptOffsetX;
+ }
+
+ public float getSubscriptOffsetY(){
+ return lSubscriptOffsetY;
+ }
+
+ public float getSuperscriptSizeX(){
+ return lSuperscriptSizeX;
+ }
+
+ public float getSuperscriptSizeY(){
+ return lSuperscriptSizeY;
+ }
+
+ public float getSuperscriptOffsetX(){
+ return lSuperscriptOffsetX;
+ }
+
+ public float getSuperscriptOffsetY(){
+ return lSuperscriptOffsetY;
+ }
+
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontFinder.java b/awt/org/apache/harmony/awt/gl/font/FontFinder.java
new file mode 100644
index 0000000..09bcf5c
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontFinder.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jul 12, 2005
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.GraphicsEnvironment;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class chooses the default font for the given text.
+ * If it finds the character which current font is unable to display
+ * it starts the next font run and looks for the font which is able to
+ * display the current character. It also caches the font mappings
+ * (index in the array containing all fonts) for the characters,
+ * using that fact that scripts are mainly contiguous in the UTF-16 encoding
+ * and there's a high probability that the upper byte will be the same for the
+ * next character as for the previous. This allows to save the space used for the cache.
+ */
+public class FontFinder {
+ private static final float DEFAULT_FONT_SIZE = 12;
+
+ private static final Font fonts[] =
+ GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+
+ private static final int NUM_BLOCKS = 256;
+ private static final int BLOCK_SIZE = 256;
+ private static final int INDEX_MASK = 0xFF;
+ private static final int BLOCK_SHIFT = 8;
+
+ // Maps characters into the fonts array
+ private static final int blocks[][] = new int[NUM_BLOCKS][];
+
+ /**
+ * Finds the font which is able to display the given character
+ * and saves the font mapping for this character
+ * @param c - character
+ * @return font
+ */
+ static Font findFontForChar(char c) {
+ int blockNum = c >> BLOCK_SHIFT;
+ int index = c & INDEX_MASK;
+
+ if (blocks[blockNum] == null) {
+ blocks[blockNum] = new int[BLOCK_SIZE];
+ }
+
+ if (blocks[blockNum][index] == 0) {
+ blocks[blockNum][index] = 1;
+
+ for (int i=0; i<fonts.length; i++) {
+ if (fonts[i].canDisplay(c)) {
+ blocks[blockNum][index] = i+1;
+ break;
+ }
+ }
+ }
+
+ return getDefaultSizeFont(blocks[blockNum][index]-1);
+ }
+
+ /**
+ * Derives the default size font
+ * @param i - index in the array of all fonts
+ * @return derived font
+ */
+ static Font getDefaultSizeFont(int i) {
+ if (fonts[i].getSize() != DEFAULT_FONT_SIZE) {
+ fonts[i] = fonts[i].deriveFont(DEFAULT_FONT_SIZE);
+ }
+
+ return fonts[i];
+ }
+
+ /**
+ * Assigns default fonts for the given text run.
+ * First three parameters are input, last three are output.
+ * @param text - given text
+ * @param runStart - start of the text run
+ * @param runLimit - end of the text run
+ * @param runStarts - starts of the resulting font runs
+ * @param fonts - mapping of the font run starts to the fonts
+ */
+ static void findFonts(char text[], int runStart, int runLimit, List<Integer> runStarts,
+ Map<Integer, Font> fonts) {
+ Font prevFont = null;
+ Font currFont;
+ for (int i = runStart; i < runLimit; i++) {
+ currFont = findFontForChar(text[i]);
+ if (currFont != prevFont) {
+ prevFont = currFont;
+ Integer idx = new Integer(i);
+ fonts.put(idx, currFont);
+ if (i != runStart) {
+ runStarts.add(idx);
+ }
+ }
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontManager.java b/awt/org/apache/harmony/awt/gl/font/FontManager.java
new file mode 100644
index 0000000..8354e25
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontManager.java
@@ -0,0 +1,819 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.peer.FontPeer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+
+public abstract class FontManager {
+
+ //???AWT
+ boolean NOT_IMP = false;
+
+ /**
+ * array of font families names
+ */
+ public String[] allFamilies;
+
+ public static final String DEFAULT_NAME = "Default"; /* Default font name */ //$NON-NLS-1$
+ public static final String DIALOG_NAME = "Dialog"; /* Dialog font name */ //$NON-NLS-1$
+
+ /**
+ * Set of constants applicable to the TrueType 'name' table.
+ */
+ public static final byte FAMILY_NAME_ID = 1; /* Family name identifier */
+ public static final byte FONT_NAME_ID = 4; /* Full font name identifier */
+ public static final byte POSTSCRIPT_NAME_ID = 6; /* PostScript name identifier */
+ public static final short ENGLISH_LANGID = 0x0409; /* English (United States)language identifier */
+
+ /**
+ * Set of constants describing font type.
+ */
+ public static final byte FONT_TYPE_TT = 4; /* TrueType type (TRUETYPE_FONTTYPE) */
+ public static final byte FONT_TYPE_T1 = 2; /* Type1 type (DEVICE_FONTTYPE) */
+ public static final byte FONT_TYPE_UNDEF = 0; /* Undefined type */
+
+ // logical family types (indices in FontManager.LOGICAL_FONT_NAMES)
+ static final int DIALOG = 3; // FF_SWISS
+ static final int SANSSERIF = 1; // FF_SWISS
+ static final int DIALOGINPUT = 4; // FF_MODERN
+ static final int MONOSPACED = 2; // FF_MODERN
+ static final int SERIF = 0; // FF_ROMAN
+
+
+ /**
+ * FontProperty related constants.
+ */
+ public static final String PLATFORM_FONT_NAME = "PlatformFontName"; //$NON-NLS-1$
+ public static final String LOGICAL_FONT_NAME = "LogicalFontName"; //$NON-NLS-1$
+ public static final String COMPONENT_INDEX = "ComponentIndex"; //$NON-NLS-1$
+ public static final String STYLE_INDEX = "StyleIndex"; //$NON-NLS-1$
+
+ public static final String[] FONT_MAPPING_KEYS = {
+ "LogicalFontName.StyleName.ComponentIndex", "LogicalFontName.ComponentIndex" //$NON-NLS-1$ //$NON-NLS-2$
+ };
+
+ public static final String FONT_CHARACTER_ENCODING = "fontcharset.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
+
+ public static final String EXCLUSION_RANGES = "exclusion.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
+
+ public static final String FONT_FILE_NAME = "filename.PlatformFontName"; //$NON-NLS-1$
+
+ /**
+ * Available logical font families names.
+ */
+ public static final String[] LOGICAL_FONT_FAMILIES = {
+ "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ /**
+ * Available logical font names.
+ */
+ public static final String[] LOGICAL_FONT_NAMES = {
+ "serif", "serif.plain", "serif.bold", "serif.italic", "serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "sansserif", "sansserif.plain", "sansserif.bold", "sansserif.italic", "sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "monospaced", "monospaced.plain", "monospaced.bold", "monospaced.italic", "monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "dialog", "dialog.plain", "dialog.bold", "dialog.italic", "dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "dialoginput", "dialoginput.plain", "dialoginput.bold", "dialoginput.italic", "dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ /**
+ * Available logical font face names.
+ */
+ public static final String[] LOGICAL_FONT_FACES = {
+ "Serif", "Serif.plain", "Serif.bold", "Serif.italic", "Serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Sansserif", "Sansserif.plain", "Sansserif.bold", "Sansserif.italic", "Sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Monospaced", "Monospaced.plain", "Monospaced.bold", "Monospaced.italic", "Monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Dialog", "Dialog.plain", "Dialog.bold", "Dialog.italic", "Dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Dialoginput", "Dialoginput.plain", "Dialoginput.bold", "Dialoginput.italic", "Dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ /**
+ * Set of font style names.
+ * Font.getStyle() corresponds to indexes in STYLE_NAMES array.
+ */
+ public static final String[] STYLE_NAMES = {
+ "plain", "bold", "italic", "bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ };
+
+ /**
+ * Logical font styles names table where font styles names used
+ * as the key and the value is the index of this style name.
+ */
+ private static final Hashtable<String, Integer> style_keys = new Hashtable<String, Integer>(4);
+
+ /**
+ * Initialize font styles keys table.
+ */
+ static {
+ for (int i = 0; i < STYLE_NAMES.length; i++){
+ style_keys.put(STYLE_NAMES[i], Integer.valueOf(i));
+ }
+ }
+
+ /**
+ * Return font style from the logical style name.
+ *
+ * @param lName style name of the logical face
+ */
+ public static int getLogicalStyle(String lName){
+ Integer value = style_keys.get(lName);
+ return value != null ? value.intValue(): -1;
+ }
+
+ /**
+ * Set of possible "os" property values.
+ */
+ public static final String[] OS_VALUES = {
+ "NT", "98", "2000", "Me", "XP", // For Windows //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Redhat", "Turbo", "SuSE" // For Linux //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ };
+
+ /**
+ * Set of possible font.property file names.
+ * Language, Country, Encoding, OS, Version should be replaced with
+ * the values from current configuration.
+ */
+ public static final String[] FP_FILE_NAMES = {
+ "/lib/font.properties.Language_Country_Encoding.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country_Encoding.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country_Encoding.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country_Encoding", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding", //$NON-NLS-1$
+ "/lib/font.properties.Language.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language", //$NON-NLS-1$
+ "/lib/font.properties.Encoding.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Encoding.OS", //$NON-NLS-1$
+ "/lib/font.properties.Encoding.Version", //$NON-NLS-1$
+ "/lib/font.properties.Encoding", //$NON-NLS-1$
+ "/lib/font.properties.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.OS", //$NON-NLS-1$
+ "/lib/font.properties.Version", //$NON-NLS-1$
+ "/lib/font.properties" //$NON-NLS-1$
+ };
+
+ /**
+ * Table with all available font properties corresponding
+ * to the current system configuration.
+ */
+ public Hashtable<String, Vector<FontProperty>> fProperties = new Hashtable<String, Vector<FontProperty>>();
+
+ public FontManager(){
+ allFamilies = getAllFamilies();
+ /*
+ * Creating and registering shutdown hook to free resources
+ * before object is destroyed.
+ */
+ //???AWT
+ //DisposeNativeHook shutdownHook = new DisposeNativeHook();
+ //Runtime.getRuntime().addShutdownHook(shutdownHook);
+ }
+
+ /**
+ * Maximum number of unreferenced font peers to keep.
+ */
+ public static final int EMPTY_FONTS_CAPACITY = 10;
+
+ /**
+ * Locale - Language ID hash table.
+ */
+ Hashtable<String, Short> tableLCID = new Hashtable<String, Short>();
+
+ /**
+ * Hash table that contains FontPeers instances.
+ */
+ public Hashtable<String, HashMapReference> fontsTable = new Hashtable<String, HashMapReference>();
+
+ /**
+ * ReferenceQueue for HashMapReference objects to check
+ * if they were collected by garbage collector.
+ */
+ public ReferenceQueue<FontPeer> queue = new ReferenceQueue<FontPeer>();
+
+ /**
+ * Singleton instance
+ */
+ public final static FontManager inst = CommonGraphics2DFactory.inst.getFontManager();
+
+ /**
+ * Gets singleton instance of FontManager
+ *
+ * @return instance of FontManager implementation
+ */
+ public static FontManager getInstance() {
+ return inst;
+ }
+
+ /**
+ * Returns platform-dependent Font peer created from the specified
+ * Font object from the table with cached FontPeers instances.
+ *
+ * Note, this method checks whether FontPeer with specified parameters
+ * exists in the table with cached FontPeers' instances. If there is no needed
+ * instance - it is created and cached.
+ *
+ * @param fontName name of the font
+ * @param _fontStyle style of the font
+ * @param size font size
+ *
+ * @return platform dependent FontPeer implementation created from
+ * the specified parameters
+ */
+ public FontPeer getFontPeer(String fontName, int _fontStyle, int size) {
+ updateFontsTable();
+
+ FontPeer peer = null;
+ String key;
+ String name;
+ int fontStyle = _fontStyle;
+
+ int logicalIndex = getLogicalFaceIndex(fontName);
+
+ if (logicalIndex != -1){
+ name = getLogicalFaceFromFont(fontStyle, logicalIndex);
+ fontStyle = getStyleFromLogicalFace(name);
+ key = name.concat(String.valueOf(size));
+ } else {
+ name = fontName;
+ key = name.concat(String.valueOf(fontStyle)).
+ concat(String.valueOf(size));
+ }
+
+ HashMapReference hmr = fontsTable.get(key);
+ if (hmr != null) {
+ peer = hmr.get();
+ }
+
+ if (peer == null) {
+ peer = createFontPeer(name, fontStyle, size, logicalIndex);
+ if (peer == null){
+ peer = getFontPeer(DIALOG_NAME, fontStyle, size);
+ }
+ fontsTable.put(key, new HashMapReference(key, peer, queue));
+ }
+
+ return peer;
+ }
+
+ /**
+ * Returns instance of font peer (logical or physical) according to the
+ * specified parameters.
+ *
+ * @param name font face name
+ * @param style style of the font
+ * @param size size of the font
+ * @param logicalIndex index of the logical face name in LOGICAL_FONT_FACES
+ * array or -1 if desired font peer is not logical.
+ */
+ private FontPeer createFontPeer(String name, int style, int size, int logicalIndex){
+ FontPeer peer;
+ if (logicalIndex != -1){
+ peer = createLogicalFontPeer(name, style, size);
+ }else {
+ peer = createPhysicalFontPeer(name, style, size);
+ }
+
+ return peer;
+ }
+
+ /**
+ * Returns family name for logical face names as a parameter.
+ *
+ * @param faceName logical font face name
+ */
+ public String getFamilyFromLogicalFace(String faceName){
+ int pos = faceName.indexOf("."); //$NON-NLS-1$
+ if (pos == -1){
+ return faceName;
+ }
+
+ return faceName.substring(0, pos);
+ }
+
+ /**
+ * Returns new logical font peer for the parameters specified using font
+ * properties.
+ *
+ * @param faceName face name of the logical font
+ * @param style style of the font
+ * @param size font size
+ *
+ */
+ private FontPeer createLogicalFontPeer(String faceName, int style, int size){
+ String family = getFamilyFromLogicalFace(faceName);
+ FontProperty[] fps = getFontProperties(family.toLowerCase() + "." + style); //$NON-NLS-1$
+ if (fps != null){
+ int numFonts = fps.length;
+ FontPeerImpl[] physicalFonts = new FontPeerImpl[numFonts];
+ for (int i = 0; i < numFonts; i++){
+ FontProperty fp = fps[i];
+
+ String name = fp.getName();
+ int fpStyle = fp.getStyle();
+ String key = name.concat(String.valueOf(fpStyle)).
+ concat(String.valueOf(size));
+
+ HashMapReference hmr = fontsTable.get(key);
+ if (hmr != null) {
+ physicalFonts[i] = (FontPeerImpl)hmr.get();
+ }
+
+ if (physicalFonts[i] == null){
+ physicalFonts[i] = (FontPeerImpl)createPhysicalFontPeer(name, fpStyle, size);
+ fontsTable.put(key, new HashMapReference(key, physicalFonts[i], queue));
+ }
+
+ if (physicalFonts[i] == null){
+ physicalFonts[i] = (FontPeerImpl)getDefaultFont(style, size);
+ }
+ }
+ return new CompositeFont(family, faceName, style, size, fps, physicalFonts);
+ }
+
+ // if there is no property for this logical font - default font is to be
+ // created
+ FontPeerImpl peer = (FontPeerImpl)getDefaultFont(style, size);
+
+ return peer;
+ }
+
+ /**
+ * Returns new physical font peer for the parameters specified using font properties
+ * This method must be overridden by subclasses implementations.
+ *
+ * @param faceName face name or family name of the font
+ * @param style style of the font
+ * @param size font size
+ *
+ */
+ public abstract FontPeer createPhysicalFontPeer(String name, int style, int size);
+
+ /**
+ * Returns default font peer class with "Default" name that is usually
+ * used when font with specified font names and style doesn't exsist
+ * on a system.
+ *
+ * @param style style of the font
+ * @param size size of the font
+ */
+ public FontPeer getDefaultFont(int style, int size){
+ updateFontsTable();
+
+ FontPeer peer = null;
+ String key = DEFAULT_NAME.concat(String.valueOf(style)).
+ concat(String.valueOf(size));
+
+ HashMapReference hmr = fontsTable.get(key);
+ if (hmr != null) {
+ peer = hmr.get();
+ }
+
+ if (peer == null) {
+ peer = createDefaultFont(style, size);
+
+ ((FontPeerImpl)peer).setFamily(DEFAULT_NAME);
+ ((FontPeerImpl)peer).setPSName(DEFAULT_NAME);
+ ((FontPeerImpl)peer).setFontName(DEFAULT_NAME);
+
+ fontsTable.put(key, new HashMapReference(key, peer, queue));
+ }
+
+ return peer;
+ }
+
+ /**
+ *
+ * Returns new default font peer with "Default" name for the parameters
+ * specified. This method must be overridden by subclasses implementations.
+ *
+ * @param style style of the font
+ * @param size size of the font
+ */
+ public abstract FontPeer createDefaultFont(int style, int size);
+
+ /**
+ * Returns face name of the logical font, which is the result
+ * of specified font style and face style union.
+ *
+ * @param fontStyle specified style of the font
+ * @param logicalIndex index of the specified face from the
+ * LOGICAL_FONT_FACES array
+ * @return resulting face name
+ */
+ public String getLogicalFaceFromFont(int fontStyle, int logicalIndex){
+ int style = 0;
+ String name = LOGICAL_FONT_FACES[logicalIndex];
+ int pos = name.indexOf("."); //$NON-NLS-1$
+
+ if (pos == -1){
+ return createLogicalFace(name, fontStyle);
+ }
+
+ String styleName = name.substring(pos+1);
+ name = name.substring(0, pos);
+
+ // appending font style to the face style
+ style = fontStyle | getLogicalStyle(styleName);
+
+ return createLogicalFace(name, style);
+ }
+
+ /**
+ * Function returns style value from logical face name.
+ *
+ * @param name face name
+ * @return font style
+ */
+ public int getStyleFromLogicalFace(String name){
+ int style;
+ int pos = name.indexOf("."); //$NON-NLS-1$
+
+ if (pos == -1){
+ return Font.PLAIN;
+ }
+
+ String styleName = name.substring(pos+1);
+
+ style = getLogicalStyle(styleName);
+
+ return style;
+ }
+
+ /**
+ * Returns logical face name corresponding to the logical
+ * family name and style of the font.
+ *
+ * @param family font family
+ * @param styleIndex index of the style name from the STYLE_NAMES array
+ */
+ public String createLogicalFace(String family, int styleIndex){
+ return family + "." + STYLE_NAMES[styleIndex]; //$NON-NLS-1$
+ }
+
+ /**
+ * Return language Id from LCID hash corresponding to the specified locale
+ *
+ * @param l specified locale
+ */
+ public Short getLCID(Locale l){
+ if (this.tableLCID.size() == 0){
+ initLCIDTable();
+ }
+
+ return tableLCID.get(l.toString());
+ }
+
+ /**
+ * Platform-dependent LCID table init.
+ */
+ public abstract void initLCIDTable();
+
+ /**
+ * Freeing native resources. This hook is used to avoid
+ * sudden application exit and to free resources created in native code.
+ */
+ private class DisposeNativeHook extends Thread {
+
+ @Override
+ public void run() {
+ try{
+ /* Disposing native font peer's resources */
+ Enumeration<String> kEnum = fontsTable.keys();
+
+ while(kEnum.hasMoreElements()){
+ Object key = kEnum.nextElement();
+ HashMapReference hmr = fontsTable.remove(key);
+ FontPeerImpl delPeer = (FontPeerImpl)hmr.get();
+
+ if ((delPeer != null) && (delPeer.getClass() != CompositeFont.class)){
+ // there's nothing to dispose in CompositeFont objects
+ delPeer.dispose();
+ }
+ }
+ } catch (Throwable t){
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+ /**
+ * Returns File object, created in a directory
+ * according to the System, where JVM is being ran.
+ *
+ * In Linux case we use ".fonts" directory (for fontconfig purpose),
+ * where font file from the stream will be stored, hence in LinuxFontManager this
+ * method is overridden.
+ * In Windows case we use Windows temp directory (default implementation)
+ *
+ */
+ public File getTempFontFile()throws IOException{
+ //???AWT
+ /*
+ File fontFile = File.createTempFile("jFont", ".ttf"); //$NON-NLS-1$ //$NON-NLS-2$
+ fontFile.deleteOnExit();
+
+ return fontFile;
+ */
+ if(NOT_IMP)
+ throw new NotImplementedException("getTempFontFile not Implemented");
+ return null;
+ }
+
+ /**
+ * Returns File object with font properties. It's name obtained using current
+ * system configuration properties and locale settings. If no appropriate
+ * file is found method returns null.
+ */
+ public static File getFontPropertyFile(){
+ File file = null;
+
+ String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+ Locale l = Locale.getDefault();
+ String language = l.getLanguage();
+ String country = l.getCountry();
+ String fileEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$
+
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+
+ int i = 0;
+
+ // OS names from system properties don't match
+ // OS identifiers used in font.property files
+ for (; i < OS_VALUES.length; i++){
+ if (os.endsWith(OS_VALUES[i])){
+ os = OS_VALUES[i];
+ break;
+ }
+ }
+
+ if (i == OS_VALUES.length){
+ os = null;
+ }
+
+ String version = System.getProperty("os.version"); //$NON-NLS-1$
+ String pathname;
+
+ for (i = 0; i < FP_FILE_NAMES.length; i++){
+ pathname = FP_FILE_NAMES[i];
+ if (os != null){
+ pathname = pathname.replaceFirst("OS", os); //$NON-NLS-1$
+ }
+
+ pathname = javaHome + pathname;
+
+ pathname = pathname.replaceAll("Language", language). //$NON-NLS-1$
+ replaceAll("Country", country). //$NON-NLS-1$
+ replaceAll("Encoding", fileEncoding). //$NON-NLS-1$
+ replaceAll("Version", version); //$NON-NLS-1$
+
+ file = new File(pathname);
+
+ if (file.exists()){
+ break;
+ }
+ }
+
+ return file.exists() ? file : null;
+ }
+
+ /**
+ * Returns an array of integer range values
+ * if the parameter exclusionString has format:
+ * Range
+ * Range [, exclusionString]
+ *
+ * Range:
+ * Char-Char
+ *
+ * Char:
+ * HexDigit HexDigit HexDigit HexDigit
+ *
+ * Method returns null if the specified string is null.
+ *
+ * @param exclusionString string parameter in specified format
+ */
+ public static int[] parseIntervals(String exclusionString){
+ int[] results = null;
+
+ if (exclusionString == null){
+ return null;
+ }
+
+ String[] intervals = exclusionString.split(","); //$NON-NLS-1$
+
+ if (intervals != null){
+ int num = intervals.length;
+ if (num > 0){
+ results = new int[intervals.length << 1];
+ for (int i = 0; i < intervals.length; i++){
+ String ranges[] = intervals[i].split("-"); //$NON-NLS-1$
+ results[i*2] = Integer.parseInt(ranges[0], 16);
+ results[i*2+1] = Integer.parseInt(ranges[1], 16);
+
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Returns Properties from the properties file or null if
+ * there is an error with FileInputStream processing.
+ *
+ * @param file File object containing properties
+ */
+ public static Properties getProperties(File file){
+ Properties props = null;
+ FileInputStream fis = null;
+ try{
+ fis = new FileInputStream(file);
+ props = new Properties();
+ props.load(fis);
+ } catch (Exception e){
+ System.out.println(e);
+ }
+ return props;
+ }
+
+ /**
+ * Returns an array of FontProperties from the properties file
+ * with the specified property name "logical face.style". E.g.
+ * "dialog.2" corresponds to the font family Dialog with bold style.
+ *
+ * @param fpName key of the font properties in the properties set
+ */
+ public FontProperty[] getFontProperties(String fpName){
+ Vector<FontProperty> props = fProperties.get(fpName);
+
+ if (props == null){
+ return null;
+ }
+
+ int size = props.size();
+
+ if (size == 0){
+ return null;
+ }
+
+ FontProperty[] fps = new FontProperty[size];
+ for (int i=0; i < fps.length; i++){
+ fps[i] = props.elementAt(i);
+ }
+ return fps;
+ }
+
+ /**
+ * Returns index of the font name in array of font names or -1 if
+ * this font is not logical.
+ *
+ * @param fontName specified font name
+ */
+ public static int getLogicalFaceIndex(String fontName){
+ for (int i=0; i<LOGICAL_FONT_NAMES.length; i++ ){
+ if (LOGICAL_FONT_NAMES[i].equalsIgnoreCase(fontName)){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns true if specified family name is available in this
+ * GraphicsEnvironment.
+ *
+ * @param familyName the specified font family name
+ */
+ public boolean isFamilyExist(String familyName){
+ return (getFamilyIndex(familyName) != -1);
+ }
+
+ /**
+ * Returns index of family name from the array of family names available in
+ * this GraphicsEnvironment or -1 if no family name was found.
+ *
+ * @param familyName specified font family name
+ */
+ public int getFamilyIndex(String familyName){
+ for (int i=0; i<allFamilies.length; i++ ){
+ if (familyName.equalsIgnoreCase(allFamilies[i])){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns family with index specified from the array of family names available in
+ * this GraphicsEnvironment.
+ *
+ * @param index index of the family in families names array
+ */
+ public String getFamily(int index){
+ return allFamilies[index];
+ }
+ /**
+ * Returns index of face name from the array of face names available in
+ * this GraphicsEnvironment or -1 if no face name was found. Default return
+ * value is -1, method must be overridden by FontManager implementation.
+ *
+ * @param faceName font face name which index is to be searched
+ */
+ public int getFaceIndex(String faceName){
+ return -1;
+ }
+
+ public abstract String[] getAllFamilies();
+
+ public abstract Font[] getAllFonts();
+
+ /**
+ * Class contains SoftReference instance that can be stored in the
+ * Hashtable by means of key field corresponding to it.
+ */
+ private class HashMapReference extends SoftReference<FontPeer> {
+
+ /**
+ * The key for Hashtable.
+ */
+ private final String key;
+
+ /**
+ * Creates a new soft reference with the key specified and
+ * adding this reference in the reference queue specified.
+ *
+ * @param key the key in Hashtable
+ * @param value object that corresponds to the key
+ * @param queue reference queue where reference is to be added
+ */
+ public HashMapReference(final String key, final FontPeer value,
+ final ReferenceQueue<FontPeer> queue) {
+ super(value, queue);
+ this.key = key;
+ }
+
+ /**
+ * Returns the key that corresponds to the SoftReference instance
+ *
+ * @return the key in Hashtable with cached references
+ */
+ public Object getKey() {
+ return key;
+ }
+ }
+
+ /**
+ * Removes keys from the Hashtable with font peers which corresponding
+ * HashMapReference objects were garbage collected.
+ */
+ private void updateFontsTable() {
+ HashMapReference r;
+ //???AWT
+ //while ((r = (HashMapReference)queue.poll()) != null) {
+ // fontsTable.remove(r.getKey());
+ //}
+ }
+
+}
+
+
diff --git a/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java b/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
new file mode 100644
index 0000000..7783317
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+//import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+
+import android.graphics.Paint;
+
+/**
+ * FontMetrics implementation
+ */
+
+public class FontMetricsImpl extends FontMetrics {
+
+ private static final long serialVersionUID = 844695615201925138L;
+
+ // ascent of the font
+ private int ascent;
+
+ // descent of the font
+ private int descent;
+
+ // leading of the font
+ private int leading;
+
+ // maximum ascent of the font
+ private int maxAscent;
+
+ // maximum descent of the font
+ private int maxDescent;
+
+ // maximum advance of the font
+ private int maxAdvance;
+
+ // array of char advance widths
+ private int[] widths = new int[256];
+
+ // font peer corresponding to this FontPeerImpl
+ private transient FontPeerImpl peer;
+
+ // X scale parameter of the font transform
+ private float scaleX = 1;
+
+ public AndroidGraphics2D mSg;
+
+ private Font mFn;
+
+ // Y scale parameter of the font transform
+ private float scaleY = 1;
+
+ /**
+ * Creates new FontMericsImpl object described by the specified Font.
+ *
+ * @param fnt
+ * the specified Font object
+ */
+ public FontMetricsImpl(Font fnt) {
+ super(fnt);
+ this.mFn = fnt;
+
+ mSg = AndroidGraphics2D.getInstance();
+ Paint p = mSg.getAndroidPaint();
+
+ this.ascent = (int)-p.ascent();
+ this.descent = (int)p.descent();
+ this.leading = p.getFontMetricsInt().leading;
+
+ AffineTransform at = fnt.getTransform();
+ if (!at.isIdentity()) {
+ scaleX = (float) at.getScaleX();
+ scaleY = (float) at.getScaleY();
+ }
+
+ /*
+ * metrics[5] - strikethrough thickness<p>
+ * -metrics[6] - strikethrough offset<p>
+ * metrics[7] - maximum char width<p>
+ * metrics[8] - ascent in pixels<p>
+ * metrics[9] - descent in pixles<p>
+ * metrics[10] - external leading in pixels<p>
+ * metrics[11] - underline thickness in pixels<p>
+ * -metrics[12] - underline offset in pixels<p>
+ * metrics[13] - strikethrough thickness in pixels<p>
+ * -metrics[14] - strikethrough offset in pixels<p>
+ * metrics[15] - maximum char width in pixels<p>
+
+ * @param _baselineData an array of 3 elements with baseline offsets metrics<p>
+ * _baselineData[0] - roman baseline offset<p>
+ * _baselineData[1] - center baseline offset<p>
+ * _baselineData[2] - hanging baseline offset<p>
+ */
+ }
+
+
+ /**
+ * Initialize the array of the first 256 chars' advance widths of the Font
+ * describing this FontMetricsImpl object.
+ */
+ private void initWidths() {
+
+ this.widths = new int[256];
+ for (int chr = 0; chr < 256; chr++) {
+ widths[chr] = (int) (getFontPeer().charWidth((char) chr) * scaleX);
+ }
+
+ }
+
+ /**
+ * Returns the ascent of the Font describing this FontMetricsImpl object.
+ */
+ @Override
+ public int getAscent() {
+ return this.ascent;
+ }
+
+ /**
+ * Returns the descent of the Font describing this FontMetricsImpl object.
+ */
+ @Override
+ public int getDescent() {
+ return this.descent;
+ }
+
+ /**
+ * Returns the leading of the Font describing this FontMetricsImpl object.
+ */
+ @Override
+ public int getLeading() {
+ return this.leading;
+ }
+
+ /**
+ * Returns the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object.
+ *
+ * @param ch
+ * the char which width is to be returned
+ * @return the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object
+ */
+ @Override
+ public int charWidth(int ch) {
+ if (ch < 256) {
+ return widths[ch];
+ }
+
+ return getFontPeer().charWidth((char) ch);
+ }
+
+ /**
+ * Returns the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object.
+ *
+ * @param ch
+ * the char which width is to be returned
+ * @return the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object
+ */
+ @Override
+ public int charWidth(char ch) {
+ if (ch < 256) {
+ return widths[ch];
+ }
+ return (int) (getFontPeer().charWidth(ch) * scaleX);
+ }
+
+ /**
+ * Returns the maximum advance of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @Override
+ public int getMaxAdvance() {
+ return this.maxAdvance;
+ }
+
+ /**
+ * Returns the maximum ascent of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @Override
+ public int getMaxAscent() {
+ return this.maxAscent;
+ }
+
+ /**
+ * Returns the maximum descent of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @SuppressWarnings("deprecation")
+ @Deprecated
+ @Override
+ public int getMaxDecent() {
+ return this.maxDescent;
+ }
+
+ /**
+ * Returns the maximum descent of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @Override
+ public int getMaxDescent() {
+ return this.maxDescent;
+ }
+
+ /**
+ * Returns the advance widths of the first 256 characters in the Font
+ * describing this FontMetricsImpl object.
+ */
+ @Override
+ public int[] getWidths() {
+ return this.widths;
+ }
+
+ /**
+ * Returns the total advance width of the specified string in the metrics of
+ * the Font describing this FontMetricsImpl object.
+ *
+ * @param str
+ * the String which width is to be measured
+ * @return the total advance width of the specified string in the metrics of
+ * the Font describing this FontMetricsImpl object
+ */
+ @Override
+ public int stringWidth(String str) {
+
+ int width = 0;
+ char chr;
+
+ for (int i = 0; i < str.length(); i++) {
+ chr = str.charAt(i);
+ width += charWidth(chr);
+ }
+ return width;
+
+ /*
+ * float res = 0; int ln = str.length(); char[] c = new char[ln]; float[] f =
+ * new float[ln]; str.getChars(0, ln, c, 0); mSg.getPaint().getTextWidths(c, 0,
+ * ln, f);
+ *
+ * for(int i = 0; i < f.length; i++) { res += f[i]; } return (int)res;
+ */
+ }
+
+ /**
+ * Returns FontPeer implementation of the Font describing this
+ * FontMetricsImpl object.
+ *
+ * @return a FontPeer object, that is the platform dependent FontPeer
+ * implementation for the Font describing this FontMetricsImpl
+ * object.
+ */
+ @SuppressWarnings("deprecation")
+ public FontPeerImpl getFontPeer() {
+ if (peer == null) {
+ peer = (FontPeerImpl) font.getPeer();
+ }
+ return peer;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java b/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
new file mode 100644
index 0000000..14ff997
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
@@ -0,0 +1,499 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+
+import com.android.internal.awt.AndroidGraphics2D;
+import com.android.internal.awt.AndroidGraphicsFactory;
+
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.peer.FontPeer;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import android.graphics.Paint;
+
+/**
+ * Abstract class for platform dependent peer implementation of the Font class.
+ */
+public abstract class FontPeerImpl implements FontPeer{
+
+ // ascent of this font peer (in pixels)
+ int ascent;
+
+ // descent of this font peer (in pixels)
+ int descent;
+
+ // leading of this font peer (in pixels)
+ int leading;
+
+ // logical maximum advance of this font peer (in pixels)
+ int maxAdvance;
+
+ // the height of this font peer
+ float height;
+
+ // the style of this font peer
+ int style;
+
+ // the point size of this font peer (in pixels)
+ int size;
+
+ // the logical hight of this font peer (in pixels)
+ int logicalHeight;
+
+ // the name of this font peer
+ String name;
+
+ // family name of this font peer
+ String fontFamilyName;
+
+ // the Face name of this font peer
+ String faceName;
+
+ // bounds rectanlge of the largest character in this font peer
+ Rectangle2D maxCharBounds;
+
+ // italic angle value of this font peer
+ float italicAngle = 0.0f;
+
+ // the number of glyphs supported by this font peer
+ int numGlyphs = 0;
+
+ // native font handle
+ long pFont;
+
+ // cached line metrics object
+ LineMetricsImpl nlm;
+
+ // the postscript name of this font peer
+ String psName = null;
+
+ /**
+ * Default glyph index, that is used, when the desired glyph
+ * is unsupported in this Font.
+ */
+ public char defaultChar = (char)0xFFFF;
+
+ /**
+ * Uniform LineMetrics flag, that is false for CompositeFont.
+ * Default value is true.
+ */
+ boolean uniformLM = true;
+
+ /**
+ * Flag of the type of this Font that is indicate is the Font
+ * has TrueType or Type1 type. Default value is FONT_TYPE_UNDEF.
+ */
+ int fontType = FontManager.FONT_TYPE_UNDEF;
+
+ /**
+ * Flag if this Font was created from stream,
+ * this parameter used in finilize method.
+ */
+ private boolean createdFromStream = false;
+
+ // temorary Font file name, if this FontPeerImpl was created from InputStream
+ private String tempFontFileName = null;
+
+ // cached FontExtraMetrics object related to this font peer
+ FontExtraMetrics extraMetrix = null;
+
+ public abstract FontExtraMetrics getExtraMetrics();
+
+ /**
+ * Returns LineMetrics object with specified parameters
+ * @param str specified String
+ * @param frc specified render context
+ * @param at specified affine transform
+ * @return
+ */
+ public abstract LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at);
+
+ /**
+ * Returns postscript name of the font.
+ */
+ public abstract String getPSName();
+
+ //private Graphics2D g = ((AndroidGraphicsFactory)Toolkit.getDefaultToolkit().getGraphicsFactory()).getGraphics2D();
+ //private Graphics2D g = AndroidGraphics2D.getInstance();
+
+ /**
+ * Set postscript name of the font to the specified parameter.
+ */
+ public void setPSName(String name){
+ this.psName = name;
+ }
+
+ /**
+ * Returns code of the missing glyph.
+ */
+ public abstract int getMissingGlyphCode();
+
+ /**
+ * Returns Glyph representation of the given char.
+ * @param ch specified char
+ */
+ public abstract Glyph getGlyph(char ch);
+
+ /**
+ * Disposes nesessary resources.
+ */
+ public abstract void dispose();
+
+ /**
+ * Returns Glyph represeting missing char.
+ */
+ public abstract Glyph getDefaultGlyph();
+
+ /**
+ * Returns true if this FontPeerImpl can display the specified char
+ */
+ public abstract boolean canDisplay(char c);
+
+ /**
+ * Returns family name of the font in specified locale settings.
+ * @param l specified Locale
+ */
+ public String getFamily(Locale l){
+ return this.getFamily();
+ }
+
+ /**
+ * Sets family name of the font in specified locale settings.
+ */
+ public void setFamily(String familyName){
+ this.fontFamilyName = familyName;
+ }
+
+ /**
+ * Returns face name of the font in specified locale settings.
+ * @param l specified Locale
+ */
+ public String getFontName(Locale l){
+ return this.getFontName();
+ }
+
+ /**
+ * Sets font name of the font in specified locale settings.
+ */
+ public void setFontName(String fontName){
+ this.faceName = fontName;
+ }
+
+ /**
+ * Returns true, if this font peer was created from InputStream, false otherwise.
+ * In case of creating fonts from InputStream some font peer implementations
+ * may need to free temporary resources.
+ */
+ public boolean isCreatedFromStream(){
+ return this.createdFromStream;
+ }
+
+ /**
+ * Sets createdFromStream flag to the specified parameter.
+ * If parameter is true it means font peer was created from InputStream.
+ *
+ * @param value true, if font peer was created from InputStream
+ */
+ public void setCreatedFromStream(boolean value){
+ this.createdFromStream = value;
+ }
+
+ /**
+ * Returns font file name of this font.
+ */
+ public String getTempFontFileName(){
+ return this.tempFontFileName;
+ }
+
+ /**
+ * Sets font file name of this font to the specified one.
+ * @param value String representing font file name
+ */
+ public void setFontFileName(String value){
+ this.tempFontFileName = value;
+ }
+
+ /**
+ * Returns the advance width of the specified char of this FontPeerImpl.
+ * Note, if glyph is absent in the font's glyphset - returned value
+ * is the advance of the deafualt glyph. For escape-chars returned
+ * width value is 0.
+ *
+ * @param ch the char which width is to be returned
+ * @return the advance width of the specified char of this FontPeerImpl
+ */
+ public int charWidth(char ch) {
+ Paint p;
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ if(g == null) {
+ throw new RuntimeException("AndroidGraphics2D not instantiated!");
+ }
+ p = ((AndroidGraphics2D)g).getAndroidPaint();
+ char[] ca = {ch};
+ float[] fa = new float[1];
+ p.getTextWidths(ca, 0, 1, fa);
+ return (int)fa[0];
+ }
+
+ /**
+ * Returns the advance width of the specified char of this FontPeerImpl.
+ *
+ * @param ind the char which width is to be returned
+ * @return the advance width of the specified char of this FontPeerImpl
+ */
+ public int charWidth(int ind) {
+ return charWidth((char)ind);
+ }
+
+ /**
+ * Returns an array of Glyphs that represent characters from the specified
+ * Unicode range.
+ *
+ * @param uFirst start position in Unicode range
+ * @param uLast end position in Unicode range
+ * @return
+ */
+ public Glyph[] getGlyphs(char uFirst, char uLast) {
+
+ char i = uFirst;
+ int len = uLast - uFirst;
+ ArrayList<Glyph> lst = new ArrayList<Glyph>(len);
+
+ if (size < 0) {
+ // awt.09=min range bound value is greater than max range bound
+ throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$
+ }
+
+ while (i < uLast) {
+ lst.add(this.getGlyph(i));
+ }
+
+ return (Glyph[]) lst.toArray();
+ }
+
+ /**
+ * Returns an array of Glyphs representing given array of chars.
+ *
+ * @param chars specified array of chars
+ */
+ public Glyph[] getGlyphs(char[] chars) {
+ if (chars == null){
+ return null;
+ }
+
+ Glyph[] result = new Glyph[chars.length];
+
+ for (int i = 0; i < chars.length; i++) {
+ result[i] = this.getGlyph(chars[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array of Glyphs representing given string.
+ *
+ * @param str specified string
+ */
+ public Glyph[] getGlyphs(String str) {
+ char[] chars = str.toCharArray();
+ return this.getGlyphs(chars);
+ }
+
+ /**
+ * Returns family name of this FontPeerImpl.
+ */
+ public String getFamily() {
+ return fontFamilyName;
+ }
+
+ /**
+ * Returns face name of this FontPeerImpl.
+ */
+ public String getFontName() {
+ if (this.fontType == FontManager.FONT_TYPE_T1){
+ return this.fontFamilyName;
+ }
+
+ return faceName;
+ }
+
+ /**
+ * Returns height of this font peer in pixels.
+ */
+ public int getLogicalHeight() {
+ return logicalHeight;
+ }
+
+ /**
+ * Sets height of this font peer in pixels to the given value.
+ *
+ * @param newHeight new height in pixels value
+ */
+ public void setLogicalHeight(int newHeight) {
+ logicalHeight = newHeight;
+ }
+
+ /**
+ * Returns font size.
+ */
+ public int getSize() {
+ return size;
+ }
+
+ /**
+ * Returns font style.
+ */
+ public int getStyle() {
+ return style;
+ }
+
+ /**
+ * Returns font name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the bounds of the largest char in this FontPeerImpl in
+ * specified render context.
+ *
+ * @param frc specified FontRenderContext
+ */
+ public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
+ return maxCharBounds;
+ }
+
+ /**
+ * Returns the number of glyphs in this FontPeerImpl.
+ */
+ public int getNumGlyphs() {
+ return numGlyphs;
+ }
+
+ /**
+ * Returns tangens of the italic angle of this FontPeerImpl.
+ * If the FontPeerImpl has TrueType font type, italic angle value can be
+ * calculated as (CharSlopeRun / CharSlopeRise) in terms of GDI.
+ */
+ public float getItalicAngle() {
+ return italicAngle;
+ }
+
+ /**
+ * Returns height of this font peer.
+ */
+ public float getHeight(){
+ return height;
+ }
+
+ /**
+ * Returns cached LineMetrics object of this font peer.
+ */
+ public LineMetrics getLineMetrics(){
+ return nlm;
+ }
+
+ /**
+ * Returns native font handle of this font peer.
+ */
+ public long getFontHandle(){
+ return pFont;
+ }
+
+ /**
+ * Returns ascent of this font peer.
+ */
+ public int getAscent(){
+ Paint p;
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ if(g == null) {
+ throw new RuntimeException("AndroidGraphics2D not instantiated!");
+ }
+ p = ((AndroidGraphics2D)g).getAndroidPaint();
+ return (int)p.ascent();
+ //return ascent;
+ }
+
+ /**
+ * Returns descent of this font peer.
+ */
+ public int getDescent(){
+ return descent;
+ }
+
+ /**
+ * Returns leading of this font peer.
+ */
+ public int getLeading(){
+ return leading;
+ }
+
+ /**
+ * Returns true if this font peer has uniform line metrics.
+ */
+ public boolean hasUniformLineMetrics(){
+ return uniformLM;
+ }
+
+ /**
+ * Returns type of this font.
+ *
+ * @return one of constant font type values.
+ */
+ public int getFontType(){
+ return fontType;
+ }
+
+ /**
+ * Sets new font type to the font object.
+ *
+ * @param newType new type value
+ */
+ public void setFontType(int newType){
+ if (newType == FontManager.FONT_TYPE_T1 || newType == FontManager.FONT_TYPE_TT){
+ fontType = newType;
+ }
+ }
+
+ /**
+ * Sets new font type to the font object.
+ *
+ * @param newType new type value
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+
+ dispose();
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontProperty.java b/awt/org/apache/harmony/awt/gl/font/FontProperty.java
new file mode 100644
index 0000000..4eb7cbb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontProperty.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+
+/**
+ * Class containing font property information. This information can be found
+ * in font.property files. See API documentation, logical fonts description part.
+ *
+ */
+public class FontProperty {
+
+ // font file name
+ String fileName = null;
+
+ // name of the encoding to be used
+ String encoding = null;
+
+ // array of exclusion ranges (pairs of low and high unicode exclusion bounds)
+ int[] exclRange = null;
+
+ // font face name
+ String name = null;
+
+ // font style
+ int style = -1;
+
+ /**
+ * Returns font style of this font property.
+ */
+ public int getStyle(){
+ return this.style;
+ }
+
+ /**
+ * Returns font name of this font property.
+ */
+ public String getName(){
+ return this.name;
+ }
+
+ /**
+ * Returns encoding used in this font property.
+ */
+ public String getEncoding(){
+ return this.encoding;
+ }
+
+ /**
+ * Returns an array of exclusion ranges. This array contain pairs of
+ * low and high bounds of the intervals of characters to ignore in
+ * total Unicode characters range.
+ */
+ public int[] getExclusionRange(){
+ return this.exclRange;
+ }
+
+ /**
+ * Returns file name of the font that is described by this font property.
+ */
+ public String getFileName(){
+ return this.fileName;
+ }
+
+ /**
+ * Returns true if specified character covered by exclusion ranges of this
+ * font property, false otherwise.
+ *
+ * @param ch specified char to check
+ */
+ public boolean isCharExcluded(char ch){
+ if (exclRange == null ){
+ return false;
+ }
+
+ for (int i = 0; i < exclRange.length;){
+ int lb = exclRange[i++];
+ int hb = exclRange[i++];
+
+ if (ch >= lb && ch <= hb){
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/Glyph.java b/awt/org/apache/harmony/awt/gl/font/Glyph.java
new file mode 100644
index 0000000..44b8809
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/Glyph.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Shape;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.image.BufferedImage;
+
+public abstract class Glyph{
+
+ // character of the glyph
+ char glChar;
+
+ // precise glyph metrics
+ GlyphMetrics glMetrics;
+
+ // glyph metrics in pixels
+ GlyphMetrics glPointMetrics;
+
+ // glyph code of this Glyph
+ int glCode;
+
+ // justification info of this glyph
+ GlyphJustificationInfo glJustInfo;
+
+ // native font handle of the font corresponding to this glyph
+ long pFont;
+
+ // size of the font corresponding to this glyph
+ int fontSize;
+
+ // bitmap representation of the glyph
+ byte[] bitmap = null;
+
+ // Buffered image representation of the glyph
+ BufferedImage image;
+
+ // shape that representing the outline of this glyph
+ Shape glOutline = null;
+
+ /**
+ * image bitmap parameters
+ */
+
+ // top side bearing
+ public int bmp_top = 0;
+
+ // left side bearing
+ public int bmp_left = 0;
+
+ // number of bytes in row
+ public int bmp_pitch;
+
+ // number of rows
+ public int bmp_rows;
+
+ // width of the row
+ public int bmp_width;
+
+ /**
+ * Retruns handle to Native Font object
+ */
+ public long getPFont(){
+ return this.pFont;
+ }
+
+ /**
+ * Retruns char value of this glyph object
+ */
+ public char getChar(){
+ return glChar;
+ }
+
+ /**
+ * Retruns precise width of this glyph object
+ */
+ public int getWidth(){
+ return Math.round((float)glMetrics.getBounds2D().getWidth());
+ }
+
+ /**
+ * Retruns precise height of this glyph object
+ */
+ public int getHeight(){
+ return Math.round((float)glMetrics.getBounds2D().getHeight());
+ }
+
+ /**
+ * Retruns glyph code of this glyph object
+ */
+ public int getGlyphCode(){
+ return glCode;
+ }
+
+ /**
+ * Retruns GlyphMetrics of this glyph object with precise metrics.
+ */
+ public GlyphMetrics getGlyphMetrics(){
+ return glMetrics;
+ }
+
+ /**
+ * Retruns GlyphMetrics of this glyph object in pixels.
+ */
+ public GlyphMetrics getGlyphPointMetrics(){
+ return glPointMetrics;
+ }
+
+ /**
+ * Retruns GlyphJustificationInfo of this glyph object
+ */
+ public GlyphJustificationInfo getGlyphJustificationInfo(){
+ return glJustInfo;
+ }
+
+ /**
+ * Sets JustificationInfo of this glyph object
+ *
+ * @param newJustInfo GlyphJustificationInfo object to set to the Glyph object
+ */
+ public void setGlyphJustificationInfo(GlyphJustificationInfo newJustInfo){
+ this.glJustInfo = newJustInfo;
+ }
+
+ /**
+ * Returns an int array of 3 elements, so-called ABC structure that contains
+ * the width of the character:
+ * 1st element = left side bearing of the glyph
+ * 2nd element = width of the glyph
+ * 3d element = right side bearing of the glyph
+ */
+ public int[] getABC(){
+ int[] abc = new int[3];
+ abc[0] = (int)glMetrics.getLSB();
+ abc[1] = (int)glMetrics.getBounds2D().getWidth();
+ abc[2] = (int)glMetrics.getRSB();
+
+ return abc;
+ }
+
+ /**
+ * Sets BufferedImage representation of this glyph to the specified parameter.
+ *
+ * @param newImage new BufferedImage object to be set as BufferedImage
+ * representation.
+ */
+ public void setImage(BufferedImage newImage){
+ this.image = newImage;
+ }
+
+ /**
+ * Returns true if this Glyph and specified object are equal.
+ */
+ @Override
+ public boolean equals(Object obj){
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null) {
+ try {
+ Glyph gl = (Glyph)obj;
+
+ return ((this.getChar() == gl.getChar())
+ && (this.getGlyphMetrics().equals(gl.getGlyphMetrics()))
+ && (this.getGlyphCode() == gl.getGlyphCode()));
+ } catch (ClassCastException e) {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns height of the glyph in points.
+ */
+ public int getPointHeight(){
+ return (int)glPointMetrics.getBounds2D().getHeight();
+ }
+
+ /**
+ * Returns width of the glyph in points.
+ */
+ public int getPointWidth(){
+ return (int)glPointMetrics.getBounds2D().getWidth();
+ }
+
+ public Shape getShape(){
+ if (glOutline == null){
+ glOutline = initOutline(this.glChar);
+ }
+ return glOutline;
+ }
+
+ /**
+ * Sets BufferedImage representation of this glyph.
+ */
+ public BufferedImage getImage(){
+ //!! Implementation classes must override this method
+ return null;
+ }
+
+ /**
+ * Returns array of bytes, representing image of this glyph
+ */
+ public abstract byte[] getBitmap();
+
+ /**
+ * Returns shape that represents outline of the specified character.
+ *
+ * @param c specified character
+ */
+ public abstract Shape initOutline(char c);
+
+}
+
+
diff --git a/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java b/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
new file mode 100644
index 0000000..370146d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
@@ -0,0 +1,412 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ *
+ * LineMetrics implementation class.
+ */
+
+public class LineMetricsImpl extends LineMetrics implements Cloneable{
+
+ // array of baseline offsets
+ float[] baselineOffsets;
+
+ // the number of characters to measure
+ int numChars;
+
+ // baseline index of the font corresponding to this line metrics
+ int baseLineIndex;
+
+ // underline thickness
+ float underlineThickness;
+
+ // underline offset
+ float underlineOffset;
+
+ // strikethrough thickness
+ float strikethroughThickness;
+
+ // strikethrough offset
+ float strikethroughOffset;
+
+ // External leading
+ float leading;
+
+ // Height of the font ( == (ascent+descent+leading))
+ float height;
+
+ // Ascent of the font
+ float ascent;
+
+ // Descent of the font
+ float descent;
+
+ // Width of the widest char in the font
+ float maxCharWidth;
+
+ // underline thickness (in pixels)
+ int lUnderlineThickness;
+
+ // underline offset (in pixels)
+ int lUnderlineOffset;
+
+ // strikethrough thickness (in pixels)
+ int lStrikethroughThickness;
+
+ // strikethrough offset (in pixels)
+ int lStrikethroughOffset;
+
+ // External leading (in pixels)
+ int lLeading;
+
+ // Height of the font ( == (ascent+descent+leading)) (in pixels)
+ int lHeight;
+
+ // Ascent of the font (in pixels)
+ int lAscent;
+
+ // Descent of the font (in pixels)
+ int lDescent;
+
+ // Width of the widest char in the font (in pixels)
+ int lMaxCharWidth;
+
+ // units per EM square in font value
+ int units_per_EM = 0;
+
+ /**
+ * Creates LineMetricsImpl object from specified parameters. If baseline data parameter
+ * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets.
+ *
+ * @param len a number of characters
+ * @param metrics an array of 16 elements with metrics values that can be
+ * initialized in native code.<p>
+ * metrics[0] - ascent<p>
+ * metrics[1] - descent<p>
+ * metrics[2] - external leading<p>
+ * metrics[3] - underline thickness<p>
+ * -metrics[4] - underline offset<p>
+ * metrics[5] - strikethrough thickness<p>
+ * -metrics[6] - strikethrough offset<p>
+ * metrics[7] - maximum char width<p>
+ * metrics[8] - ascent in pixels<p>
+ * metrics[9] - descent in pixles<p>
+ * metrics[10] - external leading in pixels<p>
+ * metrics[11] - underline thickness in pixels<p>
+ * -metrics[12] - underline offset in pixels<p>
+ * metrics[13] - strikethrough thickness in pixels<p>
+ * -metrics[14] - strikethrough offset in pixels<p>
+ * metrics[15] - maximum char width in pixels<p>
+
+ * @param _baselineData an array of 3 elements with baseline offsets metrics<p>
+ * _baselineData[0] - roman baseline offset<p>
+ * _baselineData[1] - center baseline offset<p>
+ * _baselineData[2] - hanging baseline offset<p>
+ */
+ public LineMetricsImpl(int len, float[] metrics, float[] _baselineData){
+ numChars = len;
+
+ ascent = metrics[0]; // Ascent of the font
+ descent = metrics[1]; // Descent of the font
+ leading = metrics[2]; // External leading
+ height = metrics[0] + metrics[1] + metrics[2]; // Height of the font ( == (ascent + descent + leading))
+ }
+
+ /**
+ * Creates LineMetricsImpl object from specified parameters. If baseline data parameter
+ * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets.
+ *
+ * @param _numChars number of chars
+ * @param _baseLineIndex index of the baseline offset
+ * @param _baselineOffsets an array of baseline offsets
+ * @param _underlineThickness underline thickness
+ * @param _underlineOffset underline offset
+ * @param _strikethroughThickness strikethrough thickness
+ * @param _strikethroughOffset strinkethrough offset
+ * @param _leading leading of the font
+ * @param _height font height
+ * @param _ascent ascent of the font
+ * @param _descent descent of the font
+ * @param _maxCharWidth max char width
+ */
+ public LineMetricsImpl(int _numChars, int _baseLineIndex,
+ float[] _baselineOffsets, float _underlineThickness,
+ float _underlineOffset, float _strikethroughThickness,
+ float _strikethroughOffset, float _leading, float _height,
+ float _ascent, float _descent, float _maxCharWidth) {
+
+ numChars = _numChars;
+ baseLineIndex = _baseLineIndex;
+ underlineThickness = _underlineThickness;
+ underlineOffset = _underlineOffset;
+ strikethroughThickness = _strikethroughThickness;
+ strikethroughOffset = _strikethroughOffset;
+ leading = _leading;
+ height = _height;
+ ascent = _ascent;
+ descent = _descent;
+ baselineOffsets = _baselineOffsets;
+ lUnderlineThickness = (int) underlineThickness;
+ lUnderlineOffset = (int) underlineOffset;
+ lStrikethroughThickness = (int) strikethroughThickness;
+ lStrikethroughOffset = (int) strikethroughOffset;
+ lLeading = (int) leading;
+ lHeight = (int) height;
+ lAscent = (int) ascent;
+ lDescent = (int) descent;
+ maxCharWidth = _maxCharWidth;
+ }
+
+ public LineMetricsImpl(){
+
+ }
+
+ /**
+ * All metrics are scaled according to scaleX and scaleY values.
+ * This function helps to recompute metrics according to the scale factors
+ * of desired AffineTransform.
+ *
+ * @param scaleX scale X factor
+ * @param scaleY scale Y factor
+ */
+ public void scale(float scaleX, float scaleY){
+ float absScaleX = Math.abs(scaleX);
+ float absScaleY = Math.abs(scaleY);
+
+ underlineThickness *= absScaleY;
+ underlineOffset *= scaleY;
+ strikethroughThickness *= absScaleY;
+ strikethroughOffset *= scaleY;
+ leading *= absScaleY;
+ height *= absScaleY;
+ ascent *= absScaleY;
+ descent *= absScaleY;
+
+ if(baselineOffsets == null) {
+ getBaselineOffsets();
+ }
+
+ for (int i=0; i< baselineOffsets.length; i++){
+ baselineOffsets[i] *= scaleY;
+ }
+
+ lUnderlineThickness *= absScaleY;
+ lUnderlineOffset *= scaleY;
+ lStrikethroughThickness *= absScaleY;
+ lStrikethroughOffset *= scaleY;
+ lLeading *= absScaleY;
+ lHeight *= absScaleY;
+ lAscent *= absScaleY;
+ lDescent *= absScaleY;
+ maxCharWidth *= absScaleX;
+
+ }
+
+
+ /**
+ * Returns offset of the baseline.
+ */
+ @Override
+ public float[] getBaselineOffsets() {
+ // XXX: at the moment there only horizontal metrics are taken into
+ // account. If there is no baseline information in TrueType font
+ // file default values used: {0, -ascent, (-ascent+descent)/2}
+
+ return baselineOffsets;
+ }
+
+ /**
+ * Returns a number of chars in specified text
+ */
+ @Override
+ public int getNumChars() {
+ return numChars;
+ }
+
+ /**
+ * Returns index of the baseline, one of predefined constants.
+ */
+ @Override
+ public int getBaselineIndex() {
+ // Baseline index is the deafult baseline index value
+ // taken from the TrueType table "BASE".
+ return baseLineIndex;
+ }
+
+ /**
+ * Returns thickness of the Underline.
+ */
+ @Override
+ public float getUnderlineThickness() {
+ return underlineThickness;
+ }
+
+ /**
+ * Returns offset of the Underline.
+ */
+ @Override
+ public float getUnderlineOffset() {
+ return underlineOffset;
+ }
+
+ /**
+ * Returns thickness of the Strikethrough line.
+ */
+ @Override
+ public float getStrikethroughThickness() {
+ return strikethroughThickness;
+ }
+
+ /**
+ * Returns offset of the Strikethrough line.
+ */
+ @Override
+ public float getStrikethroughOffset() {
+ return strikethroughOffset;
+ }
+
+ /**
+ * Returns the leading.
+ */
+ @Override
+ public float getLeading() {
+ return leading;
+ }
+
+ /**
+ * Returns the height of the font.
+ */
+ @Override
+ public float getHeight() {
+ //return height; // equals to (ascent + descent + leading);
+ return ascent + descent + leading;
+ }
+
+ /**
+ * Returns the descent.
+ */
+ @Override
+ public float getDescent() {
+ return descent;
+ }
+
+ /**
+ * Returns the ascent.
+ */
+ @Override
+ public float getAscent() {
+ return ascent;
+ }
+
+ /**
+ * Returns logical thickness of the Underline.
+ */
+ public int getLogicalUnderlineThickness() {
+ return lUnderlineThickness;
+ }
+
+ /**
+ * Returns logical offset of the Underline.
+ */
+ public int getLogicalUnderlineOffset() {
+ return lUnderlineOffset;
+ }
+
+ /**
+ * Returns logical thickness of the Strikethrough line.
+ */
+ public int getLogicalStrikethroughThickness() {
+ return lStrikethroughThickness;
+ }
+
+ /**
+ * Returns logical offset of the Strikethrough line.
+ */
+ public int getLogicalStrikethroughOffset() {
+ return lStrikethroughOffset;
+ }
+
+ /**
+ * Returns the logical leading.
+ */
+ public int getLogicalLeading() {
+ return lLeading;
+ }
+
+ /**
+ * Returns the logical height of the font.
+ */
+ public int getLogicalHeight() {
+ return lHeight; // equals to (ascent + descent + leading);
+ }
+
+ /**
+ * Returns the logical descent.
+ */
+ public int getLogicalDescent() {
+ return lDescent;
+ }
+
+ /**
+ * Returns the logical ascent.
+ */
+ public int getLogicalAscent() {
+ return lAscent;
+ }
+
+ /**
+ * Returns the logical size of the widest char.
+ */
+ public int getLogicalMaxCharWidth() {
+ return lMaxCharWidth;
+ }
+
+ /**
+ * Returns the size of the widest char.
+ */
+ public float getMaxCharWidth() {
+ return maxCharWidth;
+ }
+
+ /**
+ * Set num chars to the desired value.
+ *
+ * @param num specified number of chars
+ */
+ public void setNumChars(int num){
+ numChars = num;
+ }
+
+ @Override
+ public Object clone(){
+ try{
+ return super.clone();
+ }catch (CloneNotSupportedException e){
+ return null;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/font/TextDecorator.java b/awt/org/apache/harmony/awt/gl/font/TextDecorator.java
new file mode 100644
index 0000000..81905fd
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextDecorator.java
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.TextAttribute;
+import java.awt.geom.Area;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Map;
+
+/**
+ * This class is responsible for rendering text decorations like
+ * underline, strikethrough, text with background, etc.
+ */
+public class TextDecorator {
+ private static final TextDecorator inst = new TextDecorator();
+ private TextDecorator() {}
+ static TextDecorator getInstance() {
+ return inst;
+ }
+
+ /**
+ * This class encapsulates a set of decoration attributes for a single text run.
+ */
+ static class Decoration {
+ private static final BasicStroke UNDERLINE_LOW_ONE_PIXEL_STROKE =
+ new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10);
+
+ private static final BasicStroke UNDERLINE_LOW_TWO_PIXEL_STROKE =
+ new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10);
+
+ private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE =
+ new BasicStroke(
+ 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+ new float[] { 1, 1 }, 0
+ );
+
+ private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE2 =
+ new BasicStroke(
+ 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+ new float[] { 1, 1 }, 1
+ );
+
+ private static final BasicStroke UNDERLINE_LOW_DASHED_STROKE =
+ new BasicStroke(
+ 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+ new float[] { 4, 4 }, 0
+ );
+
+ boolean ulOn = false; // Have standard underline?
+ BasicStroke ulStroke;
+
+ BasicStroke imUlStroke; // Stroke for INPUT_METHOD_UNDERLINE
+ BasicStroke imUlStroke2; // Specially for UNDERLINE_LOW_GRAY
+
+ boolean strikeThrough;
+ BasicStroke strikeThroughStroke;
+
+ boolean haveStrokes = false; // Strokes already created?
+
+ boolean swapBfFg;
+ Paint bg; // background color
+ Paint fg; // foreground color
+
+ Paint graphicsPaint; // Slot for saving current paint
+
+ Decoration(
+ Integer imUl,
+ boolean swap,
+ boolean sth,
+ Paint bg, Paint fg,
+ boolean ulOn) {
+
+ if (imUl != null) {
+ // Determine which stroke to use
+ if (imUl == TextAttribute.UNDERLINE_LOW_ONE_PIXEL) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_ONE_PIXEL_STROKE;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_TWO_PIXEL) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_TWO_PIXEL_STROKE;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_DOTTED) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_GRAY) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE;
+ this.imUlStroke2 = Decoration.UNDERLINE_LOW_DOTTED_STROKE2;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_DASHED) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_DASHED_STROKE;
+ }
+ }
+
+ this.ulOn = ulOn; // Has underline
+ this.swapBfFg = swap;
+ this.strikeThrough = sth;
+ this.bg = bg;
+ this.fg = fg;
+ }
+
+ /**
+ * Creates strokes of proper width according to the info
+ * stored in the BasicMetrics
+ * @param metrics - basic metrics
+ */
+ private void getStrokes(BasicMetrics metrics) {
+ if (!haveStrokes) {
+ if (strikeThrough) {
+ strikeThroughStroke =
+ new BasicStroke(
+ metrics.strikethroughThickness,
+ BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_MITER,
+ 10
+ );
+ }
+
+ if (ulOn) {
+ ulStroke =
+ new BasicStroke(
+ metrics.underlineThickness,
+ BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_MITER,
+ 10
+ );
+ }
+
+ haveStrokes = true;
+ }
+ }
+ }
+
+ /**
+ * Creates Decoration object from the set of text attributes
+ * @param attributes - text attributes
+ * @return Decoration object
+ */
+ static Decoration getDecoration(Map<? extends Attribute, ?> attributes) {
+ if (attributes == null) {
+ return null; // It is for plain text
+ }
+
+ Object underline = attributes.get(TextAttribute.UNDERLINE);
+ boolean hasStandardUnderline = underline == TextAttribute.UNDERLINE_ON;
+
+ Object imUnderline = attributes.get(TextAttribute.INPUT_METHOD_UNDERLINE);
+ Integer imUl = (Integer) imUnderline;
+
+ boolean swapBgFg =
+ TextAttribute.SWAP_COLORS_ON.equals(
+ attributes.get(TextAttribute.SWAP_COLORS)
+ );
+
+ boolean strikeThrough =
+ TextAttribute.STRIKETHROUGH_ON.equals(
+ attributes.get(TextAttribute.STRIKETHROUGH)
+ );
+
+ Paint fg = (Paint) attributes.get(TextAttribute.FOREGROUND);
+ Paint bg = (Paint) attributes.get(TextAttribute.BACKGROUND);
+
+ if (
+ !hasStandardUnderline &&
+ imUnderline == null &&
+ fg == null &&
+ bg == null &&
+ !swapBgFg &&
+ !strikeThrough
+ ) {
+ return null;
+ }
+ return new Decoration(imUl, swapBgFg, strikeThrough, bg, fg, hasStandardUnderline);
+ }
+
+ /**
+ * Fills the background before drawing if needed.
+ *
+ * @param trs - text segment
+ * @param g2d - graphics to draw to
+ * @param xOffset - offset in X direction to the upper left corner of the
+ * layout from the origin of the graphics
+ * @param yOffset - offset in Y direction to the upper left corner of the
+ * layout from the origin of the graphics
+ */
+ static void prepareGraphics(
+ TextRunSegment trs, Graphics2D g2d,
+ float xOffset, float yOffset
+ ) {
+ Decoration d = trs.decoration;
+
+ if (d.fg == null && d.bg == null && d.swapBfFg == false) {
+ return; // Nothing to do
+ }
+
+ d.graphicsPaint = g2d.getPaint();
+
+ if (d.fg == null) {
+ d.fg = d.graphicsPaint;
+ }
+
+ if (d.swapBfFg) {
+ // Fill background area
+ g2d.setPaint(d.fg);
+ Rectangle2D bgArea = trs.getLogicalBounds();
+ Rectangle2D toFill =
+ new Rectangle2D.Double(
+ bgArea.getX() + xOffset,
+ bgArea.getY() + yOffset,
+ bgArea.getWidth(),
+ bgArea.getHeight()
+ );
+ g2d.fill(toFill);
+
+ // Set foreground color
+ g2d.setPaint(d.bg == null ? Color.WHITE : d.bg);
+ } else {
+ if (d.bg != null) { // Fill background area
+ g2d.setPaint(d.bg);
+ Rectangle2D bgArea = trs.getLogicalBounds();
+ Rectangle2D toFill =
+ new Rectangle2D.Double(
+ bgArea.getX() + xOffset,
+ bgArea.getY() + yOffset,
+ bgArea.getWidth(),
+ bgArea.getHeight()
+ );
+ g2d.fill(toFill);
+ }
+
+ // Set foreground color
+ g2d.setPaint(d.fg);
+ }
+ }
+
+ /**
+ * Restores the original state of the graphics if needed
+ * @param d - decoration
+ * @param g2d - graphics
+ */
+ static void restoreGraphics(Decoration d, Graphics2D g2d) {
+ if (d.fg == null && d.bg == null && d.swapBfFg == false) {
+ return; // Nothing to do
+ }
+
+ g2d.setPaint(d.graphicsPaint);
+ }
+
+ /**
+ * Renders the text decorations
+ * @param trs - text run segment
+ * @param g2d - graphics to render to
+ * @param xOffset - offset in X direction to the upper left corner
+ * of the layout from the origin of the graphics
+ * @param yOffset - offset in Y direction to the upper left corner
+ * of the layout from the origin of the graphics
+ */
+ static void drawTextDecorations(
+ TextRunSegment trs, Graphics2D g2d,
+ float xOffset, float yOffset
+ ) {
+ Decoration d = trs.decoration;
+
+ if (!d.ulOn && d.imUlStroke == null && !d.strikeThrough) {
+ return; // Nothing to do
+ }
+
+ float left = xOffset + (float) trs.getLogicalBounds().getMinX();
+ float right = xOffset + (float) trs.getLogicalBounds().getMaxX();
+
+ Stroke savedStroke = g2d.getStroke();
+
+ d.getStrokes(trs.metrics);
+
+ if (d.strikeThrough) {
+ float y = trs.y + yOffset + trs.metrics.strikethroughOffset;
+ g2d.setStroke(d.strikeThroughStroke);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ }
+
+ if (d.ulOn) {
+ float y = trs.y + yOffset + trs.metrics.underlineOffset;
+ g2d.setStroke(d.ulStroke);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ }
+
+ if (d.imUlStroke != null) {
+ float y = trs.y + yOffset + trs.metrics.underlineOffset;
+ g2d.setStroke(d.imUlStroke);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ if (d.imUlStroke2 != null) {
+ y++;
+ g2d.setStroke(d.imUlStroke2);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ }
+ }
+
+ g2d.setStroke(savedStroke);
+ }
+
+ /**
+ * Extends the visual bounds of the text run segment to
+ * include text decorations.
+ * @param trs - text segment
+ * @param segmentBounds - bounds of the undecorated text
+ * @param d - decoration
+ * @return extended bounds
+ */
+ static Rectangle2D extendVisualBounds(
+ TextRunSegment trs,
+ Rectangle2D segmentBounds,
+ Decoration d
+ ) {
+ if (d == null) {
+ return segmentBounds;
+ }
+ double minx = segmentBounds.getMinX();
+ double miny = segmentBounds.getMinY();
+ double maxx = segmentBounds.getMaxX();
+ double maxy = segmentBounds.getMaxY();
+
+ Rectangle2D lb = trs.getLogicalBounds();
+
+ if (d.swapBfFg || d.bg != null) {
+ minx = Math.min(lb.getMinX() - trs.x, minx);
+ miny = Math.min(lb.getMinY() - trs.y, miny);
+ maxx = Math.max(lb.getMaxX() - trs.x, maxx);
+ maxy = Math.max(lb.getMaxY() - trs.y, maxy);
+ }
+
+ if (d.ulOn || d.imUlStroke != null || d.strikeThrough) {
+ minx = Math.min(lb.getMinX() - trs.x, minx);
+ maxx = Math.max(lb.getMaxX() - trs.x, maxx);
+
+ d.getStrokes(trs.metrics);
+
+ if (d.ulStroke != null) {
+ maxy = Math.max(
+ maxy,
+ trs.metrics.underlineOffset +
+ d.ulStroke.getLineWidth()
+ );
+ }
+
+ if (d.imUlStroke != null) {
+ maxy = Math.max(
+ maxy,
+ trs.metrics.underlineOffset +
+ d.imUlStroke.getLineWidth() +
+ (d.imUlStroke2 == null ? 0 : d.imUlStroke2.getLineWidth())
+ );
+ }
+ }
+
+ return new Rectangle2D.Double(minx, miny, maxx-minx, maxy-miny);
+ }
+
+ /**
+ * Extends the outline of the text run segment to
+ * include text decorations.
+ * @param trs - text segment
+ * @param segmentOutline - outline of the undecorated text
+ * @param d - decoration
+ * @return extended outline
+ */
+ static Shape extendOutline(
+ TextRunSegment trs,
+ Shape segmentOutline,
+ Decoration d
+ ) {
+ if (d == null || !d.ulOn && d.imUlStroke == null && !d.strikeThrough) {
+ return segmentOutline; // Nothing to do
+ }
+
+ Area res = new Area(segmentOutline);
+
+ float left = (float) trs.getLogicalBounds().getMinX() - trs.x;
+ float right = (float) trs.getLogicalBounds().getMaxX() - trs.x;
+
+ d.getStrokes(trs.metrics);
+
+ if (d.strikeThrough) {
+ float y = trs.metrics.strikethroughOffset;
+ res.add(new Area(d.strikeThroughStroke.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+ }
+
+ if (d.ulOn) {
+ float y = trs.metrics.underlineOffset;
+ res.add(new Area(d.ulStroke.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+ }
+
+ if (d.imUlStroke != null) {
+ float y = trs.metrics.underlineOffset;
+ res.add(new Area(d.imUlStroke.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+
+ if (d.imUlStroke2 != null) {
+ y++;
+ res.add(new Area(d.imUlStroke2.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
new file mode 100644
index 0000000..be5762a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.Font;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class operates with an arbitrary text string which can include
+ * any number of style, font and direction runs. It is responsible for computation
+ * of the text metrics, such as ascent, descent, leading and advance. Actually,
+ * each text run segment contains logic which allows it to compute its own metrics and
+ * responsibility of this class is to combine metrics for all segments included in the text,
+ * managed by the associated TextRunBreaker object.
+ */
+public class TextMetricsCalculator {
+ TextRunBreaker breaker; // Associated run breaker
+
+ // Metrics
+ float ascent = 0;
+ float descent = 0;
+ float leading = 0;
+ float advance = 0;
+
+ private float baselineOffsets[];
+ int baselineIndex;
+
+ public TextMetricsCalculator(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ checkBaselines();
+ }
+
+ /**
+ * Returns either values cached by checkBaselines method or reasonable
+ * values for the TOP and BOTTOM alignments.
+ * @param baselineIndex - baseline index
+ * @return baseline offset
+ */
+ float getBaselineOffset(int baselineIndex) {
+ if (baselineIndex >= 0) {
+ return baselineOffsets[baselineIndex];
+ } else if (baselineIndex == GraphicAttribute.BOTTOM_ALIGNMENT) {
+ return descent;
+ } else if (baselineIndex == GraphicAttribute.TOP_ALIGNMENT) {
+ return -ascent;
+ } else {
+ // awt.3F=Invalid baseline index
+ throw new IllegalArgumentException(Messages.getString("awt.3F")); //$NON-NLS-1$
+ }
+ }
+
+ public float[] getBaselineOffsets() {
+ float ret[] = new float[baselineOffsets.length];
+ System.arraycopy(baselineOffsets, 0, ret, 0, baselineOffsets.length);
+ return ret;
+ }
+
+ /**
+ * Take baseline offsets from the first font or graphic attribute
+ * and normalizes them, than caches the results.
+ */
+ public void checkBaselines() {
+ // Take baseline offsets of the first font and normalize them
+ HashMap<Integer, Font> fonts = breaker.fonts;
+
+ Object val = fonts.get(new Integer(0));
+
+ if (val instanceof Font) {
+ Font firstFont = (Font) val;
+ LineMetrics lm = firstFont.getLineMetrics(breaker.text, 0, 1, breaker.frc);
+ baselineOffsets = lm.getBaselineOffsets();
+ baselineIndex = lm.getBaselineIndex();
+ } else if (val instanceof GraphicAttribute) {
+ // Get first graphic attribute and use it
+ GraphicAttribute ga = (GraphicAttribute) val;
+
+ int align = ga.getAlignment();
+
+ if (
+ align == GraphicAttribute.TOP_ALIGNMENT ||
+ align == GraphicAttribute.BOTTOM_ALIGNMENT
+ ) {
+ baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+ } else {
+ baselineIndex = align;
+ }
+
+ baselineOffsets = new float[3];
+ baselineOffsets[0] = 0;
+ baselineOffsets[1] = (ga.getDescent() - ga.getAscent()) / 2.f;
+ baselineOffsets[2] = -ga.getAscent();
+ } else { // Use defaults - Roman baseline and zero offsets
+ baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+ baselineOffsets = new float[3];
+ }
+
+ // Normalize offsets if needed
+ if (baselineOffsets[baselineIndex] != 0) {
+ float baseOffset = baselineOffsets[baselineIndex];
+ for (int i = 0; i < baselineOffsets.length; i++) {
+ baselineOffsets[i] -= baseOffset;
+ }
+ }
+ }
+
+ /**
+ * Computes metrics for the text managed by the associated TextRunBreaker
+ */
+ void computeMetrics() {
+
+ ArrayList<TextRunSegment> segments = breaker.runSegments;
+
+ float maxHeight = 0;
+ float maxHeightLeading = 0;
+
+ for (int i = 0; i < segments.size(); i++) {
+ TextRunSegment segment = segments.get(i);
+ BasicMetrics metrics = segment.metrics;
+ int baseline = metrics.baseLineIndex;
+
+ if (baseline >= 0) {
+ float baselineOffset = baselineOffsets[metrics.baseLineIndex];
+ float fixedDescent = metrics.descent + baselineOffset;
+
+ ascent = Math.max(ascent, metrics.ascent - baselineOffset);
+ descent = Math.max(descent, fixedDescent);
+ leading = Math.max(leading, fixedDescent + metrics.leading);
+ } else { // Position is not fixed by the baseline, need sum of ascent and descent
+ float height = metrics.ascent + metrics.descent;
+
+ maxHeight = Math.max(maxHeight, height);
+ maxHeightLeading = Math.max(maxHeightLeading, height + metrics.leading);
+ }
+ }
+
+ // Need to increase sizes for graphics?
+ if (maxHeightLeading != 0) {
+ descent = Math.max(descent, maxHeight - ascent);
+ leading = Math.max(leading, maxHeightLeading - ascent);
+ }
+
+ // Normalize leading
+ leading -= descent;
+
+ BasicMetrics currMetrics;
+ float currAdvance = 0;
+
+ for (int i = 0; i < segments.size(); i++) {
+ TextRunSegment segment = segments.get(breaker.getSegmentFromVisualOrder(i));
+ currMetrics = segment.metrics;
+
+ segment.y = getBaselineOffset(currMetrics.baseLineIndex)
+ + currMetrics.superScriptOffset;
+ segment.x = currAdvance;
+
+ currAdvance += segment.getAdvance();
+ }
+
+ advance = currAdvance;
+ }
+
+ /**
+ * Computes metrics and creates BasicMetrics object from them
+ * @return basic metrics
+ */
+ public BasicMetrics createMetrics() {
+ computeMetrics();
+ return new BasicMetrics(this);
+ }
+
+ /**
+ * Corrects advance after justification. Gets BasicMetrics object
+ * and updates advance stored into it.
+ * @param metrics - metrics with outdated advance which should be corrected
+ */
+ public void correctAdvance(BasicMetrics metrics) {
+ ArrayList<TextRunSegment> segments = breaker.runSegments;
+ TextRunSegment segment = segments.get(breaker
+ .getSegmentFromVisualOrder(segments.size() - 1));
+
+ advance = segment.x + segment.getAdvance();
+ metrics.advance = advance;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java b/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
new file mode 100644
index 0000000..be606f7
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
@@ -0,0 +1,861 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.awt.im.InputMethodHighlight;
+import java.awt.font.*;
+import java.awt.*;
+import java.text.AttributedCharacterIterator;
+import java.text.Annotation;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.*;
+
+import org.apache.harmony.awt.gl.font.TextDecorator.Decoration;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+// TODO - bidi not implemented yet
+
+/**
+ * This class is responsible for breaking the text into the run segments
+ * with constant font, style, other text attributes and direction.
+ * It also stores the created text run segments and covers functionality
+ * related to the operations on the set of segments, like calculating metrics,
+ * rendering, justification, hit testing, etc.
+ */
+public class TextRunBreaker implements Cloneable {
+ AttributedCharacterIterator aci;
+ FontRenderContext frc;
+
+ char[] text;
+
+ byte[] levels;
+
+ HashMap<Integer, Font> fonts;
+ HashMap<Integer, Decoration> decorations;
+
+ // Related to default font substitution
+ int forcedFontRunStarts[];
+
+ ArrayList<TextRunSegment> runSegments = new ArrayList<TextRunSegment>();
+
+ // For fast retrieving of the segment containing
+ // character with known logical index
+ int logical2segment[];
+ int segment2visual[]; // Visual order of segments TODO - implement
+ int visual2segment[];
+ int logical2visual[];
+ int visual2logical[];
+
+ SegmentsInfo storedSegments;
+ private boolean haveAllSegments = false;
+ int segmentsStart, segmentsEnd;
+
+ float justification = 1.0f;
+
+ public TextRunBreaker(AttributedCharacterIterator aci, FontRenderContext frc) {
+ this.aci = aci;
+ this.frc = frc;
+
+ segmentsStart = aci.getBeginIndex();
+ segmentsEnd = aci.getEndIndex();
+
+ int len = segmentsEnd - segmentsStart;
+ text = new char[len];
+ aci.setIndex(segmentsEnd);
+ while (len-- != 0) { // Going in backward direction is faster? Simplier checks here?
+ text[len] = aci.previous();
+ }
+
+ createStyleRuns();
+ }
+
+ /**
+ * Visual order of text segments may differ from the logical order.
+ * This method calculates visual position of the segment from its logical position.
+ * @param segmentNum - logical position of the segment
+ * @return visual position of the segment
+ */
+ int getVisualFromSegmentOrder(int segmentNum) {
+ return (segment2visual == null) ? segmentNum : segment2visual[segmentNum];
+ }
+
+ /**
+ * Visual order of text segments may differ from the logical order.
+ * This method calculates logical position of the segment from its visual position.
+ * @param visual - visual position of the segment
+ * @return logical position of the segment
+ */
+ int getSegmentFromVisualOrder(int visual) {
+ return (visual2segment == null) ? visual : visual2segment[visual];
+ }
+
+ /**
+ * Visual order of the characters may differ from the logical order.
+ * This method calculates visual position of the character from its logical position.
+ * @param logical - logical position of the character
+ * @return visual position
+ */
+ int getVisualFromLogical(int logical) {
+ return (logical2visual == null) ? logical : logical2visual[logical];
+ }
+
+ /**
+ * Visual order of the characters may differ from the logical order.
+ * This method calculates logical position of the character from its visual position.
+ * @param visual - visual position
+ * @return logical position
+ */
+ int getLogicalFromVisual(int visual) {
+ return (visual2logical == null) ? visual : visual2logical[visual];
+ }
+
+ /**
+ * Calculates the end index of the level run, limited by the given text run.
+ * @param runStart - run start
+ * @param runEnd - run end
+ * @return end index of the level run
+ */
+ int getLevelRunLimit(int runStart, int runEnd) {
+ if (levels == null) {
+ return runEnd;
+ }
+ int endLevelRun = runStart + 1;
+ byte level = levels[runStart];
+
+ while (endLevelRun <= runEnd && levels[endLevelRun] == level) {
+ endLevelRun++;
+ }
+
+ return endLevelRun;
+ }
+
+ /**
+ * Adds InputMethodHighlight to the attributes
+ * @param attrs - text attributes
+ * @return patched text attributes
+ */
+ Map<? extends Attribute, ?> unpackAttributes(Map<? extends Attribute, ?> attrs) {
+ if (attrs.containsKey(TextAttribute.INPUT_METHOD_HIGHLIGHT)) {
+ Map<TextAttribute, ?> styles = null;
+
+ Object val = attrs.get(TextAttribute.INPUT_METHOD_HIGHLIGHT);
+
+ if (val instanceof Annotation) {
+ val = ((Annotation) val).getValue();
+ }
+
+ if (val instanceof InputMethodHighlight) {
+ InputMethodHighlight ihl = ((InputMethodHighlight) val);
+ styles = ihl.getStyle();
+
+ if (styles == null) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ styles = tk.mapInputMethodHighlight(ihl);
+ }
+ }
+
+ if (styles != null) {
+ HashMap<Attribute, Object> newAttrs = new HashMap<Attribute, Object>();
+ newAttrs.putAll(attrs);
+ newAttrs.putAll(styles);
+ return newAttrs;
+ }
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Breaks the text into separate style runs.
+ */
+ void createStyleRuns() {
+ // TODO - implement fast and simple case
+ fonts = new HashMap<Integer, Font>();
+ decorations = new HashMap<Integer, Decoration>();
+ ////
+
+ ArrayList<Integer> forcedFontRunStartsList = null;
+
+ Map<? extends Attribute, ?> attributes = null;
+
+ // Check justification attribute
+ Object val = aci.getAttribute(TextAttribute.JUSTIFICATION);
+ if (val != null) {
+ justification = ((Float) val).floatValue();
+ }
+
+ for (
+ int index = segmentsStart, nextRunStart = segmentsStart;
+ index < segmentsEnd;
+ index = nextRunStart, aci.setIndex(index)
+ ) {
+ nextRunStart = aci.getRunLimit();
+ attributes = unpackAttributes(aci.getAttributes());
+
+ TextDecorator.Decoration d = TextDecorator.getDecoration(attributes);
+ decorations.put(new Integer(index), d);
+
+ // Find appropriate font or place GraphicAttribute there
+
+ // 1. Try to pick up CHAR_REPLACEMENT (compatibility)
+ Font value = (Font)attributes.get(TextAttribute.CHAR_REPLACEMENT);
+
+ if (value == null) {
+ // 2. Try to Get FONT
+ value = (Font)attributes.get(TextAttribute.FONT);
+
+ if (value == null) {
+ // 3. Try to create font from FAMILY
+ if (attributes.get(TextAttribute.FAMILY) != null) {
+ value = Font.getFont(attributes);
+ }
+
+ if (value == null) {
+ // 4. No attributes found, using default.
+ if (forcedFontRunStartsList == null) {
+ forcedFontRunStartsList = new ArrayList<Integer>();
+ }
+ FontFinder.findFonts(
+ text,
+ index,
+ nextRunStart,
+ forcedFontRunStartsList,
+ fonts
+ );
+ value = fonts.get(new Integer(index));
+ }
+ }
+ }
+
+ fonts.put(new Integer(index), value);
+ }
+
+ // We have added some default fonts, so we have some extra runs in text
+ if (forcedFontRunStartsList != null) {
+ forcedFontRunStarts = new int[forcedFontRunStartsList.size()];
+ for (int i=0; i<forcedFontRunStartsList.size(); i++) {
+ forcedFontRunStarts[i] =
+ forcedFontRunStartsList.get(i).intValue();
+ }
+ }
+ }
+
+ /**
+ * Starting from the current position looks for the end of the text run with
+ * constant text attributes.
+ * @param runStart - start position
+ * @param maxPos - position where to stop if no run limit found
+ * @return style run limit
+ */
+ int getStyleRunLimit(int runStart, int maxPos) {
+ try {
+ aci.setIndex(runStart);
+ } catch(IllegalArgumentException e) { // Index out of bounds
+ if (runStart < segmentsStart) {
+ aci.first();
+ } else {
+ aci.last();
+ }
+ }
+
+ // If we have some extra runs we need to check for their limits
+ if (forcedFontRunStarts != null) {
+ for (int element : forcedFontRunStarts) {
+ if (element > runStart) {
+ maxPos = Math.min(element, maxPos);
+ break;
+ }
+ }
+ }
+
+ return Math.min(aci.getRunLimit(), maxPos);
+ }
+
+ /**
+ * Creates segments for the text run with
+ * constant decoration, font and bidi level
+ * @param runStart - run start
+ * @param runEnd - run end
+ */
+ public void createSegments(int runStart, int runEnd) {
+ int endStyleRun, endLevelRun;
+
+ // TODO - update levels
+
+ int pos = runStart, levelPos;
+
+ aci.setIndex(pos);
+ final int firstRunStart = aci.getRunStart();
+ Object tdd = decorations.get(new Integer(firstRunStart));
+ Object fontOrGAttr = fonts.get(new Integer(firstRunStart));
+
+ logical2segment = new int[runEnd - runStart];
+
+ do {
+ endStyleRun = getStyleRunLimit(pos, runEnd);
+
+ // runStart can be non-zero, but all arrays will be indexed from 0
+ int ajustedPos = pos - runStart;
+ int ajustedEndStyleRun = endStyleRun - runStart;
+ levelPos = ajustedPos;
+ do {
+ endLevelRun = getLevelRunLimit(levelPos, ajustedEndStyleRun);
+
+ if (fontOrGAttr instanceof GraphicAttribute) {
+ runSegments.add(
+ new TextRunSegmentImpl.TextRunSegmentGraphic(
+ (GraphicAttribute)fontOrGAttr,
+ endLevelRun - levelPos,
+ levelPos + runStart)
+ );
+ Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1);
+ } else {
+ TextRunSegmentImpl.TextSegmentInfo i =
+ new TextRunSegmentImpl.TextSegmentInfo(
+ levels == null ? 0 : levels[ajustedPos],
+ (Font) fontOrGAttr,
+ frc,
+ text,
+ levelPos + runStart,
+ endLevelRun + runStart
+ );
+
+ runSegments.add(
+ new TextRunSegmentImpl.TextRunSegmentCommon(
+ i,
+ (TextDecorator.Decoration) tdd
+ )
+ );
+ Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1);
+ }
+
+ levelPos = endLevelRun;
+ } while (levelPos < ajustedEndStyleRun);
+
+ // Prepare next iteration
+ pos = endStyleRun;
+ tdd = decorations.get(new Integer(pos));
+ fontOrGAttr = fonts.get(new Integer(pos));
+ } while (pos < runEnd);
+ }
+
+ /**
+ * Checks if text run segments are up to date and creates the new segments if not.
+ */
+ public void createAllSegments() {
+ if ( !haveAllSegments &&
+ (logical2segment == null ||
+ logical2segment.length != segmentsEnd - segmentsStart)
+ ) { // Check if we don't have all segments yet
+ resetSegments();
+ createSegments(segmentsStart, segmentsEnd);
+ }
+
+ haveAllSegments = true;
+ }
+
+ /**
+ * Calculates position where line should be broken without
+ * taking into account word boundaries.
+ * @param start - start index
+ * @param maxAdvance - maximum advance, width of the line
+ * @return position where to break
+ */
+ public int getLineBreakIndex(int start, float maxAdvance) {
+ int breakIndex;
+ TextRunSegment s = null;
+
+ for (
+ int segmentIndex = logical2segment[start];
+ segmentIndex < runSegments.size();
+ segmentIndex++
+ ) {
+ s = runSegments.get(segmentIndex);
+ breakIndex = s.getCharIndexFromAdvance(maxAdvance, start);
+
+ if (breakIndex < s.getEnd()) {
+ return breakIndex;
+ }
+ maxAdvance -= s.getAdvanceDelta(start, s.getEnd());
+ start = s.getEnd();
+ }
+
+ return s.getEnd();
+ }
+
+ /**
+ * Inserts character into the managed text.
+ * @param newParagraph - new character iterator
+ * @param insertPos - insertion position
+ */
+ public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
+ aci = newParagraph;
+
+ char insChar = aci.setIndex(insertPos);
+
+ Integer key = new Integer(insertPos);
+
+ insertPos -= aci.getBeginIndex();
+
+ char newText[] = new char[text.length + 1];
+ System.arraycopy(text, 0, newText, 0, insertPos);
+ newText[insertPos] = insChar;
+ System.arraycopy(text, insertPos, newText, insertPos+1, text.length - insertPos);
+ text = newText;
+
+ if (aci.getRunStart() == key.intValue() && aci.getRunLimit() == key.intValue() + 1) {
+ createStyleRuns(); // We have to create one new run, could be optimized
+ } else {
+ shiftStyleRuns(key, 1);
+ }
+
+ resetSegments();
+
+ segmentsEnd++;
+ }
+
+ /**
+ * Deletes character from the managed text.
+ * @param newParagraph - new character iterator
+ * @param deletePos - deletion position
+ */
+ public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
+ aci = newParagraph;
+
+ Integer key = new Integer(deletePos);
+
+ deletePos -= aci.getBeginIndex();
+
+ char newText[] = new char[text.length - 1];
+ System.arraycopy(text, 0, newText, 0, deletePos);
+ System.arraycopy(text, deletePos+1, newText, deletePos, newText.length - deletePos);
+ text = newText;
+
+ if (fonts.get(key) != null) {
+ fonts.remove(key);
+ }
+
+ shiftStyleRuns(key, -1);
+
+ resetSegments();
+
+ segmentsEnd--;
+ }
+
+ /**
+ * Shift all runs after specified position, needed to perfom insertion
+ * or deletion in the managed text
+ * @param pos - position where to start
+ * @param shift - shift, could be negative
+ */
+ private void shiftStyleRuns(Integer pos, final int shift) {
+ ArrayList<Integer> keys = new ArrayList<Integer>();
+
+ Integer key, oldkey;
+ for (Iterator<Integer> it = fonts.keySet().iterator(); it.hasNext(); ) {
+ oldkey = it.next();
+ if (oldkey.intValue() > pos.intValue()) {
+ keys.add(oldkey);
+ }
+ }
+
+ for (int i=0; i<keys.size(); i++) {
+ oldkey = keys.get(i);
+ key = new Integer(shift + oldkey.intValue());
+ fonts.put(key, fonts.remove(oldkey));
+ decorations.put(key, decorations.remove(oldkey));
+ }
+ }
+
+ /**
+ * Resets state of the class
+ */
+ private void resetSegments() {
+ runSegments = new ArrayList<TextRunSegment>();
+ logical2segment = null;
+ segment2visual = null;
+ visual2segment = null;
+ levels = null;
+ haveAllSegments = false;
+ }
+
+ private class SegmentsInfo {
+ ArrayList<TextRunSegment> runSegments;
+ int logical2segment[];
+ int segment2visual[];
+ int visual2segment[];
+ byte levels[];
+ int segmentsStart;
+ int segmentsEnd;
+ }
+
+ /**
+ * Saves the internal state of the class
+ * @param newSegStart - new start index in the text
+ * @param newSegEnd - new end index in the text
+ */
+ public void pushSegments(int newSegStart, int newSegEnd) {
+ storedSegments = new SegmentsInfo();
+ storedSegments.runSegments = this.runSegments;
+ storedSegments.logical2segment = this.logical2segment;
+ storedSegments.segment2visual = this.segment2visual;
+ storedSegments.visual2segment = this.visual2segment;
+ storedSegments.levels = this.levels;
+ storedSegments.segmentsStart = segmentsStart;
+ storedSegments.segmentsEnd = segmentsEnd;
+
+ resetSegments();
+
+ segmentsStart = newSegStart;
+ segmentsEnd = newSegEnd;
+ }
+
+ /**
+ * Restores the internal state of the class
+ */
+ public void popSegments() {
+ if (storedSegments == null) {
+ return;
+ }
+
+ this.runSegments = storedSegments.runSegments;
+ this.logical2segment = storedSegments.logical2segment;
+ this.segment2visual = storedSegments.segment2visual;
+ this.visual2segment = storedSegments.visual2segment;
+ this.levels = storedSegments.levels;
+ this.segmentsStart = storedSegments.segmentsStart;
+ this.segmentsEnd = storedSegments.segmentsEnd;
+ storedSegments = null;
+
+ if (runSegments.size() == 0 && logical2segment == null) {
+ haveAllSegments = false;
+ } else {
+ haveAllSegments = true;
+ }
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ TextRunBreaker res = (TextRunBreaker) super.clone();
+ res.storedSegments = null;
+ ArrayList<TextRunSegment> newSegments = new ArrayList<TextRunSegment>(runSegments.size());
+ for (int i = 0; i < runSegments.size(); i++) {
+ TextRunSegment seg = runSegments.get(i);
+ newSegments.add((TextRunSegment)seg.clone());
+ }
+ res.runSegments = newSegments;
+ return res;
+ } catch (CloneNotSupportedException e) {
+ // awt.3E=Clone not supported
+ throw new UnsupportedOperationException(Messages.getString("awt.3E")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TextRunBreaker)) {
+ return false;
+ }
+
+ TextRunBreaker br = (TextRunBreaker) obj;
+
+ if (br.getACI().equals(aci) && br.frc.equals(frc)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCode.combine(aci.hashCode(), frc.hashCode());
+ }
+
+ /**
+ * Renders the managed text
+ * @param g2d - graphics where to render
+ * @param xOffset - offset in X direction to the upper left corner
+ * of the layout from the origin of the graphics
+ * @param yOffset - offset in Y direction to the upper left corner
+ * of the layout from the origin of the graphics
+ */
+ public void drawSegments(Graphics2D g2d, float xOffset, float yOffset) {
+ for (int i=0; i<runSegments.size(); i++) {
+ runSegments.get(i).draw(g2d, xOffset, yOffset);
+ }
+ }
+
+ /**
+ * Creates the black box bounds shape
+ * @param firstEndpoint - start position
+ * @param secondEndpoint - end position
+ * @return black box bounds shape
+ */
+ public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) {
+ GeneralPath bounds = new GeneralPath();
+
+ TextRunSegment segment;
+
+ for (int idx = firstEndpoint; idx < secondEndpoint; idx=segment.getEnd()) {
+ segment = runSegments.get(logical2segment[idx]);
+ bounds.append(segment.getCharsBlackBoxBounds(idx, secondEndpoint), false);
+ }
+
+ return bounds;
+ }
+
+ /**
+ * Creates visual bounds shape
+ * @return visual bounds rectangle
+ */
+ public Rectangle2D getVisualBounds() {
+ Rectangle2D bounds = null;
+
+ for (int i=0; i<runSegments.size(); i++) {
+ TextRunSegment s = runSegments.get(i);
+ if (bounds != null) {
+ Rectangle2D.union(bounds, s.getVisualBounds(), bounds);
+ } else {
+ bounds = s.getVisualBounds();
+ }
+ }
+
+ return bounds;
+ }
+
+ /**
+ * Creates logical bounds shape
+ * @return logical bounds rectangle
+ */
+ public Rectangle2D getLogicalBounds() {
+ Rectangle2D bounds = null;
+
+ for (int i=0; i<runSegments.size(); i++) {
+ TextRunSegment s = runSegments.get(i);
+ if (bounds != null) {
+ Rectangle2D.union(bounds, s.getLogicalBounds(), bounds);
+ } else {
+ bounds = s.getLogicalBounds();
+ }
+ }
+
+ return bounds;
+ }
+
+ public int getCharCount() {
+ return segmentsEnd - segmentsStart;
+ }
+
+ public byte getLevel(int idx) {
+ if (levels == null) {
+ return 0;
+ }
+ return levels[idx];
+ }
+
+ public int getBaseLevel() {
+ return 0;
+ }
+
+ public boolean isLTR() {
+ return true;
+ }
+
+ public char getChar(int index) {
+ return text[index];
+ }
+
+ public AttributedCharacterIterator getACI() {
+ return aci;
+ }
+
+ /**
+ * Creates outline shape for the managed text
+ * @return outline
+ */
+ public GeneralPath getOutline() {
+ GeneralPath outline = new GeneralPath();
+
+ TextRunSegment segment;
+
+ for (int i = 0; i < runSegments.size(); i++) {
+ segment = runSegments.get(i);
+ outline.append(segment.getOutline(), false);
+ }
+
+ return outline;
+ }
+
+ /**
+ * Calculates text hit info from the screen coordinates.
+ * Current implementation totally ignores Y coordinate.
+ * If X coordinate is outside of the layout boundaries, this
+ * method returns leftmost or rightmost hit.
+ * @param x - x coordinate of the hit
+ * @param y - y coordinate of the hit
+ * @return hit info
+ */
+ public TextHitInfo hitTest(float x, float y) {
+ TextRunSegment segment;
+
+ double endOfPrevSeg = -1;
+ for (int i = 0; i < runSegments.size(); i++) {
+ segment = runSegments.get(i);
+ Rectangle2D bounds = segment.getVisualBounds();
+ if ((bounds.getMinX() <= x && bounds.getMaxX() >= x) || // We are in the segment
+ (endOfPrevSeg < x && bounds.getMinX() > x)) { // We are somewhere between the segments
+ return segment.hitTest(x,y);
+ }
+ endOfPrevSeg = bounds.getMaxX();
+ }
+
+ return isLTR() ? TextHitInfo.trailing(text.length) : TextHitInfo.leading(0);
+ }
+
+ public float getJustification() {
+ return justification;
+ }
+
+ /**
+ * Calculates position of the last non whitespace character
+ * in the managed text.
+ * @return position of the last non whitespace character
+ */
+ public int getLastNonWhitespace() {
+ int lastNonWhitespace = text.length;
+
+ while (lastNonWhitespace >= 0) {
+ lastNonWhitespace--;
+ if (!Character.isWhitespace(text[lastNonWhitespace])) {
+ break;
+ }
+ }
+
+ return lastNonWhitespace;
+ }
+
+ /**
+ * Performs justification of the managed text by changing segment positions
+ * and positions of the glyphs inside of the segments.
+ * @param gap - amount of space which should be compensated by justification
+ */
+ public void justify(float gap) {
+ // Ignore trailing logical whitespace
+ int firstIdx = segmentsStart;
+ int lastIdx = getLastNonWhitespace() + segmentsStart;
+ JustificationInfo jInfos[] = new JustificationInfo[5];
+ float gapLeft = gap;
+
+ int highestPriority = -1;
+ // GlyphJustificationInfo.PRIORITY_KASHIDA is 0
+ // GlyphJustificationInfo.PRIORITY_NONE is 3
+ for (int priority = 0; priority <= GlyphJustificationInfo.PRIORITY_NONE + 1; priority++) {
+ JustificationInfo jInfo = new JustificationInfo();
+ jInfo.lastIdx = lastIdx;
+ jInfo.firstIdx = firstIdx;
+ jInfo.grow = gap > 0;
+ jInfo.gapToFill = gapLeft;
+
+ if (priority <= GlyphJustificationInfo.PRIORITY_NONE) {
+ jInfo.priority = priority;
+ } else {
+ jInfo.priority = highestPriority; // Last pass
+ }
+
+ for (int i = 0; i < runSegments.size(); i++) {
+ TextRunSegment segment = runSegments.get(i);
+ if (segment.getStart() <= lastIdx) {
+ segment.updateJustificationInfo(jInfo);
+ }
+ }
+
+ if (jInfo.priority == highestPriority) {
+ jInfo.absorb = true;
+ jInfo.absorbedWeight = jInfo.weight;
+ }
+
+ if (jInfo.weight != 0) {
+ if (highestPriority < 0) {
+ highestPriority = priority;
+ }
+ jInfos[priority] = jInfo;
+ } else {
+ continue;
+ }
+
+ gapLeft -= jInfo.growLimit;
+
+ if (((gapLeft > 0) ^ jInfo.grow) || gapLeft == 0) {
+ gapLeft = 0;
+ jInfo.gapPerUnit = jInfo.gapToFill/jInfo.weight;
+ break;
+ }
+ jInfo.useLimits = true;
+
+ if (jInfo.absorbedWeight > 0) {
+ jInfo.absorb = true;
+ jInfo.absorbedGapPerUnit =
+ (jInfo.gapToFill-jInfo.growLimit)/jInfo.absorbedWeight;
+ break;
+ }
+ }
+
+ float currJustificationOffset = 0;
+ for (int i = 0; i < runSegments.size(); i++) {
+ TextRunSegment segment =
+ runSegments.get(getSegmentFromVisualOrder(i));
+ segment.x += currJustificationOffset;
+ currJustificationOffset += segment.doJustification(jInfos);
+ }
+
+ justification = -1; // Make further justification impossible
+ }
+
+ /**
+ * This class represents the information collected before the actual
+ * justification is started and needed to perform the justification.
+ * This information is closely related to the information stored in the
+ * GlyphJustificationInfo for the text represented by glyph vectors.
+ */
+ class JustificationInfo {
+ boolean grow;
+ boolean absorb = false;
+ boolean useLimits = false;
+ int priority = 0;
+ float weight = 0;
+ float absorbedWeight = 0;
+ float growLimit = 0;
+
+ int lastIdx;
+ int firstIdx;
+
+ float gapToFill;
+
+ float gapPerUnit = 0; // Precalculated value, gapToFill / weight
+ float absorbedGapPerUnit = 0; // Precalculated value, gapToFill / weight
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
new file mode 100644
index 0000000..1cd2c05
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.TextHitInfo;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Abstract class which represents the segment of the text with constant attributes
+ * running in one direction (i.e. constant level).
+ */
+public abstract class TextRunSegment implements Cloneable {
+ float x; // Calculated x location of this segment on the screen
+ float y; // Calculated y location of this segment on the screen
+
+ BasicMetrics metrics; // Metrics of this text run segment
+ TextDecorator.Decoration decoration; // Underline, srikethrough, etc.
+ Rectangle2D logicalBounds = null; // Logical bounding box for the segment
+ Rectangle2D visualBounds = null; // Visual bounding box for the segment
+
+ /**
+ * Returns start index of the segment
+ * @return start index
+ */
+ abstract int getStart();
+
+ /**
+ * Returns end index of the segment
+ * @return end index
+ */
+ abstract int getEnd();
+
+ /**
+ * Returns the number of characters in the segment
+ * @return number of characters
+ */
+ abstract int getLength();
+
+ /**
+ * Renders this text run segment
+ * @param g2d - graphics to render to
+ * @param xOffset - X offset from the graphics origin to the
+ * origin of the text layout
+ * @param yOffset - Y offset from the graphics origin to the
+ * origin of the text layout
+ */
+ abstract void draw(Graphics2D g2d, float xOffset, float yOffset);
+
+ /**
+ * Creates black box bounds shape for the specified range
+ * @param start - range sart
+ * @param limit - range end
+ * @return black box bounds shape
+ */
+ abstract Shape getCharsBlackBoxBounds(int start, int limit);
+
+ /**
+ * Returns the outline shape
+ * @return outline
+ */
+ abstract Shape getOutline();
+
+ /**
+ * Returns visual bounds of this segment
+ * @return visual bounds
+ */
+ abstract Rectangle2D getVisualBounds();
+
+ /**
+ * Returns logical bounds of this segment
+ * @return logical bounds
+ */
+ abstract Rectangle2D getLogicalBounds();
+
+ /**
+ * Calculates advance of the segment
+ * @return advance
+ */
+ abstract float getAdvance();
+
+ /**
+ * Calculates advance delta between two characters
+ * @param start - 1st position
+ * @param end - 2nd position
+ * @return advance increment between specified positions
+ */
+ abstract float getAdvanceDelta(int start, int end);
+
+ /**
+ * Calculates index of the character which advance is equal to
+ * the given. If the given advance is greater then the segment
+ * advance it returns the position after the last character.
+ * @param advance - given advance
+ * @param start - character, from which to start measuring advance
+ * @return character index
+ */
+ abstract int getCharIndexFromAdvance(float advance, int start);
+
+ /**
+ * Checks if the character doesn't contribute to the text advance
+ * @param index - character index
+ * @return true if the character has zero advance
+ */
+ abstract boolean charHasZeroAdvance(int index);
+
+ /**
+ * Calculates position of the character on the screen
+ * @param index - character index
+ * @return X coordinate of the character position
+ */
+ abstract float getCharPosition(int index);
+
+ /**
+ * Returns the advance of the individual character
+ * @param index - character index
+ * @return character advance
+ */
+ abstract float getCharAdvance(int index);
+
+ /**
+ * Creates text hit info from the hit position
+ * @param x - X coordinate relative to the origin of the layout
+ * @param y - Y coordinate relative to the origin of the layout
+ * @return hit info
+ */
+ abstract TextHitInfo hitTest(float x, float y);
+
+ /**
+ * Collects justification information into JustificationInfo object
+ * @param jInfo - JustificationInfo object
+ */
+ abstract void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo);
+
+ /**
+ * Performs justification of the segment.
+ * Updates positions of individual characters.
+ * @param jInfos - justification information, gathered by the previous passes
+ * @return amount of growth or shrink of the segment
+ */
+ abstract float doJustification(TextRunBreaker.JustificationInfo jInfos[]);
+
+ @Override
+ public abstract Object clone();
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
new file mode 100644
index 0000000..0ec2d05
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
@@ -0,0 +1,979 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+// XXX - TODO - bidi not implemented yet
+//import java.text.Bidi;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Date: Apr 25, 2005
+ * Time: 4:33:18 PM
+ *
+ * This class contains the implementation of the behavior of the
+ * text run segment with constant text attributes and direction.
+ */
+public class TextRunSegmentImpl {
+
+ /**
+ * This class contains basic information required for creation
+ * of the glyph-based text run segment.
+ */
+ public static class TextSegmentInfo {
+ // XXX - TODO - bidi not implemented yet
+ //Bidi bidi;
+
+ Font font;
+ FontRenderContext frc;
+
+ char text[];
+
+ int start;
+ int end;
+ int length;
+
+ int flags = 0;
+
+ byte level = 0;
+
+ TextSegmentInfo(
+ byte level,
+ Font font, FontRenderContext frc,
+ char text[], int start, int end
+ ) {
+ this.font = font;
+ this.frc = frc;
+ this.text = text;
+ this.start = start;
+ this.end = end;
+ this.level = level;
+ length = end - start;
+ }
+ }
+
+ /**
+ * This class represents a simple text segment backed by the glyph vector
+ */
+ public static class TextRunSegmentCommon extends TextRunSegment {
+ TextSegmentInfo info;
+ private GlyphVector gv;
+ private float advanceIncrements[];
+ private int char2glyph[];
+ private GlyphJustificationInfo gjis[]; // Glyph justification info
+
+ TextRunSegmentCommon(TextSegmentInfo i, TextDecorator.Decoration d) {
+ // XXX - todo - check support bidi
+ i.flags &= ~0x09; // Clear bidi flags
+
+ if ((i.level & 0x1) != 0) {
+ i.flags |= Font.LAYOUT_RIGHT_TO_LEFT;
+ }
+
+ info = i;
+ this.decoration = d;
+
+ LineMetrics lm = i.font.getLineMetrics(i.text, i.start, i.end, i.frc);
+ this.metrics = new BasicMetrics(lm, i.font);
+
+ if (lm.getNumChars() != i.length) { // XXX todo - This should be handled
+ // awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
+ throw new UnsupportedOperationException(
+ Messages.getString("awt.41")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object clone() {
+ return new TextRunSegmentCommon(info, decoration);
+ }
+
+ /**
+ * Creates glyph vector from the managed text if needed
+ * @return glyph vector
+ */
+ private GlyphVector getGlyphVector() {
+ if (gv==null) {
+ gv = info.font.layoutGlyphVector(
+ info.frc,
+ info.text,
+ info.start,
+ info.end - info.start, // NOTE: This parameter violates
+ // spec, it is count,
+ // not limit as spec states
+ info.flags
+ );
+ }
+
+ return gv;
+ }
+
+ /**
+ * Renders this text run segment
+ * @param g2d - graphics to render to
+ * @param xOffset - X offset from the graphics origin to the
+ * origin of the text layout
+ * @param yOffset - Y offset from the graphics origin to the
+ * origin of the text layout
+ */
+ @Override
+ void draw(Graphics2D g2d, float xOffset, float yOffset) {
+ if (decoration == null) {
+ g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
+ } else {
+ TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
+ g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
+ TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
+ TextDecorator.restoreGraphics(decoration, g2d);
+ }
+ }
+
+ /**
+ * Returns visual bounds of this segment
+ * @return visual bounds
+ */
+ @Override
+ Rectangle2D getVisualBounds() {
+ if (visualBounds == null) {
+ visualBounds =
+ TextDecorator.extendVisualBounds(
+ this,
+ getGlyphVector().getVisualBounds(),
+ decoration
+ );
+
+ visualBounds.setRect(
+ x + visualBounds.getX(),
+ y + visualBounds.getY(),
+ visualBounds.getWidth(),
+ visualBounds.getHeight()
+ );
+ }
+
+ return (Rectangle2D) visualBounds.clone();
+ }
+
+ /**
+ * Returns logical bounds of this segment
+ * @return logical bounds
+ */
+ @Override
+ Rectangle2D getLogicalBounds() {
+ if (logicalBounds == null) {
+ logicalBounds = getGlyphVector().getLogicalBounds();
+
+ logicalBounds.setRect(
+ x + logicalBounds.getX(),
+ y + logicalBounds.getY(),
+ logicalBounds.getWidth(),
+ logicalBounds.getHeight()
+ );
+ }
+
+ return (Rectangle2D) logicalBounds.clone();
+ }
+
+ @Override
+ float getAdvance() {
+ return (float) getLogicalBounds().getWidth();
+ }
+
+ /**
+ * Attemts to map each character to the corresponding advance increment
+ */
+ void initAdvanceMapping() {
+ GlyphVector gv = getGlyphVector();
+ int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
+ advanceIncrements = new float[info.length];
+
+ for (int i=0; i<charIndicies.length; i++) {
+ advanceIncrements[charIndicies[i]] = gv.getGlyphMetrics(i).getAdvance();
+ }
+ }
+
+ /**
+ * Calculates advance delta between two characters
+ * @param start - 1st position
+ * @param end - 2nd position
+ * @return advance increment between specified positions
+ */
+ @Override
+ float getAdvanceDelta(int start, int end) {
+ // Get coordinates in the segment context
+ start -= info.start;
+ end -= info.start;
+
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > info.length) {
+ end = info.length;
+ }
+
+ float sum = 0;
+ for (int i=start; i<end; i++) {
+ sum += advanceIncrements[i];
+ }
+
+ return sum;
+ }
+
+ /**
+ * Calculates index of the character which advance is equal to
+ * the given. If the given advance is greater then the segment
+ * advance it returns the position after the last character.
+ * @param advance - given advance
+ * @param start - character, from which to start measuring advance
+ * @return character index
+ */
+ @Override
+ int getCharIndexFromAdvance(float advance, int start) {
+ // XXX - todo - probably, possible to optimize
+ // Add check if the given advance is greater then
+ // the segment advance in the beginning. In this case
+ // we don't need to run through all increments
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ start -= info.start;
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ int i = start;
+ for (; i<info.length; i++) {
+ advance -= advanceIncrements[i];
+ if (advance < 0) {
+ break;
+ }
+ }
+
+ return i + info.start;
+ }
+
+ @Override
+ int getStart() {
+ return info.start;
+ }
+
+ @Override
+ int getEnd() {
+ return info.end;
+ }
+
+ @Override
+ int getLength() {
+ return info.length;
+ }
+
+ /**
+ * Attemts to create mapping of the characters to glyphs in the glyph vector.
+ * @return array where for each character index stored corresponding glyph index
+ */
+ private int[] getChar2Glyph() {
+ if (char2glyph == null) {
+ GlyphVector gv = getGlyphVector();
+ char2glyph = new int[info.length];
+ Arrays.fill(char2glyph, -1);
+
+ // Fill glyph indicies for first characters corresponding to each glyph
+ int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
+ for (int i=0; i<charIndicies.length; i++) {
+ char2glyph[charIndicies[i]] = i;
+ }
+
+ // If several characters corresponds to one glyph, create mapping for them
+ // Suppose that these characters are going all together
+ int currIndex = 0;
+ for (int i=0; i<char2glyph.length; i++) {
+ if (char2glyph[i] < 0) {
+ char2glyph[i] = currIndex;
+ } else {
+ currIndex = char2glyph[i];
+ }
+ }
+ }
+
+ return char2glyph;
+ }
+
+ /**
+ * Creates black box bounds shape for the specified range
+ * @param start - range sart
+ * @param limit - range end
+ * @return black box bounds shape
+ */
+ @Override
+ Shape getCharsBlackBoxBounds(int start, int limit) {
+ start -= info.start;
+ limit -= info.start;
+
+ if (limit > info.length) {
+ limit = info.length;
+ }
+
+ GeneralPath result = new GeneralPath();
+
+ int glyphIndex = 0;
+
+ for (int i=start; i<limit; i++) {
+ glyphIndex = getChar2Glyph()[i];
+ result.append(getGlyphVector().getGlyphVisualBounds(glyphIndex), false);
+ }
+
+ // Shift to the segment's coordinates
+ result.transform(AffineTransform.getTranslateInstance(x, y));
+
+ return result;
+ }
+
+ /**
+ * Calculates position of the character on the screen
+ * @param index - character index
+ * @return X coordinate of the character position
+ */
+ @Override
+ float getCharPosition(int index) {
+ index -= info.start;
+
+ if (index > info.length) {
+ index = info.length;
+ }
+
+ float result = 0;
+
+ int glyphIndex = getChar2Glyph()[index];
+ result = (float) getGlyphVector().getGlyphPosition(glyphIndex).getX();
+
+ // Shift to the segment's coordinates
+ result += x;
+
+ return result;
+ }
+
+ /**
+ * Returns the advance of the individual character
+ * @param index - character index
+ * @return character advance
+ */
+ @Override
+ float getCharAdvance(int index) {
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ return advanceIncrements[index - this.getStart()];
+ }
+
+ /**
+ * Returns the outline shape
+ * @return outline
+ */
+ @Override
+ Shape getOutline() {
+ AffineTransform t = AffineTransform.getTranslateInstance(x, y);
+ return t.createTransformedShape(
+ TextDecorator.extendOutline(
+ this,
+ getGlyphVector().getOutline(),
+ decoration
+ )
+ );
+ }
+
+ /**
+ * Checks if the character doesn't contribute to the text advance
+ * @param index - character index
+ * @return true if the character has zero advance
+ */
+ @Override
+ boolean charHasZeroAdvance(int index) {
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ return advanceIncrements[index - this.getStart()] == 0;
+ }
+
+ /**
+ * Creates text hit info from the hit position
+ * @param hitX - X coordinate relative to the origin of the layout
+ * @param hitY - Y coordinate relative to the origin of the layout
+ * @return hit info
+ */
+ @Override
+ TextHitInfo hitTest(float hitX, float hitY) {
+ hitX -= x;
+
+ float glyphPositions[] =
+ getGlyphVector().getGlyphPositions(0, info.length+1, null);
+
+ int glyphIdx;
+ boolean leading = false;
+ for (glyphIdx = 1; glyphIdx <= info.length; glyphIdx++) {
+ if (glyphPositions[(glyphIdx)*2] >= hitX) {
+ float advance =
+ glyphPositions[(glyphIdx)*2] - glyphPositions[(glyphIdx-1)*2];
+ leading = glyphPositions[(glyphIdx-1)*2] + advance/2 > hitX ? true : false;
+ glyphIdx--;
+ break;
+ }
+ }
+
+ if (glyphIdx == info.length) {
+ glyphIdx--;
+ }
+
+ int charIdx = getGlyphVector().getGlyphCharIndex(glyphIdx);
+
+ return (leading) ^ ((info.level & 0x1) == 0x1)?
+ TextHitInfo.leading(charIdx + info.start) :
+ TextHitInfo.trailing(charIdx + info.start);
+ }
+
+ /**
+ * Collects GlyphJustificationInfo objects from the glyph vector
+ * @return array of all GlyphJustificationInfo objects
+ */
+ private GlyphJustificationInfo[] getGlyphJustificationInfos() {
+ if (gjis == null) {
+ GlyphVector gv = getGlyphVector();
+ int nGlyphs = gv.getNumGlyphs();
+ int charIndicies[] = gv.getGlyphCharIndices(0, nGlyphs, null);
+ gjis = new GlyphJustificationInfo[nGlyphs];
+
+ // Patch: temporary patch, getGlyphJustificationInfo is not implemented
+ float fontSize = info.font.getSize2D();
+ GlyphJustificationInfo defaultInfo =
+ new GlyphJustificationInfo(
+ 0, // weight
+ false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0, // grow
+ false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0); // shrink
+ GlyphJustificationInfo spaceInfo = new GlyphJustificationInfo(
+ fontSize, // weight
+ true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize, // grow
+ true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize); // shrink
+
+ ////////
+ // Temporary patch, getGlyphJustificationInfo is not implemented
+ for (int i = 0; i < nGlyphs; i++) {
+ //gjis[i] = getGlyphVector().getGlyphJustificationInfo(i);
+
+ char c = info.text[charIndicies[i] + info.start];
+ if (Character.isWhitespace(c)) {
+ gjis[i] = spaceInfo;
+ } else {
+ gjis[i] = defaultInfo;
+ }
+ // End patch
+ }
+ }
+
+ return gjis;
+ }
+
+ /**
+ * Collects justification information into JustificationInfo object
+ * @param jInfo - JustificationInfo object
+ */
+ @Override
+ void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
+ int lastChar = Math.min(jInfo.lastIdx, info.end) - info.start;
+ boolean haveFirst = info.start <= jInfo.firstIdx;
+ boolean haveLast = info.end >= (jInfo.lastIdx + 1);
+
+ int prevGlyphIdx = -1;
+ int currGlyphIdx;
+
+ if (jInfo.grow) { // Check how much we can grow/shrink on current priority level
+ for (int i=0; i<lastChar; i++) {
+ currGlyphIdx = getChar2Glyph()[i];
+
+ if (currGlyphIdx == prevGlyphIdx) {
+ // Several chars could be represented by one glyph,
+ // suppose they are contiguous
+ continue;
+ }
+ prevGlyphIdx = currGlyphIdx;
+
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
+ if (gji.growPriority == jInfo.priority) {
+ jInfo.weight += gji.weight * 2;
+ jInfo.growLimit += gji.growLeftLimit;
+ jInfo.growLimit += gji.growRightLimit;
+ if (gji.growAbsorb) {
+ jInfo.absorbedWeight += gji.weight * 2;
+ }
+ }
+ }
+ } else {
+ for (int i=0; i<lastChar; i++) {
+ currGlyphIdx = getChar2Glyph()[i];
+ if (currGlyphIdx == prevGlyphIdx) {
+ continue;
+ }
+ prevGlyphIdx = currGlyphIdx;
+
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
+ if (gji.shrinkPriority == jInfo.priority) {
+ jInfo.weight += gji.weight * 2;
+ jInfo.growLimit -= gji.shrinkLeftLimit;
+ jInfo.growLimit -= gji.shrinkRightLimit;
+ if (gji.shrinkAbsorb) {
+ jInfo.absorbedWeight += gji.weight * 2;
+ }
+ }
+ }
+ }
+
+ if (haveFirst) { // Don't add padding before first char
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[getChar2Glyph()[0]];
+ jInfo.weight -= gji.weight;
+ if (jInfo.grow) {
+ jInfo.growLimit -= gji.growLeftLimit;
+ if (gji.growAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ } else {
+ jInfo.growLimit += gji.shrinkLeftLimit;
+ if (gji.shrinkAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ }
+ }
+
+ if (haveLast) { // Don't add padding after last char
+ GlyphJustificationInfo gji =
+ getGlyphJustificationInfos()[getChar2Glyph()[lastChar]];
+ jInfo.weight -= gji.weight;
+ if (jInfo.grow) {
+ jInfo.growLimit -= gji.growRightLimit;
+ if (gji.growAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ } else {
+ jInfo.growLimit += gji.shrinkRightLimit;
+ if (gji.shrinkAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs justification of the segment.
+ * Updates positions of individual characters.
+ * @param jInfos - justification information, gathered by the previous passes
+ * @return amount of growth or shrink of the segment
+ */
+ @Override
+ float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
+ int lastPriority =
+ jInfos[jInfos.length-1] == null ?
+ -1 : jInfos[jInfos.length-1].priority;
+
+ // Get the highest priority
+ int highestPriority = 0;
+ for (; highestPriority<jInfos.length; highestPriority++) {
+ if (jInfos[highestPriority] != null) {
+ break;
+ }
+ }
+
+ if (highestPriority == jInfos.length) {
+ return 0;
+ }
+
+ TextRunBreaker.JustificationInfo firstInfo = jInfos[highestPriority];
+ TextRunBreaker.JustificationInfo lastInfo =
+ lastPriority > 0 ? jInfos[lastPriority] : null;
+
+ boolean haveFirst = info.start <= firstInfo.firstIdx;
+ boolean haveLast = info.end >= (firstInfo.lastIdx + 1);
+
+ // Here we suppose that GLYPHS are ordered LEFT TO RIGHT
+ int firstGlyph = haveFirst ?
+ getChar2Glyph()[firstInfo.firstIdx - info.start] :
+ getChar2Glyph()[0];
+
+ int lastGlyph = haveLast ?
+ getChar2Glyph()[firstInfo.lastIdx - info.start] :
+ getChar2Glyph()[info.length - 1];
+ if (haveLast) {
+ lastGlyph--;
+ }
+
+ TextRunBreaker.JustificationInfo currInfo;
+ float glyphOffset = 0;
+ float positionIncrement = 0;
+ float sideIncrement = 0;
+
+ if (haveFirst) { // Don't add padding before first char
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[firstGlyph];
+ currInfo = jInfos[gji.growPriority];
+ if (currInfo != null) {
+ if (currInfo.useLimits) {
+ if (currInfo.absorb) {
+ glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
+ } else if (
+ lastInfo != null &&
+ lastInfo.priority == currInfo.priority
+ ) {
+ glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
+ }
+ glyphOffset +=
+ firstInfo.grow ?
+ gji.growRightLimit :
+ -gji.shrinkRightLimit;
+ } else {
+ glyphOffset += gji.weight * currInfo.gapPerUnit;
+ }
+ }
+
+ firstGlyph++;
+ }
+
+ if (firstInfo.grow) {
+ for (int i=firstGlyph; i<=lastGlyph; i++) {
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
+ currInfo = jInfos[gji.growPriority];
+ if (currInfo == null) {
+ // We still have to increment glyph position
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+
+ continue;
+ }
+
+ if (currInfo.useLimits) {
+ glyphOffset += gji.growLeftLimit;
+ if (currInfo.absorb) {
+ sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+ sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else {
+ positionIncrement = glyphOffset;
+ }
+ glyphOffset += gji.growRightLimit;
+ } else {
+ sideIncrement = gji.weight * currInfo.gapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ }
+
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+ }
+ } else {
+ for (int i=firstGlyph; i<=lastGlyph; i++) {
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
+ currInfo = jInfos[gji.shrinkPriority];
+ if (currInfo == null) {
+ // We still have to increment glyph position
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+
+ continue;
+ }
+
+ if (currInfo.useLimits) {
+ glyphOffset -= gji.shrinkLeftLimit;
+ if (currInfo.absorb) {
+ sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+ sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else {
+ positionIncrement = glyphOffset;
+ }
+ glyphOffset -= gji.shrinkRightLimit;
+ } else {
+ sideIncrement = gji.weight * currInfo.gapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ }
+
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+ }
+ }
+
+
+ if (haveLast) { // Don't add padding after last char
+ lastGlyph++;
+
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[lastGlyph];
+ currInfo = jInfos[gji.growPriority];
+
+ if (currInfo != null) {
+ if (currInfo.useLimits) {
+ glyphOffset += firstInfo.grow ? gji.growLeftLimit : -gji.shrinkLeftLimit;
+ if (currInfo.absorb) {
+ glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
+ } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+ glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
+ }
+ } else {
+ glyphOffset += gji.weight * currInfo.gapPerUnit;
+ }
+ }
+
+ // Ajust positions of all glyphs after last glyph
+ for (int i=lastGlyph; i<getGlyphVector().getNumGlyphs()+1; i++) {
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+ }
+ } else { // Update position after last glyph in glyph vector -
+ // to get correct advance for it
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(lastGlyph+1);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(lastGlyph+1, glyphPos);
+ }
+
+ gjis = null; // We don't need justification infos any more
+ // Also we have to reset cached bounds and metrics
+ this.visualBounds = null;
+ this.logicalBounds = null;
+
+ return glyphOffset; // How much our segment grown or shrunk
+ }
+ }
+
+ public static class TextRunSegmentGraphic extends TextRunSegment {
+ GraphicAttribute ga;
+ int start;
+ int length;
+ float fullAdvance;
+
+ TextRunSegmentGraphic(GraphicAttribute attr, int len, int start) {
+ this.start = start;
+ length = len;
+ ga = attr;
+ metrics = new BasicMetrics(ga);
+ fullAdvance = ga.getAdvance() * length;
+ }
+
+ @Override
+ public Object clone() {
+ return new TextRunSegmentGraphic(ga, length, start);
+ }
+
+ // Renders this text run segment
+ @Override
+ void draw(Graphics2D g2d, float xOffset, float yOffset) {
+ if (decoration != null) {
+ TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
+ }
+
+ float xPos = x + xOffset;
+ float yPos = y + yOffset;
+
+ for (int i=0; i < length; i++) {
+ ga.draw(g2d, xPos, yPos);
+ xPos += ga.getAdvance();
+ }
+
+ if (decoration != null) {
+ TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
+ TextDecorator.restoreGraphics(decoration, g2d);
+ }
+ }
+
+ // Returns visual bounds of this segment
+ @Override
+ Rectangle2D getVisualBounds() {
+ if (visualBounds == null) {
+ Rectangle2D bounds = ga.getBounds();
+
+ // First and last chars can be out of logical bounds, so we calculate
+ // (bounds.getWidth() - ga.getAdvance()) which is exactly the difference
+ bounds.setRect(
+ bounds.getMinX() + x,
+ bounds.getMinY() + y,
+ bounds.getWidth() - ga.getAdvance() + getAdvance(),
+ bounds.getHeight()
+ );
+ visualBounds = TextDecorator.extendVisualBounds(this, bounds, decoration);
+ }
+
+ return (Rectangle2D) visualBounds.clone();
+ }
+
+ @Override
+ Rectangle2D getLogicalBounds() {
+ if (logicalBounds == null) {
+ logicalBounds =
+ new Rectangle2D.Float(
+ x, y - metrics.ascent,
+ getAdvance(), metrics.ascent + metrics.descent
+ );
+ }
+
+ return (Rectangle2D) logicalBounds.clone();
+ }
+
+ @Override
+ float getAdvance() {
+ return fullAdvance;
+ }
+
+ @Override
+ float getAdvanceDelta(int start, int end) {
+ return ga.getAdvance() * (end - start);
+ }
+
+ @Override
+ int getCharIndexFromAdvance(float advance, int start) {
+ start -= this.start;
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ int charOffset = (int) (advance/ga.getAdvance());
+
+ if (charOffset + start > length) {
+ return length + this.start;
+ }
+ return charOffset + start + this.start;
+ }
+
+ @Override
+ int getStart() {
+ return start;
+ }
+
+ @Override
+ int getEnd() {
+ return start + length;
+ }
+
+ @Override
+ int getLength() {
+ return length;
+ }
+
+ @Override
+ Shape getCharsBlackBoxBounds(int start, int limit) {
+ start -= this.start;
+ limit -= this.start;
+
+ if (limit > length) {
+ limit = length;
+ }
+
+ Rectangle2D charBounds = ga.getBounds();
+ charBounds.setRect(
+ charBounds.getX() + ga.getAdvance() * start + x,
+ charBounds.getY() + y,
+ charBounds.getWidth() + ga.getAdvance() * (limit - start),
+ charBounds.getHeight()
+ );
+
+ return charBounds;
+ }
+
+ @Override
+ float getCharPosition(int index) {
+ index -= start;
+ if (index > length) {
+ index = length;
+ }
+
+ return ga.getAdvance() * index + x;
+ }
+
+ @Override
+ float getCharAdvance(int index) {
+ return ga.getAdvance();
+ }
+
+ @Override
+ Shape getOutline() {
+ AffineTransform t = AffineTransform.getTranslateInstance(x, y);
+ return t.createTransformedShape(
+ TextDecorator.extendOutline(this, getVisualBounds(), decoration)
+ );
+ }
+
+ @Override
+ boolean charHasZeroAdvance(int index) {
+ return false;
+ }
+
+ @Override
+ TextHitInfo hitTest(float hitX, float hitY) {
+ hitX -= x;
+
+ float tmp = hitX / ga.getAdvance();
+ int hitIndex = Math.round(tmp);
+
+ if (tmp > hitIndex) {
+ return TextHitInfo.leading(hitIndex + this.start);
+ }
+ return TextHitInfo.trailing(hitIndex + this.start);
+ }
+
+ @Override
+ void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
+ // Do nothing
+ }
+
+ @Override
+ float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
+ // Do nothing
+ return 0;
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java b/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
new file mode 100644
index 0000000..f1d64fb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.CommonGraphics2D;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.render.JavaBlitter;
+import org.apache.harmony.awt.gl.render.NativeImageBlitter;
+
+/**
+ * BufferedImageGraphics2D is implementation of CommonGraphics2D for
+ * drawing on buffered images.
+ */
+public class BufferedImageGraphics2D extends CommonGraphics2D {
+ private BufferedImage bi = null;
+ private Rectangle bounds = null;
+
+ public BufferedImageGraphics2D(BufferedImage bi) {
+ super();
+ this.bi = bi;
+ this.bounds = new Rectangle(0, 0, bi.getWidth(), bi.getHeight());
+ clip(bounds);
+ dstSurf = Surface.getImageSurface(bi);
+ if(dstSurf.isNativeDrawable()){
+ blitter = NativeImageBlitter.getInstance();
+ }else{
+ blitter = JavaBlitter.getInstance();
+ }
+ }
+
+ @Override
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ }
+
+ @Override
+ public Graphics create() {
+ BufferedImageGraphics2D res = new BufferedImageGraphics2D(bi);
+ copyInternalFields(res);
+ return res;
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return null;
+ }
+
+ public ColorModel getColorModel() {
+ return bi.getColorModel();
+ }
+
+ public WritableRaster getWritableRaster() {
+ return bi.getRaster();
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java b/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
new file mode 100644
index 0000000..0fe25a2
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+
+public class BufferedImageSource implements ImageProducer {
+
+ private Hashtable<?, ?> properties;
+ private ColorModel cm;
+ private WritableRaster raster;
+ private int width;
+ private int height;
+
+ private ImageConsumer ic;
+
+ public BufferedImageSource(BufferedImage image, Hashtable<?, ?> properties){
+ if(properties == null) {
+ this.properties = new Hashtable<Object, Object>();
+ } else {
+ this.properties = properties;
+ }
+
+ width = image.getWidth();
+ height = image.getHeight();
+ cm = image.getColorModel();
+ raster = image.getRaster();
+ }
+
+ public BufferedImageSource(BufferedImage image){
+ this(image, null);
+ }
+
+ public boolean isConsumer(ImageConsumer ic) {
+ return (this.ic == ic);
+ }
+
+ public void startProduction(ImageConsumer ic) {
+ addConsumer(ic);
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {
+ }
+
+ public void removeConsumer(ImageConsumer ic) {
+ if (this.ic == ic) {
+ this.ic = null;
+ }
+ }
+
+ public void addConsumer(ImageConsumer ic) {
+ this.ic = ic;
+ startProduction();
+ }
+
+ private void startProduction(){
+ try {
+ ic.setDimensions(width, height);
+ ic.setProperties(properties);
+ ic.setColorModel(cm);
+ ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEFRAME |
+ ImageConsumer.SINGLEPASS);
+ if(cm instanceof IndexColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_BYTE ||
+ cm instanceof ComponentColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_BYTE &&
+ raster.getNumDataElements() == 1){
+ DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer();
+ byte data[] = dbb.getData();
+ int off = dbb.getOffset();
+ ic.setPixels(0, 0, width, height, cm, data, off, width);
+ }else if(cm instanceof DirectColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_INT){
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int off = dbi.getOffset();
+ ic.setPixels(0, 0, width, height, cm, data, off, width);
+ }else if(cm instanceof DirectColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_BYTE){
+ DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer();
+ byte data[] = dbb.getData();
+ int off = dbb.getOffset();
+ ic.setPixels(0, 0, width, height, cm, data, off, width);
+ }else{
+ ColorModel rgbCM = ColorModel.getRGBdefault();
+ int pixels[] = new int[width];
+ Object pix = null;
+ for(int y = 0; y < height; y++){
+ for(int x = 0 ; x < width; x++){
+ pix = raster.getDataElements(x, y, pix);
+ pixels[x] = cm.getRGB(pix);
+ }
+ ic.setPixels(0, y, width, 1, rgbCM, pixels, 0, width);
+ }
+ }
+ ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }catch (NullPointerException e){
+ if (ic != null) {
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
new file mode 100644
index 0000000..cc6d7cf
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 10.02.2005
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+public class ByteArrayDecodingImageSource extends DecodingImageSource {
+
+ byte imagedata[];
+ int imageoffset;
+ int imagelength;
+
+ public ByteArrayDecodingImageSource(byte imagedata[], int imageoffset,
+ int imagelength){
+ this.imagedata = imagedata;
+ this.imageoffset = imageoffset;
+ this.imagelength = imagelength;
+ }
+
+ public ByteArrayDecodingImageSource(byte imagedata[]){
+ this(imagedata, 0, imagedata.length);
+ }
+
+ @Override
+ protected boolean checkConnection() {
+ return true;
+ }
+
+ @Override
+ protected InputStream getInputStream() {
+ // BEGIN android-modified
+ // TODO: Why does a ByteArrayInputStream need to be buffered at all?
+ return new BufferedInputStream(new ByteArrayInputStream(imagedata,
+ imageoffset, imagelength), 1024);
+ // END android-modified
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java b/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
new file mode 100644
index 0000000..8793050
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 13.03.2006
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+public interface DataBufferListener {
+
+ void dataChanged();
+ void dataTaken();
+ void dataReleased();
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
new file mode 100644
index 0000000..958d691
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is an abstract class that encapsulates a main part of ImageProducer functionality
+ * for the images being decoded by the native decoders, like PNG, JPEG and GIF.
+ * It helps to integrate image decoders into producer/consumer model. It provides
+ * functionality for working with several decoder instances and several image consumers
+ * simultaneously.
+ */
+public abstract class DecodingImageSource implements ImageProducer {
+ List<ImageConsumer> consumers = new ArrayList<ImageConsumer>(5);
+ List<ImageDecoder> decoders = new ArrayList<ImageDecoder>(5);
+ boolean loading;
+
+ ImageDecoder decoder;
+
+ protected abstract boolean checkConnection();
+
+ protected abstract InputStream getInputStream();
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if (!checkConnection()) { // No permission for this consumer
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ return;
+ }
+
+ ImageConsumer cons = findConsumer(consumers, ic);
+
+ if (cons == null) { // Try to look in the decoders
+ ImageDecoder d = null;
+
+ // Check for all existing decoders
+ for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+ d = i.next();
+ cons = findConsumer(d.consumers, ic);
+ if (cons != null) {
+ break;
+ }
+ }
+ }
+
+ if (cons == null) { // Not found, add this consumer
+ consumers.add(ic);
+ }
+ }
+
+ /**
+ * This method stops sending data to the given consumer
+ * @param ic - consumer
+ */
+ private void abortConsumer(ImageConsumer ic) {
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ consumers.remove(ic);
+ }
+
+ /**
+ * This method stops sending data to the list of consumers.
+ * @param consumersList - list of consumers
+ */
+ private void abortAllConsumers(List<ImageConsumer> consumersList) {
+ for (ImageConsumer imageConsumer : consumersList) {
+ abortConsumer(imageConsumer);
+ }
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ ImageDecoder d = null;
+
+ // Remove in all existing decoders
+ for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+ d = i.next();
+ removeConsumer(d.consumers, ic);
+ if (d.consumers.size() <= 0) {
+ d.terminate();
+ }
+ }
+
+ // Remove in the current queue of consumers
+ removeConsumer(consumers, ic);
+ }
+
+ /**
+ * Static implementation of removeConsumer method
+ * @param consumersList - list of consumers
+ * @param ic - consumer to be removed
+ */
+ private static void removeConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
+ ImageConsumer cons = null;
+
+ for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
+ cons = i.next();
+ if (cons.equals(ic)) {
+ i.remove();
+ }
+ }
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer consumer) {
+ // Do nothing
+ }
+
+ public synchronized void startProduction(ImageConsumer ic) {
+ if (ic != null) {
+ addConsumer(ic);
+ }
+
+ if (!loading && consumers.size() > 0) {
+ ImageLoader.addImageSource(this);
+ loading = true;
+ }
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ ImageDecoder d = null;
+
+ // Check for all existing decoders
+ for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+ d = i.next();
+ if (findConsumer(d.consumers, ic) != null) {
+ return true;
+ }
+ }
+
+ // Check current queue of consumers
+ return findConsumer(consumers, ic) != null;
+ }
+
+ /**
+ * Checks if the consumer is in the list and returns it it is there
+ * @param consumersList - list of consumers
+ * @param ic - consumer
+ * @return consumer if found, null otherwise
+ */
+ private static ImageConsumer findConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
+ ImageConsumer res = null;
+
+ for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
+ res = i.next();
+ if (res.equals(ic)) {
+ return res;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Use this method to finish decoding or lock the list of consumers
+ * for a particular decoder
+ * @param d - decoder
+ */
+ synchronized void lockDecoder(ImageDecoder d) {
+ if (d == decoder) {
+ decoder = null;
+ startProduction(null);
+ }
+ }
+
+ /**
+ * Tries to find an appropriate decoder for the input stream and adds it
+ * to the list of decoders
+ * @return created decoder
+ */
+ private ImageDecoder createDecoder() {
+ InputStream is = getInputStream();
+
+ ImageDecoder decoder;
+
+ if (is == null) {
+ decoder = null;
+ } else {
+ decoder = ImageDecoder.createDecoder(this, is);
+ }
+
+ if (decoder != null) {
+ synchronized (this) {
+ decoders.add(decoder);
+ this.decoder = decoder;
+ loading = false;
+ consumers = new ArrayList<ImageConsumer>(5); // Reset queue
+ }
+
+ return decoder;
+ }
+ // We were not able to find appropriate decoder
+ List<ImageConsumer> cs;
+ synchronized (this) {
+ cs = consumers;
+ consumers = new ArrayList<ImageConsumer>(5);
+ loading = false;
+ }
+ abortAllConsumers(cs);
+
+ return null;
+ }
+
+ /**
+ * Stop the given decoder and remove it from the list
+ * @param dr - decoder
+ */
+ private synchronized void removeDecoder(ImageDecoder dr) {
+ lockDecoder(dr);
+ decoders.remove(dr);
+ }
+
+ /**
+ * This method serves as an entry point.
+ * It starts the decoder and loads the image data.
+ */
+ public void load() {
+ synchronized (this) {
+ if (consumers.size() == 0) {
+ loading = false;
+ return;
+ }
+ }
+
+ ImageDecoder d = createDecoder();
+ if (d != null) {
+ try {
+ decoder.decodeImage();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ removeDecoder(d);
+ abortAllConsumers(d.consumers);
+ }
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
new file mode 100644
index 0000000..54d4664
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 20.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+public class FileDecodingImageSource extends DecodingImageSource {
+ String filename;
+
+ public FileDecodingImageSource(String file) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(file);
+ }
+
+ filename = file;
+ }
+
+ @Override
+protected boolean checkConnection() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ security.checkRead(filename);
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+protected InputStream getInputStream() {
+ try {
+ // BEGIN android-modified
+ return new BufferedInputStream(new FileInputStream(filename), 8192);
+ // END android-modified
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/GifDecoder.java b/awt/org/apache/harmony/awt/gl/image/GifDecoder.java
new file mode 100644
index 0000000..7ecb15b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/GifDecoder.java
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+* Created on 27.01.2005
+*/
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+public class GifDecoder extends ImageDecoder {
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ static {
+ System.loadLibrary("gl"); //$NON-NLS-1$
+ initIDs();
+ }
+
+ // ImageConsumer hints: common
+ private static final int baseHints =
+ ImageConsumer.SINGLEPASS | ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEFRAME;
+ // ImageConsumer hints: interlaced
+ private static final int interlacedHints =
+ baseHints | ImageConsumer.RANDOMPIXELORDER;
+
+ // Impossible color value - no translucent pixels allowed
+ static final int IMPOSSIBLE_VALUE = 0x0FFFFFFF;
+
+ // I/O buffer
+ private static final int BUFFER_SIZE = 1024;
+ private byte buffer[] = new byte[BUFFER_SIZE];
+
+ GifDataStream gifDataStream = new GifDataStream();
+ GifGraphicBlock currBlock;
+
+ // Pointer to native structure which store decoding state
+ // between subsequent decoding/IO-suspension cycles
+ private long hNativeDecoder; // NULL initially
+
+ // Number of bytes eaten by the native decoder
+ private int bytesConsumed;
+
+ private boolean consumersPrepared;
+ private Hashtable<String, String> properties = new Hashtable<String, String>();
+
+ // Could be set up by java code or native method when
+ // transparent pixel index changes or local color table encountered
+ private boolean forceRGB;
+
+ private byte screenBuffer[];
+ private int screenRGBBuffer[];
+
+ public GifDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ }
+
+ private static native int[] toRGB(byte imageData[], byte colormap[], int transparentColor);
+
+ private static native void releaseNativeDecoder(long hDecoder);
+
+ private native int decode(
+ byte input[],
+ int bytesInBuffer,
+ long hDecoder,
+ GifDataStream dataStream,
+ GifGraphicBlock currBlock
+ );
+
+ private int[] getScreenRGBBuffer() {
+ if (screenRGBBuffer == null) {
+ if (screenBuffer != null) {
+ int transparentColor =
+ gifDataStream.logicalScreen.globalColorTable.cm.getTransparentPixel();
+ transparentColor = transparentColor > 0 ? transparentColor : IMPOSSIBLE_VALUE;
+ screenRGBBuffer =
+ toRGB(
+ screenBuffer,
+ gifDataStream.logicalScreen.globalColorTable.colors,
+ transparentColor
+ );
+ } else {
+ int size = gifDataStream.logicalScreen.logicalScreenHeight *
+ gifDataStream.logicalScreen.logicalScreenWidth;
+ screenRGBBuffer = new int[size];
+ }
+ }
+
+ return screenRGBBuffer;
+ }
+
+ private void prepareConsumers() {
+ GifLogicalScreen gls = gifDataStream.logicalScreen;
+ setDimensions(gls.logicalScreenWidth,
+ gls.logicalScreenHeight);
+ setProperties(properties);
+
+ currBlock = gifDataStream.graphicBlocks.get(0);
+ if (forceRGB) {
+ setColorModel(ColorModel.getRGBdefault());
+ } else {
+ setColorModel(gls.globalColorTable.getColorModel(currBlock.transparentColor));
+ }
+
+ // Fill screen buffer with the background or transparent color
+ if (forceRGB) {
+ int fillColor = 0xFF000000;
+ if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
+ fillColor = gls.backgroundColor;
+ }
+
+ Arrays.fill(getScreenRGBBuffer(), fillColor);
+ } else {
+ int fillColor = 0;
+
+ if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
+ fillColor = gls.backgroundColor;
+ } else {
+ fillColor = gls.globalColorTable.cm.getTransparentPixel();
+ }
+
+ screenBuffer = new byte[gls.logicalScreenHeight*gls.logicalScreenWidth];
+ Arrays.fill(screenBuffer, (byte) fillColor);
+ }
+
+ setHints(interlacedHints); // XXX - always random pixel order
+ }
+
+ @Override
+ public void decodeImage() throws IOException {
+ try {
+ int bytesRead = 0;
+ int needBytes, offset, bytesInBuffer = 0;
+ boolean eosReached = false;
+ GifGraphicBlock blockToDispose = null;
+
+ // Create new graphic block
+ if (currBlock == null) {
+ currBlock = new GifGraphicBlock();
+ gifDataStream.graphicBlocks.add(currBlock);
+ }
+
+ // Read from the input stream
+ for (;;) {
+ needBytes = BUFFER_SIZE - bytesInBuffer;
+ offset = bytesInBuffer;
+
+ bytesRead = inputStream.read(buffer, offset, needBytes);
+
+ if (bytesRead < 0) {
+ eosReached = true;
+ bytesRead = 0;
+ } // Don't break, maybe something left in buffer
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer += bytesRead;
+
+ // Here we pass number of new bytes read from the input stream (bytesRead)
+ // since native decoder uses java buffer and doesn't have its own
+ // buffer. So it adds this number to the number of bytes left
+ // in buffer from the previous call.
+ int numLines = decode(
+ buffer,
+ bytesRead,
+ hNativeDecoder,
+ gifDataStream,
+ currBlock);
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer -= bytesConsumed;
+
+ if (
+ !consumersPrepared &&
+ gifDataStream.logicalScreen.completed &&
+ gifDataStream.logicalScreen.globalColorTable.completed &&
+ (currBlock.imageData != null || // Have transparent pixel filled
+ currBlock.rgbImageData != null)
+ ) {
+ prepareConsumers();
+ consumersPrepared = true;
+ }
+
+ if (bytesConsumed < 0) {
+ break; // Error exit
+ }
+
+ if (currBlock != null) {
+ if (numLines != 0) {
+ // Dispose previous image only before showing next
+ if (blockToDispose != null) {
+ blockToDispose.dispose();
+ blockToDispose = null;
+ }
+
+ currBlock.sendNewData(this, numLines);
+ }
+
+ if (currBlock.completed && hNativeDecoder != 0) {
+ blockToDispose = currBlock; // Dispose only before showing new pixels
+ currBlock = new GifGraphicBlock();
+ gifDataStream.graphicBlocks.add(currBlock);
+ }
+ }
+
+ if (hNativeDecoder == 0) {
+ break;
+ }
+
+ if (eosReached && numLines == 0) { // Maybe image is truncated...
+ releaseNativeDecoder(hNativeDecoder);
+ break;
+ }
+ }
+ } finally {
+ closeStream();
+ }
+
+ // Here all animation goes
+ // Repeat image loopCount-1 times or infinitely if loopCount = 0
+ if (gifDataStream.loopCount != 1) {
+ if (currBlock.completed == false) {
+ gifDataStream.graphicBlocks.remove(currBlock);
+ }
+
+ int numFrames = gifDataStream.graphicBlocks.size();
+ // At first last block will be disposed
+ GifGraphicBlock gb =
+ gifDataStream.graphicBlocks.get(numFrames-1);
+
+ ImageLoader.beginAnimation();
+
+ while (gifDataStream.loopCount != 1) {
+ if (gifDataStream.loopCount != 0) {
+ gifDataStream.loopCount--;
+ }
+
+ // Show all frames
+ for (int i=0; i<numFrames; i++) {
+ gb.dispose();
+ gb = gifDataStream.graphicBlocks.get(i);
+
+ // Show one frame
+ if (forceRGB) {
+ setPixels(
+ gb.imageLeft,
+ gb.imageTop,
+ gb.imageWidth,
+ gb.imageHeight,
+ ColorModel.getRGBdefault(),
+ gb.getRgbImageData(),
+ 0,
+ gb.imageWidth
+ );
+ } else {
+ setPixels(
+ gb.imageLeft,
+ gb.imageTop,
+ gb.imageWidth,
+ gb.imageHeight,
+ null,
+ gb.imageData,
+ 0,
+ gb.imageWidth
+ );
+ }
+ }
+ }
+ ImageLoader.endAnimation();
+ }
+
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }
+
+ void setComment(String newComment) {
+ Object currComment = properties.get("comment"); //$NON-NLS-1$
+
+ if (currComment == null) {
+ properties.put("comment", newComment); //$NON-NLS-1$
+ } else {
+ properties.put("comment", (String) currComment + "\n" + newComment); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ setProperties(properties);
+ }
+
+ class GifDataStream {
+ // Indicates that reading of the whole data stream accomplished
+ boolean completed = false;
+
+ // Added to support Netscape 2.0 application
+ // extension block.
+ int loopCount = 1;
+
+ GifLogicalScreen logicalScreen = new GifLogicalScreen();
+ List<GifGraphicBlock> graphicBlocks = new ArrayList<GifGraphicBlock>(10); // Of GifGraphicBlocks
+
+ // Comments from the image
+ String comments[];
+ }
+
+ class GifLogicalScreen {
+ // Indicates that reading of this block accomplished
+ boolean completed = false;
+
+ int logicalScreenWidth;
+ int logicalScreenHeight;
+
+ int backgroundColor = IMPOSSIBLE_VALUE;
+
+ GifColorTable globalColorTable = new GifColorTable();
+ }
+
+ class GifGraphicBlock {
+ // Indicates that reading of this block accomplished
+ boolean completed = false;
+
+ final static int DISPOSAL_NONE = 0;
+ final static int DISPOSAL_NODISPOSAL = 1;
+ final static int DISPOSAL_BACKGROUND = 2;
+ final static int DISPOSAL_RESTORE = 3;
+
+ int disposalMethod;
+ int delayTime; // Multiplied by 10 already
+ int transparentColor = IMPOSSIBLE_VALUE;
+
+ int imageLeft;
+ int imageTop;
+ int imageWidth;
+ int imageHeight;
+
+ // Auxilliary variables to minimize computations
+ int imageRight;
+ int imageBottom;
+
+ boolean interlace;
+
+ // Don't need local color table - if it is specified
+ // image data are converted to RGB in the native code
+
+ byte imageData[] = null;
+ int rgbImageData[] = null;
+
+ private int currY = 0; // Current output scanline
+
+ int[] getRgbImageData() {
+ if (rgbImageData == null) {
+ rgbImageData =
+ toRGB(
+ imageData,
+ gifDataStream.logicalScreen.globalColorTable.colors,
+ transparentColor
+ );
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ transparentColor =
+ gifDataStream.logicalScreen.globalColorTable.cm.getRGB(transparentColor);
+ transparentColor &= 0x00FFFFFF;
+ }
+ }
+ return rgbImageData;
+ }
+
+ private void replaceTransparentPixels(int numLines) {
+ List<GifGraphicBlock> graphicBlocks = gifDataStream.graphicBlocks;
+ int prevBlockIndex = graphicBlocks.indexOf(this) - 1;
+
+ if (prevBlockIndex >= 0) {
+ int maxY = currY + numLines + imageTop;
+ int offset = currY * imageWidth;
+
+ // Update right and bottom coordinates
+ imageRight = imageLeft + imageWidth;
+ imageBottom = imageTop + imageHeight;
+
+ int globalWidth = gifDataStream.logicalScreen.logicalScreenWidth;
+ int pixelValue, imageOffset;
+ int rgbData[] = forceRGB ? getRgbImageData() : null;
+
+ for (int y = currY + imageTop; y < maxY; y++) {
+ imageOffset = globalWidth * y + imageLeft;
+ for (int x = imageLeft; x < imageRight; x++) {
+ pixelValue = forceRGB ?
+ rgbData[offset] :
+ imageData[offset] & 0xFF;
+ if (pixelValue == transparentColor) {
+ if (forceRGB) {
+ pixelValue = getScreenRGBBuffer() [imageOffset];
+ rgbData[offset] = pixelValue;
+ } else {
+ pixelValue = screenBuffer [imageOffset];
+ imageData[offset] = (byte) pixelValue;
+ }
+ }
+ offset++;
+ imageOffset++;
+ } // for
+ } // for
+
+ } // if (prevBlockIndex >= 0)
+ }
+
+ public void sendNewData(GifDecoder decoder, int numLines) {
+ // Get values for transparent pixels
+ // from the perevious frames
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ replaceTransparentPixels(numLines);
+ }
+
+ if (forceRGB) {
+ decoder.setPixels(
+ imageLeft,
+ imageTop + currY,
+ imageWidth,
+ numLines,
+ ColorModel.getRGBdefault(),
+ getRgbImageData(),
+ currY*imageWidth,
+ imageWidth
+ );
+ } else {
+ decoder.setPixels(
+ imageLeft,
+ imageTop + currY,
+ imageWidth,
+ numLines,
+ null,
+ imageData,
+ currY*imageWidth,
+ imageWidth
+ );
+ }
+
+ currY += numLines;
+ }
+
+ public void dispose() {
+ imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+
+ // Show current frame until delayInterval will not elapse
+ if (delayTime > 0) {
+ try {
+ Thread.sleep(delayTime);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ Thread.yield(); // Allow consumers to consume data
+ }
+
+ // Don't dispose if image is outside of the visible area
+ if (imageLeft > gifDataStream.logicalScreen.logicalScreenWidth ||
+ imageTop > gifDataStream.logicalScreen.logicalScreenHeight) {
+ disposalMethod = DISPOSAL_NONE;
+ }
+
+ switch(disposalMethod) {
+ case DISPOSAL_BACKGROUND: {
+ if (forceRGB) {
+ getRgbImageData(); // Ensure that transparentColor is RGB, not index
+
+ int data[] = new int[imageWidth*imageHeight];
+
+ // Compatibility: Fill with transparent color if we have one
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ Arrays.fill(
+ data,
+ transparentColor
+ );
+ } else {
+ Arrays.fill(
+ data,
+ gifDataStream.logicalScreen.backgroundColor
+ );
+ }
+
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ ColorModel.getRGBdefault(),
+ data,
+ 0,
+ imageWidth
+ );
+
+ sendToScreenBuffer(data);
+ } else {
+ byte data[] = new byte[imageWidth*imageHeight];
+
+ // Compatibility: Fill with transparent color if we have one
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ Arrays.fill(
+ data,
+ (byte) transparentColor
+ );
+ } else {
+ Arrays.fill(
+ data,
+ (byte) gifDataStream.logicalScreen.backgroundColor
+ );
+ }
+
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ null,
+ data,
+ 0,
+ imageWidth
+ );
+
+ sendToScreenBuffer(data);
+ }
+ break;
+ }
+ case DISPOSAL_RESTORE: {
+ screenBufferToScreen();
+ break;
+ }
+ case DISPOSAL_NONE:
+ case DISPOSAL_NODISPOSAL:
+ default: {
+ // Copy transmitted data to the screen buffer
+ Object data = forceRGB ? (Object) getRgbImageData() : imageData;
+ sendToScreenBuffer(data);
+ break;
+ }
+ }
+ }
+
+ private void sendToScreenBuffer(Object data) {
+ int dataInt[];
+ byte dataByte[];
+
+ int width = gifDataStream.logicalScreen.logicalScreenWidth;
+
+
+ if (forceRGB) {
+ dataInt = (int[]) data;
+
+ if (imageWidth == width) {
+ System.arraycopy(dataInt,
+ 0,
+ getScreenRGBBuffer(),
+ imageLeft + imageTop*width,
+ dataInt.length
+ );
+ } else { // Each scanline
+ copyScanlines(dataInt, getScreenRGBBuffer(), width);
+ }
+ } else {
+ dataByte = (byte[]) data;
+
+ if (imageWidth == width) {
+ System.arraycopy(dataByte,
+ 0,
+ screenBuffer,
+ imageLeft + imageTop*width,
+ dataByte.length
+ );
+ } else { // Each scanline
+ copyScanlines(dataByte, screenBuffer, width);
+ }
+ }
+ } // sendToScreenBuffer
+
+ private void copyScanlines(Object src, Object dst, int width) {
+ for (int i=0; i<imageHeight; i++) {
+ System.arraycopy(src,
+ i*imageWidth,
+ dst,
+ imageLeft + i*width + imageTop*width,
+ imageWidth
+ );
+ } // for
+ }
+
+ private void screenBufferToScreen() {
+ int width = gifDataStream.logicalScreen.logicalScreenWidth;
+
+ Object dst = forceRGB ?
+ (Object) new int[imageWidth*imageHeight] :
+ new byte[imageWidth*imageHeight];
+
+ Object src = forceRGB ?
+ getScreenRGBBuffer() :
+ (Object) screenBuffer;
+
+ int offset = 0;
+ Object toSend;
+
+ if (width == imageWidth) {
+ offset = imageWidth * imageTop;
+ toSend = src;
+ } else {
+ for (int i=0; i<imageHeight; i++) {
+ System.arraycopy(src,
+ imageLeft + i*width + imageTop*width,
+ dst,
+ i*imageWidth,
+ imageWidth
+ );
+ } // for
+ toSend = dst;
+ }
+
+ if (forceRGB) {
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ ColorModel.getRGBdefault(),
+ (int [])toSend,
+ offset,
+ imageWidth
+ );
+ } else {
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ null,
+ (byte [])toSend,
+ offset,
+ imageWidth
+ );
+ }
+ }
+ }
+
+ class GifColorTable {
+ // Indicates that reading of this block accomplished
+ boolean completed = false;
+
+ IndexColorModel cm = null;
+ int size = 0; // Actual number of colors in the color table
+ byte colors[] = new byte[256*3];
+
+ IndexColorModel getColorModel(int transparentColor) {
+ if (cm != null) {
+ if (transparentColor != cm.getTransparentPixel()) {
+ return cm = null; // Force default ARGB color model
+ }
+ return cm;
+ } else
+ if (completed && size > 0) {
+ if (transparentColor == IMPOSSIBLE_VALUE) {
+ return cm =
+ new IndexColorModel(8, size, colors, 0, false);
+ }
+
+ if (transparentColor > size) {
+ size = transparentColor + 1;
+ }
+ return cm =
+ new IndexColorModel(8, size, colors, 0, false, transparentColor);
+ }
+
+ return cm = null; // Force default ARGB color model
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java b/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
new file mode 100644
index 0000000..d16128e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import com.android.internal.awt.AndroidImageDecoder;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ConcurrentModificationException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * This class contains common functionality for all image decoders.
+ */
+public abstract class ImageDecoder {
+
+ /** Image types */
+ public static final int GENERIC_DECODER = 0;
+ public static final int JPG_DECODER = 1;
+ public static final int GIF_DECODER = 2;
+ public static final int PNG_DECODER = 3;
+
+ private static final int MAX_BYTES_IN_SIGNATURE = 8;
+
+ protected List<ImageConsumer> consumers;
+ protected InputStream inputStream;
+ protected DecodingImageSource src;
+
+ protected boolean terminated;
+
+ /**
+ * Chooses appropriate image decoder by looking into input stream and checking
+ * the image signature.
+ * @param src - image producer, required for passing data to it from the
+ * created decoder via callbacks
+ * @param is - stream
+ * @return decoder
+ */
+ static ImageDecoder createDecoder(DecodingImageSource src, InputStream is) {
+ InputStream markable;
+
+ if (!is.markSupported()) {
+ // BEGIN android-modified
+ markable = new BufferedInputStream(is, 8192);
+ // END android-modified
+ } else {
+ markable = is;
+ }
+
+ // Read the signature from the stream and then reset it back
+ try {
+ markable.mark(MAX_BYTES_IN_SIGNATURE);
+
+ byte[] signature = new byte[MAX_BYTES_IN_SIGNATURE];
+ markable.read(signature, 0, MAX_BYTES_IN_SIGNATURE);
+ markable.reset();
+
+ if ((signature[0] & 0xFF) == 0xFF &&
+ (signature[1] & 0xFF) == 0xD8 &&
+ (signature[2] & 0xFF) == 0xFF) { // JPEG
+ return loadDecoder(PNG_DECODER, src, is);
+ } else if ((signature[0] & 0xFF) == 0x47 && // G
+ (signature[1] & 0xFF) == 0x49 && // I
+ (signature[2] & 0xFF) == 0x46) { // F
+ return loadDecoder(GIF_DECODER, src, is);
+ } else if ((signature[0] & 0xFF) == 137 && // PNG signature: 137 80 78 71 13 10 26 10
+ (signature[1] & 0xFF) == 80 &&
+ (signature[2] & 0xFF) == 78 &&
+ (signature[3] & 0xFF) == 71 &&
+ (signature[4] & 0xFF) == 13 &&
+ (signature[5] & 0xFF) == 10 &&
+ (signature[6] & 0xFF) == 26 &&
+ (signature[7] & 0xFF) == 10) {
+ return loadDecoder(JPG_DECODER, src, is);
+ }
+
+ return loadDecoder(GENERIC_DECODER, src, is);
+
+ } catch (IOException e) { // Silently
+ }
+
+ return null;
+ }
+
+ /*
+ * In the future, we might return different decoders for differen image types.
+ * But for now, we always return the generic one.
+ * Also: we could add a factory to load image decoder.
+ */
+ private static ImageDecoder loadDecoder(int type, DecodingImageSource src,
+ InputStream is) {
+ return new AndroidImageDecoder(src, is);
+ }
+
+ protected ImageDecoder(DecodingImageSource _src, InputStream is) {
+ src = _src;
+ consumers = src.consumers;
+ inputStream = is;
+ }
+
+ public abstract void decodeImage() throws IOException;
+
+ public synchronized void closeStream() {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ /**
+ * Stops the decoding by interrupting the current decoding thread.
+ * Used when all consumers are removed and there's no more need to
+ * run the decoder.
+ */
+ public void terminate() {
+ src.lockDecoder(this);
+ closeStream();
+
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+ }
+ );
+
+ terminated = true;
+ }
+
+ protected void setDimensions(int w, int h) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setDimensions(w, h);
+ }
+ }
+
+ protected void setProperties(Hashtable<?, ?> props) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setProperties(props);
+ }
+ }
+
+ protected void setColorModel(ColorModel cm) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setColorModel(cm);
+ }
+ }
+
+ protected void setHints(int hints) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setHints(hints);
+ }
+ }
+
+ protected void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model,
+ byte pix[],
+ int off, int scansize
+ ) {
+ if (terminated) {
+ return;
+ }
+
+ src.lockDecoder(this);
+
+ for (ImageConsumer ic : consumers) {
+ ic.setPixels(x, y, w, h, model, pix, off, scansize);
+ }
+ }
+
+ protected void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model,
+ int pix[],
+ int off, int scansize
+ ) {
+ if (terminated) {
+ return;
+ }
+
+ src.lockDecoder(this);
+
+ for (ImageConsumer ic : consumers) {
+ ic.setPixels(x, y, w, h, model, pix, off, scansize);
+ }
+ }
+
+ protected void imageComplete(int status) {
+ if (terminated) {
+ return;
+ }
+
+ src.lockDecoder(this);
+
+ ImageConsumer ic = null;
+
+ for (Iterator<ImageConsumer> i = consumers.iterator(); i.hasNext();) {
+ try {
+ ic = i.next();
+ } catch (ConcurrentModificationException e) {
+ i = consumers.iterator();
+ continue;
+ }
+ ic.imageComplete(status);
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ImageLoader.java b/awt/org/apache/harmony/awt/gl/image/ImageLoader.java
new file mode 100644
index 0000000..5c7d180
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ImageLoader.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class provides functionality for simultaneous loading of
+ * several images and running animation.
+ */
+public class ImageLoader extends Thread {
+ // Contains ImageLoader objects
+ // and queue of image sources waiting to be loaded
+ static class ImageLoadersStorage {
+ private static final int MAX_THREADS = 5;
+ private static final int TIMEOUT = 4000;
+ static ImageLoadersStorage instance;
+
+ List<DecodingImageSource> queue = new LinkedList<DecodingImageSource>();
+ List<Thread> loaders = new ArrayList<Thread>(MAX_THREADS);
+
+ private int freeLoaders;
+
+ private ImageLoadersStorage() {}
+
+ static ImageLoadersStorage getStorage() {
+ if (instance == null) {
+ instance = new ImageLoadersStorage();
+ }
+
+ return instance;
+ }
+ }
+
+ ImageLoader() {
+ super();
+ setDaemon(true);
+ }
+
+ /**
+ * This method creates a new thread which is able to load an image
+ * or run animation (if the number of existing loader threads does not
+ * exceed the limit).
+ */
+ private static void createLoader() {
+ final ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+ synchronized(storage.loaders) {
+ if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS) {
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ ImageLoader loader = new ImageLoader();
+ storage.loaders.add(loader);
+ loader.start();
+ return null;
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Adds a new image source to the queue and starts a new loader
+ * thread if required
+ * @param imgSrc - image source
+ */
+ public static void addImageSource(DecodingImageSource imgSrc) {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+ synchronized(storage.queue) {
+ if (!storage.queue.contains(imgSrc)) {
+ storage.queue.add(imgSrc);
+ }
+ if (storage.freeLoaders == 0) {
+ createLoader();
+ }
+
+ storage.queue.notify();
+ }
+ }
+
+ /**
+ * Waits for a new ImageSource until timout expires.
+ * Loader thread will terminate after returning from this method
+ * if timeout expired and image source was not picked up from the queue.
+ * @return image source picked up from the queue or null if timeout expired
+ */
+ private static DecodingImageSource getWaitingImageSource() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+ synchronized(storage.queue) {
+ DecodingImageSource isrc = null;
+
+ if (storage.queue.size() == 0) {
+ try {
+ storage.freeLoaders++;
+ storage.queue.wait(ImageLoadersStorage.TIMEOUT);
+ } catch (InterruptedException e) {
+ return null;
+ } finally {
+ storage.freeLoaders--;
+ }
+ }
+
+ if (storage.queue.size() > 0) {
+ isrc = storage.queue.get(0);
+ storage.queue.remove(0);
+ }
+
+ return isrc;
+ }
+ }
+
+ /**
+ * Entry point of the loader thread. Picks up image sources and
+ * runs decoders for them while there are available image sources in the queue.
+ * If there are no and timeout expires it terminates.
+ */
+ @Override
+ public void run() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+ try {
+ while (storage.loaders.contains(this)) {
+ Thread.interrupted(); // Reset the interrupted flag
+ DecodingImageSource isrc = getWaitingImageSource();
+ if (isrc != null) {
+ try {
+ isrc.load();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ break; // Don't wait if timeout expired - terminate loader
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ synchronized(storage.loaders) {
+ storage.loaders.remove(Thread.currentThread());
+ }
+ }
+ }
+
+ /**
+ * Removes current thread from loaders (so we are able
+ * to create more loaders) and decreases its priority.
+ */
+ static void beginAnimation() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+ Thread currThread = Thread.currentThread();
+
+ synchronized(storage) {
+ storage.loaders.remove(currThread);
+
+ if (storage.freeLoaders < storage.queue.size()) {
+ createLoader();
+ }
+ }
+
+ currThread.setPriority(Thread.MIN_PRIORITY);
+ }
+
+ /**
+ * Sends the current thread to wait for the new images to load
+ * if there are free placeholders for loaders
+ */
+ static void endAnimation() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+ Thread currThread = Thread.currentThread();
+
+ synchronized(storage) {
+ if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS &&
+ !storage.loaders.contains(currThread)
+ ) {
+ storage.loaders.add(currThread);
+ }
+ }
+
+ currThread.setPriority(Thread.NORM_PRIORITY);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java b/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
new file mode 100644
index 0000000..2e64427
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
@@ -0,0 +1,231 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.*;
+import java.awt.color.ColorSpace;
+import java.awt.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class JpegDecoder extends ImageDecoder {
+ // Only 2 output colorspaces expected. Others are converted into
+ // these ones.
+ // 1. Grayscale
+ public static final int JCS_GRAYSCALE = 1;
+ // 2. RGB
+ public static final int JCS_RGB = 2;
+
+ // Flags for the consumer, progressive JPEG
+ private static final int hintflagsProgressive =
+ ImageConsumer.SINGLEFRAME | // JPEG is a static image
+ ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+ ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+ // Flags for the consumer, singlepass JPEG
+ private static final int hintflagsSingle =
+ ImageConsumer.SINGLEPASS |
+ hintflagsProgressive;
+
+ // Buffer for the stream
+ private static final int BUFFER_SIZE = 1024;
+ private byte buffer[] = new byte[BUFFER_SIZE];
+
+ // 3 possible color models only
+ private static ColorModel cmRGB;
+ private static ColorModel cmGray;
+
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ // Pointer to native structure which store decoding state
+ // between subsequent decoding/IO-suspension cycles
+ private long hNativeDecoder = 0; // NULL initially
+
+ private boolean headerDone = false;
+
+ // Next 4 members are filled by the native method (decompress).
+ // We can simply check if imageWidth is still negative to find
+ // out if they are already filled.
+ private int imageWidth = -1;
+ private int imageHeight = -1;
+ private boolean progressive = false;
+ private int jpegColorSpace = 0;
+
+ // Stores number of bytes consumed by the native decoder
+ private int bytesConsumed = 0;
+ // Stores current scanline returned by the decoder
+ private int currScanline = 0;
+
+ private ColorModel cm = null;
+
+ static {
+ System.loadLibrary("jpegdecoder"); //$NON-NLS-1$
+
+ cmGray = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ false, false,
+ Transparency.OPAQUE, DataBuffer.TYPE_BYTE
+ );
+
+ // Create RGB color model
+ cmRGB = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+
+ initIDs();
+ }
+
+ public JpegDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ }
+
+ /*
+ public JpegDecoder(InputStream iStream, ImageConsumer iConsumer) {
+ inputStream = iStream;
+ consumer = iConsumer;
+ }
+ */
+
+ /**
+ * @return - not NULL if call is successful
+ */
+ private native Object decode(
+ byte[] input,
+ int bytesInBuffer,
+ long hDecoder);
+
+ private static native void releaseNativeDecoder(long hDecoder);
+
+ @Override
+ public void decodeImage() throws IOException {
+ try {
+ int bytesRead = 0, dataLength = 0;
+ boolean eosReached = false;
+ int needBytes, offset, bytesInBuffer = 0;
+ byte byteOut[] = null;
+ int intOut[] = null;
+ // Read from the input stream
+ for (;;) {
+ needBytes = BUFFER_SIZE - bytesInBuffer;
+ offset = bytesInBuffer;
+
+ bytesRead = inputStream.read(buffer, offset, needBytes);
+
+ if (bytesRead < 0) {
+ bytesRead = 0;//break;
+ eosReached = true;
+ } // Don't break, maybe something left in buffer
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer += bytesRead;
+
+ // Here we pass overall number of bytes left in the java buffer
+ // (bytesInBuffer) since jpeg decoder has its own buffer and consumes
+ // as many bytes as it can. If there are any unconsumed bytes
+ // it didn't add them to its buffer...
+ Object arr = decode(
+ buffer,
+ bytesInBuffer,
+ hNativeDecoder);
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer -= bytesConsumed;
+
+ if (!headerDone && imageWidth != -1) {
+ returnHeader();
+ headerDone = true;
+ }
+
+ if (bytesConsumed < 0) {
+ break; // Error exit
+ }
+
+ if (arr instanceof byte[]) {
+ byteOut = (byte[]) arr;
+ dataLength = byteOut.length;
+ returnData(byteOut, currScanline);
+ } else if (arr instanceof int[]) {
+ intOut = (int[]) arr;
+ dataLength = intOut.length;
+ returnData(intOut, currScanline);
+ } else {
+ dataLength = 0;
+ }
+
+ if (hNativeDecoder == 0) {
+ break;
+ }
+
+ if (dataLength == 0 && eosReached) {
+ releaseNativeDecoder(hNativeDecoder);
+ break; // Probably image is truncated
+ }
+ }
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ closeStream();
+ }
+ }
+
+ public void returnHeader() {
+ setDimensions(imageWidth, imageHeight);
+
+ switch (jpegColorSpace) {
+ case JCS_GRAYSCALE: cm = cmGray; break;
+ case JCS_RGB: cm = cmRGB; break;
+ default:
+ // awt.3D=Unknown colorspace
+ throw new IllegalArgumentException(Messages.getString("awt.3D")); //$NON-NLS-1$
+ }
+ setColorModel(cm);
+
+ setHints(progressive ? hintflagsProgressive : hintflagsSingle);
+
+ setProperties(new Hashtable<Object, Object>()); // Empty
+ }
+
+ // Send the data to the consumer
+ public void returnData(int data[], int currScanLine) {
+ // Send 1 or more scanlines to the consumer.
+ int numScanlines = data.length / imageWidth;
+ if (numScanlines > 0) {
+ setPixels(
+ 0, currScanLine - numScanlines,
+ imageWidth, numScanlines,
+ cm, data, 0, imageWidth
+ );
+ }
+ }
+
+ public void returnData(byte data[], int currScanLine) {
+ int numScanlines = data.length / imageWidth;
+ if (numScanlines > 0) {
+ setPixels(
+ 0, currScanLine - numScanlines,
+ imageWidth, numScanlines,
+ cm, data, 0, imageWidth
+ );
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java b/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
new file mode 100644
index 0000000..3445f8e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
@@ -0,0 +1,532 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 22.12.2004
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent implementation of abstract Image class
+ */
+public class OffscreenImage extends Image implements ImageConsumer {
+
+ static final ColorModel rgbCM = ColorModel.getRGBdefault();
+ ImageProducer src;
+ BufferedImage image;
+ ColorModel cm;
+ WritableRaster raster;
+ boolean isIntRGB;
+ Hashtable<?, ?> properties;
+ Vector<ImageObserver> observers;
+ int width;
+ int height;
+ int imageState;
+ int hints;
+ private boolean producing;
+ private ImageSurface imageSurf;
+
+ public OffscreenImage(ImageProducer ip){
+ imageState = 0;
+ src = ip;
+ width = -1;
+ height = -1;
+ observers = new Vector<ImageObserver>();
+ producing = false;
+ }
+
+ @Override
+ public Object getProperty(String name, ImageObserver observer) {
+ if(name == null) {
+ // awt.38=Property name is not defined
+ throw new NullPointerException(Messages.getString("awt.38")); //$NON-NLS-1$
+ }
+ if(properties == null){
+ addObserver(observer);
+ startProduction();
+ if(properties == null) {
+ return null;
+ }
+ }
+ Object prop = properties.get(name);
+ if(prop == null) {
+ prop = UndefinedProperty;
+ }
+ return prop;
+ }
+
+ @Override
+ public ImageProducer getSource() {
+ return src;
+ }
+
+ @Override
+ public int getWidth(ImageObserver observer) {
+ if((imageState & ImageObserver.WIDTH) == 0){
+ addObserver(observer);
+ startProduction();
+ if((imageState & ImageObserver.WIDTH) == 0) {
+ return -1;
+ }
+ }
+ return width;
+ }
+
+ @Override
+ public int getHeight(ImageObserver observer) {
+ if((imageState & ImageObserver.HEIGHT) == 0){
+ addObserver(observer);
+ startProduction();
+ if((imageState & ImageObserver.HEIGHT) == 0) {
+ return -1;
+ }
+ }
+ return height;
+ }
+
+ @Override
+ public Graphics getGraphics() {
+ // awt.39=This method is not implemented for image obtained from ImageProducer
+ throw new UnsupportedOperationException(Messages.getString("awt.39")); //$NON-NLS-1$
+ }
+
+ @Override
+ public void flush() {
+ stopProduction();
+ imageUpdate(this, ImageObserver.ABORT, -1, -1, -1, -1);
+ imageState &= ~ImageObserver.ERROR;
+ imageState = 0;
+ image = null;
+ cm = null;
+ raster = null;
+ hints = 0;
+ width = -1;
+ height = -1;
+ }
+
+ public void setProperties(Hashtable<?, ?> properties) {
+ this.properties = properties;
+ imageUpdate(this, ImageObserver.PROPERTIES, 0, 0, width, height);
+ }
+
+ public void setColorModel(ColorModel cm) {
+ this.cm = cm;
+ }
+
+ /*
+ * We suppose what in case loading JPEG image then image has DirectColorModel
+ * and for infill image Raster will use setPixels method with int array.
+ *
+ * In case loading GIF image, for raster infill, is used setPixels method with
+ * byte array and Color Model is IndexColorModel. But Color Model may
+ * be changed during this process. Then is called setPixels method with
+ * int array and image force to default color model - int ARGB. The rest
+ * pixels are sending in DirectColorModel.
+ */
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ int[] pixels, int off, int scansize) {
+ if(raster == null){
+ if(cm == null){
+ if(model == null) {
+ // awt.3A=Color Model is null
+ throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
+ }
+ cm = model;
+ }
+ createRaster();
+ }
+
+ if(model == null) {
+ model = cm;
+ }
+ if(cm != model){
+ forceToIntARGB();
+ }
+
+ if(cm == model && model.getTransferType() == DataBuffer.TYPE_INT &&
+ raster.getNumDataElements() == 1){
+
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int scanline = raster.getWidth();
+ int rof = dbi.getOffset() + y * scanline + x;
+ for(int lineOff = off, line = y; line < y + h;
+ line++, lineOff += scansize, rof += scanline){
+
+ System.arraycopy(pixels, lineOff, data, rof, w);
+ }
+
+ }else if(isIntRGB){
+ int buff[] = new int[w];
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int scanline = raster.getWidth();
+ int rof = dbi.getOffset() + y * scanline + x;
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+ rof += scanline) {
+
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ buff[idx] = model.getRGB(pixels[sOff + idx]);
+ }
+ System.arraycopy(buff, 0, data, rof, w);
+ }
+ }else{
+ Object buf = null;
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ int rgb = model.getRGB(pixels[sOff + idx]);
+ buf = cm.getDataElements(rgb, buf);
+ raster.setDataElements(sx, sy, buf);
+ }
+ }
+ }
+
+ if (imageSurf != null) {
+ imageSurf.invalidate();
+ }
+
+ imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
+ }
+
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ byte[] pixels, int off, int scansize) {
+
+ if(raster == null){
+ if(cm == null){
+ if(model == null) {
+ // awt.3A=Color Model is null
+ throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
+ }
+ cm = model;
+ }
+ createRaster();
+ }
+ if(model == null) {
+ model = cm;
+ }
+ if(model != cm){
+ forceToIntARGB();
+ }
+
+ if(isIntRGB){
+ int buff[] = new int[w];
+ IndexColorModel icm = (IndexColorModel) model;
+ int colorMap[] = new int[icm.getMapSize()];
+ icm.getRGBs(colorMap);
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int scanline = raster.getWidth();
+ int rof = dbi.getOffset() + y * scanline + x;
+ if(model instanceof IndexColorModel){
+
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+ rof += scanline) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ buff[idx] = colorMap[pixels[sOff + idx] & 0xff];
+ }
+ System.arraycopy(buff, 0, data, rof, w);
+ }
+ }else{
+
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+ rof += scanline) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ buff[idx] = model.getRGB(pixels[sOff + idx] & 0xff);
+ }
+ System.arraycopy(buff, 0, data, rof, w);
+ }
+ }
+ }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
+ raster.getNumDataElements() == 1){
+
+ DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer();
+ byte data[] = dbb.getData();
+ int scanline = raster.getWidth();
+ int rof = dbb.getOffset() + y * scanline + x;
+ for(int lineOff = off, line = y; line < y + h;
+ line++, lineOff += scansize, rof += scanline){
+ System.arraycopy(pixels, lineOff, data, rof, w);
+ }
+ // BEGIN android-added (taken from newer Harmony)
+ }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
+ cm instanceof ComponentColorModel){
+
+ int nc = cm.getNumComponents();
+ byte stride[] = new byte[scansize];
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+ System.arraycopy(pixels, sOff, stride, 0, scansize);
+
+ raster.setDataElements(x, sy, w, 1, stride);
+ }
+ // END android-added
+ }else {
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ int rgb = model.getRGB(pixels[sOff + idx] & 0xff);
+ raster.setDataElements(sx, sy, cm.getDataElements(rgb, null));
+ }
+ }
+ }
+
+ if (imageSurf != null) {
+ imageSurf.invalidate();
+ }
+
+ imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
+ }
+
+ public void setDimensions(int width, int height) {
+ if(width <= 0 || height <= 0){
+ imageComplete(ImageObserver.ERROR);
+ return;
+ }
+
+ this.width = width;
+ this.height = height;
+ imageUpdate(this, (ImageObserver.HEIGHT | ImageObserver.WIDTH),
+ 0, 0, width, height);
+ }
+
+ public void setHints(int hints) {
+ this.hints = hints;
+ }
+
+ public void imageComplete(int state) {
+ int flag;
+ switch(state){
+ case IMAGEABORTED:
+ flag = ImageObserver.ABORT;
+ break;
+ case IMAGEERROR:
+ flag = ImageObserver.ERROR | ImageObserver.ABORT;
+ break;
+ case SINGLEFRAMEDONE:
+ flag = ImageObserver.FRAMEBITS;
+ break;
+ case STATICIMAGEDONE:
+ flag = ImageObserver.ALLBITS;
+ break;
+ default:
+ // awt.3B=Incorrect ImageConsumer completion status
+ throw new IllegalArgumentException(Messages.getString("awt.3B")); //$NON-NLS-1$
+ }
+ imageUpdate(this, flag, 0, 0, width, height);
+
+ if((flag & (ImageObserver.ERROR | ImageObserver.ABORT |
+ ImageObserver.ALLBITS)) != 0 ) {
+ stopProduction();
+ observers.removeAllElements();
+ }
+ }
+
+ public /*synchronized*/ BufferedImage getBufferedImage(){
+ if(image == null){
+ ColorModel model = getColorModel();
+ WritableRaster wr = getRaster();
+ if(model != null && wr != null) {
+ image = new BufferedImage(model, wr, model.isAlphaPremultiplied(), null);
+ }
+ }
+ return image;
+ }
+
+ public /*synchronized*/ int checkImage(ImageObserver observer){
+ addObserver(observer);
+ return imageState;
+ }
+
+ public /*synchronized*/ boolean prepareImage(ImageObserver observer){
+ if((imageState & ImageObserver.ERROR) != 0){
+ if(observer != null){
+ observer.imageUpdate(this, ImageObserver.ERROR |
+ ImageObserver.ABORT, -1, -1, -1, -1);
+ }
+ return false;
+ }
+ if((imageState & ImageObserver.ALLBITS) != 0) {
+ return true;
+ }
+ addObserver(observer);
+ startProduction();
+ return ((imageState & ImageObserver.ALLBITS) != 0);
+ }
+
+ public /*synchronized*/ ColorModel getColorModel(){
+ if(cm == null) {
+ startProduction();
+ }
+ return cm;
+ }
+
+ public /*synchronized*/ WritableRaster getRaster(){
+ if(raster == null) {
+ startProduction();
+ }
+ return raster;
+ }
+
+ public int getState(){
+ return imageState;
+ }
+
+ private /*synchronized*/ void addObserver(ImageObserver observer){
+ if(observer != null){
+ if(observers.contains(observer)) {
+ return;
+ }
+ if((imageState & ImageObserver.ERROR) != 0){
+ observer.imageUpdate(this, ImageObserver.ERROR |
+ ImageObserver.ABORT, -1, -1, -1, -1);
+ return;
+ }
+ if((imageState & ImageObserver.ALLBITS) != 0){
+ observer.imageUpdate(this, imageState, 0, 0, width, height);
+ return;
+ }
+ observers.addElement(observer);
+ }
+ }
+
+ private synchronized void startProduction(){
+ if(!producing){
+ imageState &= ~ImageObserver.ABORT;
+ producing = true;
+ src.startProduction(this);
+ }
+ }
+
+ private synchronized void stopProduction(){
+ producing = false;
+ src.removeConsumer(this);
+ }
+
+ private void createRaster(){
+ try{
+ raster = cm.createCompatibleWritableRaster(width, height);
+ isIntRGB = false;
+ if(cm instanceof DirectColorModel){
+ DirectColorModel dcm = (DirectColorModel) cm;
+ if(dcm.getTransferType() == DataBuffer.TYPE_INT &&
+ dcm.getRedMask() == 0xff0000 &&
+ dcm.getGreenMask() == 0xff00 &&
+ dcm.getBlueMask() == 0xff){
+ isIntRGB = true;
+ }
+ }
+ }catch(Exception e){
+ cm = ColorModel.getRGBdefault();
+ raster = cm.createCompatibleWritableRaster(width, height);
+ isIntRGB = true;
+ }
+ }
+
+ private /*synchronized*/ void imageUpdate(Image img, int infoflags, int x, int y,
+ int width, int height){
+
+ imageState |= infoflags;
+ for (ImageObserver observer : observers) {
+ observer.imageUpdate(this, infoflags, x, y, width, height);
+ }
+
+// notifyAll();
+ }
+
+ private void forceToIntARGB(){
+
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ WritableRaster destRaster = rgbCM.createCompatibleWritableRaster(w, h);
+
+ Object obj = null;
+ int pixels[] = new int[w];
+
+ if(cm instanceof IndexColorModel){
+ IndexColorModel icm = (IndexColorModel) cm;
+ int colorMap[] = new int[icm.getMapSize()];
+ icm.getRGBs(colorMap);
+
+ for (int y = 0; y < h; y++) {
+ obj = raster.getDataElements(0, y, w, 1, obj);
+ byte ba[] = (byte[]) obj;
+ for (int x = 0; x < ba.length; x++) {
+ pixels[x] = colorMap[ba[x] & 0xff];
+ }
+ destRaster.setDataElements(0, y, w, 1, pixels);
+ }
+
+ }else{
+ for(int y = 0; y < h; y++){
+ for(int x = 0; x < w; x++){
+ obj = raster.getDataElements(x, y, obj);
+ pixels[x] = cm.getRGB(obj);
+ }
+ destRaster.setDataElements(0, y, w, 1, pixels);
+ }
+ }
+
+ synchronized(this){
+ if(imageSurf != null){
+ imageSurf.dispose();
+ imageSurf = null;
+ }
+ if(image != null){
+ image.flush();
+ image = null;
+ }
+ cm = rgbCM;
+ raster = destRaster;
+ isIntRGB = true;
+ }
+ }
+
+ public ImageSurface getImageSurface() {
+ if (imageSurf == null) {
+ ColorModel model = getColorModel();
+ WritableRaster wr = getRaster();
+ if(model != null && wr != null) {
+ imageSurf = new ImageSurface(model, wr);
+ }
+ }
+ return imageSurf;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java b/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
new file mode 100644
index 0000000..1748e1b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 30.09.2004
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+public class OrdinaryWritableRaster extends WritableRaster {
+
+ public OrdinaryWritableRaster(SampleModel sampleModel,
+ DataBuffer dataBuffer, Rectangle aRegion,
+ Point sampleModelTranslate, WritableRaster parent) {
+ super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent);
+ }
+
+ public OrdinaryWritableRaster(SampleModel sampleModel,
+ DataBuffer dataBuffer, Point origin) {
+ super(sampleModel, dataBuffer, origin);
+ }
+
+ public OrdinaryWritableRaster(SampleModel sampleModel, Point origin) {
+ super(sampleModel, origin);
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object inData) {
+ super.setDataElements(x, y, inData);
+ }
+
+ @Override
+ public void setDataElements(int x, int y, int w, int h, Object inData) {
+ super.setDataElements(x, y, w, h, inData);
+ }
+
+ @Override
+ public WritableRaster createWritableChild(int parentX, int parentY, int w,
+ int h, int childMinX, int childMinY, int[] bandList) {
+ return super.createWritableChild(parentX, parentY, w, h, childMinX,
+ childMinY, bandList);
+ }
+
+ @Override
+ public WritableRaster createWritableTranslatedChild(int childMinX,
+ int childMinY) {
+ return super.createWritableTranslatedChild(childMinX, childMinY);
+ }
+
+ @Override
+ public WritableRaster getWritableParent() {
+ return super.getWritableParent();
+ }
+
+ @Override
+ public void setRect(Raster srcRaster) {
+ super.setRect(srcRaster);
+ }
+
+ @Override
+ public void setRect(int dx, int dy, Raster srcRaster) {
+ super.setRect(dx, dy, srcRaster);
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Raster inRaster) {
+ super.setDataElements(x, y, inRaster);
+ }
+
+ @Override
+ public void setPixel(int x, int y, int[] iArray) {
+ super.setPixel(x, y, iArray);
+ }
+
+ @Override
+ public void setPixel(int x, int y, float[] fArray) {
+ super.setPixel(x, y, fArray);
+ }
+
+ @Override
+ public void setPixel(int x, int y, double[] dArray) {
+ super.setPixel(x, y, dArray);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int[] iArray) {
+ super.setPixels(x, y, w, h, iArray);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, float[] fArray) {
+ super.setPixels(x, y, w, h, fArray);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, double[] dArray) {
+ super.setPixels(x, y, w, h, dArray);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int[] iArray) {
+ super.setSamples(x, y, w, h, b, iArray);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, float[] fArray) {
+ super.setSamples(x, y, w, h, b, fArray);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, double[] dArray) {
+ super.setSamples(x, y, w, h, b, dArray);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s) {
+ super.setSample(x, y, b, s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s) {
+ super.setSample(x, y, b, s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s) {
+ super.setSample(x, y, b, s);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/PngDecoder.java b/awt/org/apache/harmony/awt/gl/image/PngDecoder.java
new file mode 100644
index 0000000..7e85600
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/PngDecoder.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jul 22, 2005
+ */
+
+package org.apache.harmony.awt.gl.image;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.awt.color.ColorSpace;
+import java.awt.image.*;
+import java.awt.*;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class PngDecoder extends ImageDecoder {
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ static {
+ System.loadLibrary("gl"); //$NON-NLS-1$
+ initIDs();
+ }
+
+ private static final int hintflags =
+ ImageConsumer.SINGLEFRAME | // PNG is a static image
+ ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+ ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+
+ // Each pixel is a grayscale sample.
+ private static final int PNG_COLOR_TYPE_GRAY = 0;
+ // Each pixel is an R,G,B triple.
+ private static final int PNG_COLOR_TYPE_RGB = 2;
+ // Each pixel is a palette index, a PLTE chunk must appear.
+ private static final int PNG_COLOR_TYPE_PLTE = 3;
+ // Each pixel is a grayscale sample, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+ // Each pixel is an R,G,B triple, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+ private static final int INPUT_BUFFER_SIZE = 4096;
+ private byte buffer[] = new byte[INPUT_BUFFER_SIZE];
+
+ // Buffers for decoded image data
+ byte byteOut[];
+ int intOut[];
+
+ // Native pointer to png decoder data
+ private long hNativeDecoder;
+
+ int imageWidth, imageHeight;
+ int colorType;
+ int bitDepth;
+ byte cmap[];
+
+ boolean transferInts; // Is transfer type int?.. or byte?
+ int dataElementsPerPixel = 1;
+
+ ColorModel cm;
+
+ int updateFromScanline; // First scanline to update
+ int numScanlines; // Number of scanlines to update
+
+ private native long decode(byte[] input, int bytesInBuffer, long hDecoder);
+
+ private static native void releaseNativeDecoder(long hDecoder);
+
+ public PngDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ }
+
+ @Override
+ public void decodeImage() throws IOException {
+ try {
+ int bytesRead = 0;
+ int needBytes, offset, bytesInBuffer = 0;
+ // Read from the input stream
+ for (;;) {
+ needBytes = INPUT_BUFFER_SIZE - bytesInBuffer;
+ offset = bytesInBuffer;
+
+ bytesRead = inputStream.read(buffer, offset, needBytes);
+
+ if (bytesRead < 0) { // Break, nothing to read from buffer, image truncated?
+ releaseNativeDecoder(hNativeDecoder);
+ break;
+ }
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer += bytesRead;
+ hNativeDecoder = decode(buffer, bytesInBuffer, hNativeDecoder);
+ // PNG decoder always consumes all bytes at once
+ bytesInBuffer = 0;
+
+ // if (bytesConsumed < 0)
+ //break; // Error exit
+
+ returnData();
+
+ // OK, we decoded all the picture in the right way...
+ if (hNativeDecoder == 0) {
+ break;
+ }
+ }
+
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ imageComplete(ImageConsumer.IMAGEERROR);
+ throw e;
+ } finally {
+ closeStream();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void returnHeader() { // Called from native code
+ setDimensions(imageWidth, imageHeight);
+
+ switch (colorType) {
+ case PNG_COLOR_TYPE_GRAY: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ // Create gray color model
+ int numEntries = 1 << bitDepth;
+ int scaleFactor = 255 / (numEntries-1);
+ byte comps[] = new byte[numEntries];
+ for (int i = 0; i < numEntries; i++) {
+ comps[i] = (byte) (i * scaleFactor);
+ }
+ cm = new IndexColorModel(/*bitDepth*/8, numEntries, comps, comps, comps);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGB: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+
+ transferInts = true;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_PLTE: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new IndexColorModel(/*bitDepth*/8, cmap.length / 3, cmap, 0, false);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ true, false,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+
+ transferInts = false;
+ dataElementsPerPixel = 2;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGBA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = ColorModel.getRGBdefault();
+
+ transferInts = true;
+ break;
+ }
+ default:
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ // Create output buffer
+ if (transferInts) {
+ intOut = new int[imageWidth * imageHeight];
+ } else {
+ byteOut = new byte[imageWidth * imageHeight * dataElementsPerPixel];
+ }
+
+ setColorModel(cm);
+
+ setHints(hintflags);
+ setProperties(new Hashtable<Object, Object>()); // Empty
+ }
+
+ // Send the data to the consumer
+ private void returnData() {
+ // Send 1 or more scanlines to the consumer.
+ if (numScanlines > 0) {
+ // Native decoder could have returned
+ // some data from the next pass, handle it here
+ int pass1, pass2;
+ if (updateFromScanline + numScanlines > imageHeight) {
+ pass1 = imageHeight - updateFromScanline;
+ pass2 = updateFromScanline + numScanlines - imageHeight;
+ } else {
+ pass1 = numScanlines;
+ pass2 = 0;
+ }
+
+ transfer(updateFromScanline, pass1);
+ if (pass2 != 0) {
+ transfer(0, pass2);
+ }
+ }
+ }
+
+ private void transfer(int updateFromScanline, int numScanlines) {
+ if (transferInts) {
+ setPixels(
+ 0, updateFromScanline,
+ imageWidth, numScanlines,
+ cm, intOut,
+ updateFromScanline * imageWidth,
+ imageWidth
+ );
+ } else {
+ setPixels(
+ 0, updateFromScanline,
+ imageWidth, numScanlines,
+ cm, byteOut,
+ updateFromScanline * imageWidth * dataElementsPerPixel,
+ imageWidth * dataElementsPerPixel
+ );
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java b/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
new file mode 100644
index 0000000..46545f9
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
@@ -0,0 +1,282 @@
+package org.apache.harmony.awt.gl.image;
+
+// A simple PNG decoder source code in Java.
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.zip.CRC32;
+import java.util.zip.InflaterInputStream;
+
+//import javax.swing.JFrame;
+
+public class PngDecoderJava {
+
+/*
+ public static void main(String[] args) throws Exception {
+ String name = "logo.png";
+ if (args.length > 0)
+ name = args[0];
+ InputStream in = PngDecoderJava.class.getResourceAsStream(name);
+ final BufferedImage image = PngDecoderJava.decode(in);
+ in.close();
+
+ JFrame f = new JFrame() {
+ public void paint(Graphics g) {
+ Insets insets = getInsets();
+ g.drawImage(image, insets.left, insets.top, null);
+ }
+ };
+ f.setVisible(true);
+ Insets insets = f.getInsets();
+ f.setSize(image.getWidth() + insets.left + insets.right, image
+ .getHeight()
+ + insets.top + insets.bottom);
+ }
+ */
+
+ public static BufferedImage decode(InputStream in) throws IOException {
+ DataInputStream dataIn = new DataInputStream(in);
+ readSignature(dataIn);
+ PNGData chunks = readChunks(dataIn);
+
+ long widthLong = chunks.getWidth();
+ long heightLong = chunks.getHeight();
+ if (widthLong > Integer.MAX_VALUE || heightLong > Integer.MAX_VALUE)
+ throw new IOException("That image is too wide or tall.");
+ int width = (int) widthLong;
+ int height = (int) heightLong;
+
+ ColorModel cm = chunks.getColorModel();
+ WritableRaster raster = chunks.getRaster();
+
+ BufferedImage image = new BufferedImage(cm, raster, false, null);
+
+ return image;
+ }
+
+ protected static void readSignature(DataInputStream in) throws IOException {
+ long signature = in.readLong();
+ if (signature != 0x89504e470d0a1a0aL)
+ throw new IOException("PNG signature not found!");
+ }
+
+ protected static PNGData readChunks(DataInputStream in) throws IOException {
+ PNGData chunks = new PNGData();
+
+ boolean trucking = true;
+ while (trucking) {
+ try {
+ // Read the length.
+ int length = in.readInt();
+ if (length < 0)
+ throw new IOException("Sorry, that file is too long.");
+ // Read the type.
+ byte[] typeBytes = new byte[4];
+ in.readFully(typeBytes);
+ // Read the data.
+ byte[] data = new byte[length];
+ in.readFully(data);
+ // Read the CRC.
+ long crc = in.readInt() & 0x00000000ffffffffL; // Make it
+ // unsigned.
+ if (verifyCRC(typeBytes, data, crc) == false)
+ throw new IOException("That file appears to be corrupted.");
+
+ PNGChunk chunk = new PNGChunk(typeBytes, data);
+ chunks.add(chunk);
+ } catch (EOFException eofe) {
+ trucking = false;
+ }
+ }
+ return chunks;
+ }
+
+ protected static boolean verifyCRC(byte[] typeBytes, byte[] data, long crc) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(typeBytes);
+ crc32.update(data);
+ long calculated = crc32.getValue();
+ return (calculated == crc);
+ }
+}
+
+class PNGData {
+ private int mNumberOfChunks;
+
+ private PNGChunk[] mChunks;
+
+ public PNGData() {
+ mNumberOfChunks = 0;
+ mChunks = new PNGChunk[10];
+ }
+
+ public void add(PNGChunk chunk) {
+ mChunks[mNumberOfChunks++] = chunk;
+ if (mNumberOfChunks >= mChunks.length) {
+ PNGChunk[] largerArray = new PNGChunk[mChunks.length + 10];
+ System.arraycopy(mChunks, 0, largerArray, 0, mChunks.length);
+ mChunks = largerArray;
+ }
+ }
+
+ public long getWidth() {
+ return getChunk("IHDR").getUnsignedInt(0);
+ }
+
+ public long getHeight() { return getChunk("IHDR").getUnsignedInt(4);
+ }
+
+ public short getBitsPerPixel() {
+ return getChunk("IHDR").getUnsignedByte(8);
+ }
+
+ public short getColorType() {
+ return getChunk("IHDR").getUnsignedByte(9);
+ }
+
+ public short getCompression() {
+ return getChunk("IHDR").getUnsignedByte(10);
+ }
+
+ public short getFilter() {
+ return getChunk("IHDR").getUnsignedByte(11);
+ }
+
+ public short getInterlace() {
+ return getChunk("IHDR").getUnsignedByte(12);
+ }
+
+ public ColorModel getColorModel() {
+ short colorType = getColorType();
+ int bitsPerPixel = getBitsPerPixel();
+
+ if (colorType == 3) {
+ byte[] paletteData = getChunk("PLTE").getData();
+ int paletteLength = paletteData.length / 3;
+ return new IndexColorModel(bitsPerPixel, paletteLength,
+ paletteData, 0, false);
+ }
+ System.out.println("Unsupported color type: " + colorType);
+ return null;
+ }
+
+ public WritableRaster getRaster() {
+ int width = (int) getWidth();
+ int height = (int) getHeight();
+ int bitsPerPixel = getBitsPerPixel();
+ short colorType = getColorType();
+
+ if (colorType == 3) {
+ byte[] imageData = getImageData();
+ //Orig: DataBuffer db = new DataBufferByte(imageData, imageData.length);
+ int len = Math.max(imageData.length, (width - 1) * (height -1));
+ DataBuffer db = new DataBufferByte(imageData, len);
+ WritableRaster raster = Raster.createPackedRaster(db, width,
+ height, bitsPerPixel, null);
+ return raster;
+ } else
+ System.out.println("Unsupported color type!");
+ return null;
+ }
+
+ public byte[] getImageData() {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // Write all the IDAT data into the array.
+ for (int i = 0; i < mNumberOfChunks; i++) {
+ PNGChunk chunk = mChunks[i];
+ if (chunk.getTypeString().equals("IDAT")) {
+ out.write(chunk.getData());
+ }
+ }
+ out.flush();
+ // Now deflate the data.
+ InflaterInputStream in = new InflaterInputStream(
+ new ByteArrayInputStream(out.toByteArray()));
+ ByteArrayOutputStream inflatedOut = new ByteArrayOutputStream();
+ int readLength;
+ byte[] block = new byte[8192];
+ while ((readLength = in.read(block)) != -1)
+ inflatedOut.write(block, 0, readLength);
+ inflatedOut.flush();
+ byte[] imageData = inflatedOut.toByteArray();
+ // Compute the real length.
+ int width = (int) getWidth();
+ int height = (int) getHeight();
+ int bitsPerPixel = getBitsPerPixel();
+ int length = width * height * bitsPerPixel / 8;
+
+ byte[] prunedData = new byte[length];
+
+ // We can only deal with non-interlaced images.
+ if (getInterlace() == 0) {
+ int index = 0;
+ for (int i = 0; i < length; i++) {
+ if ((i * 8 / bitsPerPixel) % width == 0) {
+ index++; // Skip the filter byte.
+ }
+ prunedData[i] = imageData[index++];
+ }
+ } else
+ System.out.println("Couldn't undo interlacing.");
+
+ return prunedData;
+ } catch (IOException ioe) {
+ }
+ return null;
+ }
+
+ public PNGChunk getChunk(String type) {
+ for (int i = 0; i < mNumberOfChunks; i++)
+ if (mChunks[i].getTypeString().equals(type))
+ return mChunks[i];
+ return null;
+ }
+}
+
+class PNGChunk {
+ private byte[] mType;
+
+ private byte[] mData;
+
+ public PNGChunk(byte[] type, byte[] data) {
+ mType = type;
+ mData = data;
+ }
+
+ public String getTypeString() {
+ try {
+ return new String(mType, "UTF8");
+ } catch (UnsupportedEncodingException uee) {
+ return "";
+ }
+ }
+
+ public byte[] getData() {
+ return mData;
+ }
+
+ public long getUnsignedInt(int offset) {
+ long value = 0;
+ for (int i = 0; i < 4; i++)
+ value += (mData[offset + i] & 0xff) << ((3 - i) * 8);
+ return value;
+ }
+
+ public short getUnsignedByte(int offset) {
+ return (short) (mData[offset] & 0x00ff);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
new file mode 100644
index 0000000..a1899d6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 10.02.2005
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.Permission;
+
+public class URLDecodingImageSource extends DecodingImageSource {
+
+ URL url;
+
+ public URLDecodingImageSource(URL url){
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkConnect(url.getHost(), url.getPort());
+ try {
+ Permission p = url.openConnection().getPermission();
+ security.checkPermission(p);
+ } catch (IOException e) {
+ }
+ }
+ this.url = url;
+ }
+
+ @Override
+ protected boolean checkConnection() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ security.checkConnect(url.getHost(), url.getPort());
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected InputStream getInputStream() {
+ try{
+ URLConnection uc = url.openConnection();
+ // BEGIN android-modified
+ return new BufferedInputStream(uc.getInputStream(), 8192);
+ // END android-modified
+ }catch(IOException e){
+ return null;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/Blitter.java b/awt/org/apache/harmony/awt/gl/render/Blitter.java
new file mode 100644
index 0000000..3b8012e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/Blitter.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 14.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+
+/**
+ * The interface for objects which can drawing Images on other Images which have
+ * Graphics or on the display.
+ */
+public interface Blitter {
+
+ public abstract void blit(int srcX, int srcY, Surface srcSurf,
+ int dstX, int dstY, Surface dstSurf, int width, int height,
+ AffineTransform sysxform, AffineTransform xform,
+ Composite comp, Color bgcolor,
+ MultiRectArea clip);
+
+ public abstract void blit(int srcX, int srcY, Surface srcSurf,
+ int dstX, int dstY, Surface dstSurf, int width, int height,
+ AffineTransform sysxform, Composite comp, Color bgcolor,
+ MultiRectArea clip);
+
+ public abstract void blit(int srcX, int srcY, Surface srcSurf,
+ int dstX, int dstY, Surface dstSurf, int width, int height,
+ Composite comp, Color bgcolor, MultiRectArea clip);
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
new file mode 100644
index 0000000..b643b41
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
@@ -0,0 +1,502 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+public class JavaArcRasterizer {
+
+ /**
+ * Adds particular arc segment to mra
+ */
+ static void addX0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy + (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addX1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy - (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addX2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy - (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addX3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy + (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addY0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx + (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addY1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx - (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addY2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx - (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addY3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx + (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addX0Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + prev, cy + (b - i), cx + line[i], cy + (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addX1Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + prev, cy - (b - i), cx + line[i], cy - (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addX2Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - line[i], cy - (b - i), cx - prev, cy - (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addX3Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - line[i], cy + (b - i), cx - prev, cy + (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY0Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + (a - i), cy + prev, cx + (a - i), cy + line[i]);
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY1Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - (a - i), cy + prev, cx - (a - i), cy + line[i]);
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY2Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - (a - i), cy - line[i], cx - (a - i), cy - prev);
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY3Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + (a - i), cy - line[i], cx + (a - i), cy - prev);
+ prev = line[i] + 1;
+ }
+ }
+
+ /**
+ * Returns normalized angle (from 0 to 360 degrees)
+ */
+ static double getNormAngle(double angle) {
+ angle -= Math.floor(angle / 360) * 360;
+ if (angle < 0) {
+ angle += 360;
+ }
+ return angle;
+ }
+
+ /**
+ * Creates arc lookup table
+ */
+ static int[] createLine(int a, int b, int xcount, int ycount) {
+ int[] buf = new int[b - ycount + 1];
+ int d = a * a + 2 * b * b - 2 * a * a * b;
+ int x = 0;
+ int y = b;
+ while (y >= ycount) {
+ if (d < 0) {
+ d = d + b * b * (4 * x + 6);
+ } else {
+ buf[b - y] = x;
+ d = d + b * b * (4 * x + 6) + 4 * a * a * (1 - y);
+ y--;
+ }
+ x++;
+ }
+ return buf;
+ }
+
+ /**
+ * Adds head/tail arc segment to MultiRectArea
+ */
+ static void addSeg(MultiRectArea mra, int cx1, int cy1, int cx2, int cy2, int a, int b, int[] xline, int[] yline, int[] bounds) {
+ switch(bounds[0]) {
+ case 0:
+ addY3LineSeg(mra, yline, cx2, cy1, a, bounds[1], bounds[2]);
+ break;
+ case 1:
+ addX1LineSeg(mra, xline, cx2, cy1, b, bounds[1], bounds[2]);
+ break;
+ case 2:
+ addX2LineSeg(mra, xline, cx1, cy1, b, bounds[1], bounds[2]);
+ break;
+ case 3:
+ addY2LineSeg(mra, yline, cx1, cy1, a, bounds[1], bounds[2]);
+ break;
+ case 4:
+ addY1LineSeg(mra, yline, cx1, cy2, a, bounds[1], bounds[2]);
+ break;
+ case 5:
+ addX3LineSeg(mra, xline, cx1, cy2, b, bounds[1], bounds[2]);
+ break;
+ case 6:
+ addX0LineSeg(mra, xline, cx2, cy2, b, bounds[1], bounds[2]);
+ break;
+ case 7:
+ addY0LineSeg(mra, yline, cx2, cy2, a, bounds[1], bounds[2]);
+ break;
+ }
+ }
+
+ /**
+ * Returns bounds for non quadratic arc head
+ */
+ static int[] getSegment1(double angle, int ax, int ay, int xcount, int ycount) {
+ int[] bounds = new int[3];
+ switch((int)(angle / 90)) {
+ case 0:
+ if (xcount < ax) {
+ bounds[0] = 0; // Y3
+ bounds[1] = -ay;
+ bounds[2] = ycount;
+ } else {
+ bounds[0] = 1; // X1
+ bounds[1] = 0;
+ bounds[2] = ax;
+ }
+ break;
+ case 1:
+ if (xcount > -ax) {
+ bounds[0] = 2; // X2
+ bounds[1] = -ax;
+ bounds[2] = xcount;
+ } else {
+ bounds[0] = 3; // Y2
+ bounds[1] = 0;
+ bounds[2] = -ay;
+ }
+ break;
+ case 2:
+ if (xcount < -ax) {
+ bounds[0] = 4; // Y1
+ bounds[1] = ay;
+ bounds[2] = ycount;
+ } else {
+ bounds[0] = 5; // X3
+ bounds[1] = 0;
+ bounds[2] = -ax;
+ }
+ break;
+ case 3:
+ if (xcount > ax) {
+ bounds[0] = 6; // X0
+ bounds[1] = ax;
+ bounds[2] = xcount;
+ } else {
+ bounds[0] = 7; // Y0
+ bounds[1] = 0;
+ bounds[2] = ay;
+ }
+ break;
+ }
+ return bounds;
+ }
+
+ /**
+ * Returns bounds for non quadratic arc tail
+ */
+ static int[] getSegment2(double angle, int ax, int ay, int xcount, int ycount) {
+ int[] bounds = new int[3];
+ switch((int)(angle / 90)) {
+ case 0:
+ if (xcount < ax) {
+ bounds[0] = 0; // Y3
+ bounds[1] = 0;
+ bounds[2] = -ay;
+ } else {
+ bounds[0] = 1; // X1
+ bounds[1] = ax;
+ bounds[2] = xcount;
+ }
+ break;
+ case 1:
+ if (xcount > -ax) {
+ bounds[0] = 2; // X2
+ bounds[1] = 0;
+ bounds[2] = -ax;
+ } else {
+ bounds[0] = 3; // Y2
+ bounds[1] = -ay;
+ bounds[2] = ycount;
+ }
+ break;
+ case 2:
+ if (xcount < -ax) {
+ bounds[0] = 4; // Y1
+ bounds[1] = 0;
+ bounds[2] = ay;
+ } else {
+ bounds[0] = 5; // X3
+ bounds[1] = -ax;
+ bounds[2] = xcount;
+ }
+ break;
+ case 3:
+ if (xcount > ax) {
+ bounds[0] = 6; // X0
+ bounds[1] = 0;
+ bounds[2] = ax;
+ } else {
+ bounds[0] = 7; // Y0
+ bounds[1] = ay;
+ bounds[2] = ycount;
+ }
+ break;
+ }
+ return bounds;
+ }
+
+ /**
+ * Rasterizes arc using clippind and dashing style
+ * @param x1 - the x coordinate of the left-upper corner of the arc bounds
+ * @param y1 - the y coordinate of the left-upper corner of the arc bounds
+ * @param width - the width of the arc bounds
+ * @param height - the height of the arc bounds
+ * @param angleStart - the start angle of the arc in degrees
+ * @param angleExtent - the angle extent in degrees
+ * @param clip - the MultiRectArea object of clipping area
+ * @return a MultiRectArea of rasterizer arc
+ */
+ public static MultiRectArea rasterize(int x, int y, int width, int height, double angleStart, double angleExtent, MultiRectArea clip) {
+
+ MultiRectArea mra = new MultiRectArea(false);
+
+ int cx1, cx2, cy1, cy2;
+ cx1 = cx2 = x + width / 2;
+ cy1 = cy2 = y + height / 2;
+
+ if (width % 2 == 0) {
+ cx2--;
+ }
+
+ if (height % 2 == 0) {
+ cy2--;
+ }
+
+ int a = width / 2;
+ int b = height / 2;
+ double c = Math.sqrt(a * a + b * b);
+
+ int xcount, ycount;
+ if (a < b) {
+ xcount = (int)Math.ceil(a * a / c);
+ ycount = (int)Math.floor(b * b / c);
+ } else {
+ xcount = (int)Math.floor(a * a / c);
+ ycount = (int)Math.ceil(b * b / c);
+ }
+
+ int[] xline = createLine(a, b, xcount, ycount);
+ int[] yline = createLine(b, a, ycount, xcount);
+
+ // Correct lines
+ int i = xline.length;
+ while(xline[--i] > xcount) {
+ xline[i] = xcount;
+ }
+
+ i = yline.length;
+ while(yline[--i] > ycount) {
+ yline[i] = ycount;
+ }
+
+ if (Math.abs(angleExtent) >= 360) {
+ // Rasterize CIRCLE
+ addX0Line(mra, xline, cx2, cy2, b);
+ addX1Line(mra, xline, cx2, cy1, b);
+ addX2Line(mra, xline, cx1, cy1, b);
+ addX3Line(mra, xline, cx1, cy2, b);
+ addY0Line(mra, yline, cx2, cy2, a);
+ addY1Line(mra, yline, cx1, cy2, a);
+ addY2Line(mra, yline, cx1, cy1, a);
+ addY3Line(mra, yline, cx2, cy1, a);
+ } else {
+ // Rasterize ARC
+ angleStart = getNormAngle(angleStart);
+ double angleFinish = getNormAngle(angleStart + angleExtent);
+
+ if (angleExtent < 0) {
+ double tmp = angleStart;
+ angleStart = angleFinish;
+ angleFinish = tmp;
+ }
+
+ double radStart = -Math.toRadians(angleStart);
+ double radFinish = -Math.toRadians(angleFinish);
+ int ax1 = (int)(a * Math.cos(radStart));
+ int ay1 = (int)(b * Math.sin(radStart));
+ int ax2 = (int)(a * Math.cos(radFinish));
+ int ay2 = (int)(b * Math.sin(radFinish));
+
+ int[] seg1 = getSegment1(angleStart, ax1, ay1, xcount, ycount);
+ int[] seg2 = getSegment2(angleFinish, ax2, ay2, xcount, ycount);
+
+ // Start and Finish located in the same quater
+ if (angleStart < angleFinish && seg1[0] == seg2[0]) {
+ if (seg1[0] % 2 == 0) {
+ seg1[2] = seg2[2];
+ } else {
+ seg1[1] = seg2[1];
+ }
+ addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
+ return mra;
+ }
+
+ addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
+ addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg2);
+
+ int startSeg = (seg1[0] + 1) % 8;
+ int finishSeg = seg2[0];
+
+ while (startSeg != finishSeg) {
+ switch(startSeg) {
+ case 0:
+ addY3Line(mra, yline, cx2, cy1, a);
+ break;
+ case 1:
+ addX1Line(mra, xline, cx2, cy1, b);
+ break;
+ case 2:
+ addX2Line(mra, xline, cx1, cy1, b);
+ break;
+ case 3:
+ addY2Line(mra, yline, cx1, cy1, a);
+ break;
+ case 4:
+ addY1Line(mra, yline, cx1, cy2, a);
+ break;
+ case 5:
+ addX3Line(mra, xline, cx1, cy2, b);
+ break;
+ case 6:
+ addX0Line(mra, xline, cx2, cy2, b);
+ break;
+ case 7:
+ addY0Line(mra, yline, cx2, cy2, a);
+ break;
+ }
+ startSeg = (startSeg + 1) % 8;
+ }
+ }
+
+ if (clip != null) {
+ mra.intersect(clip);
+ }
+
+ return mra;
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
new file mode 100644
index 0000000..67e0a59
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
@@ -0,0 +1,611 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 18.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Java implenetation of the Blitter interface. Using when we can't
+ * draw images natively.
+ */
+public class JavaBlitter implements Blitter {
+
+ /**
+ * Instead of multiplication and division we are using values from
+ * Lookup tables.
+ */
+ static byte mulLUT[][]; // Lookup table for multiplication
+ static byte divLUT[][]; // Lookup table for division
+
+ static{
+ mulLUT = new byte[256][256];
+ for(int i = 0; i < 256; i++){
+ for(int j = 0; j < 256; j++){
+ mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f);
+ }
+ }
+ divLUT = new byte[256][256];
+ for(int i = 1; i < 256; i++){
+ for(int j = 0; j < i; j++){
+ divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f);
+ }
+ for(int j = i; j < 256; j++){
+ divLUT[i][j] = (byte)255;
+ }
+ }
+ }
+
+ final static int AlphaCompositeMode = 1;
+ final static int XORMode = 2;
+
+ final static JavaBlitter inst = new JavaBlitter();
+
+ public static JavaBlitter getInstance(){
+ return inst;
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+
+ if(xform == null){
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ double scaledX = dstX / scaleX;
+ double scaledY = dstY / scaleY;
+ AffineTransform at = new AffineTransform();
+ at.setToTranslation(scaledX, scaledY);
+ xform.concatenate(at);
+ sysxform.concatenate(xform);
+ blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+
+ if(sysxform == null) {
+ sysxform = new AffineTransform();
+ }
+ int type = sysxform.getType();
+ switch(type){
+ case AffineTransform.TYPE_TRANSLATION:
+ dstX += sysxform.getTranslateX();
+ dstY += sysxform.getTranslateY();
+ case AffineTransform.TYPE_IDENTITY:
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+ width, height, comp, bgcolor, clip);
+ break;
+ default:
+ int srcW = srcSurf.getWidth();
+ int srcH = srcSurf.getHeight();
+
+ int w = srcX + width < srcW ? width : srcW - srcX;
+ int h = srcY + height < srcH ? height : srcH - srcY;
+
+ ColorModel srcCM = srcSurf.getColorModel();
+ Raster srcR = srcSurf.getRaster().createChild(srcX, srcY,
+ w, h, 0, 0, null);
+
+ ColorModel dstCM = dstSurf.getColorModel();
+ WritableRaster dstR = dstSurf.getRaster();
+
+ transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h,
+ sysxform, comp, bgcolor, clip);
+
+ }
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(),
+ srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY,
+ dstSurf.getWidth(), dstSurf.getHeight(),
+ dstSurf.getColorModel(), dstSurf.getRaster(),
+ width, height, comp, bgcolor, clip);
+
+ }
+ public void javaBlt(int srcX, int srcY, int srcW, int srcH,
+ ColorModel srcCM, Raster srcRast, int dstX, int dstY,
+ int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Composite comp, Color bgcolor,
+ MultiRectArea clip){
+
+ int srcX2 = srcW - 1;
+ int srcY2 = srcH - 1;
+ int dstX2 = dstW - 1;
+ int dstY2 = dstH - 1;
+
+ if(srcX < 0){
+ width += srcX;
+ srcX = 0;
+ }
+ if(srcY < 0){
+ height += srcY;
+ srcY = 0;
+ }
+
+ if(dstX < 0){
+ width += dstX;
+ srcX -= dstX;
+ dstX = 0;
+ }
+ if(dstY < 0){
+ height += dstY;
+ srcY -= dstY;
+ dstY = 0;
+ }
+
+ if(srcX > srcX2 || srcY > srcY2) {
+ return;
+ }
+ if(dstX > dstX2 || dstY > dstY2) {
+ return;
+ }
+
+ if(srcX + width > srcX2) {
+ width = srcX2 - srcX + 1;
+ }
+ if(srcY + height > srcY2) {
+ height = srcY2 - srcY + 1;
+ }
+ if(dstX + width > dstX2) {
+ width = dstX2 - dstX + 1;
+ }
+ if(dstY + height > dstY2) {
+ height = dstY2 - dstY + 1;
+ }
+
+ if(width <= 0 || height <= 0) {
+ return;
+ }
+
+ int clipRects[];
+ if(clip != null) {
+ clipRects = clip.rect;
+ } else {
+ clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1};
+ }
+
+ boolean isAlphaComp = false;
+ int rule = 0;
+ float alpha = 0;
+ boolean isXORComp = false;
+ Color xorcolor = null;
+ CompositeContext cont = null;
+
+ if(comp instanceof AlphaComposite){
+ isAlphaComp = true;
+ AlphaComposite ac = (AlphaComposite) comp;
+ rule = ac.getRule();
+ alpha = ac.getAlpha();
+ }else if(comp instanceof XORComposite){
+ isXORComp = true;
+ XORComposite xcomp = (XORComposite) comp;
+ xorcolor = xcomp.getXORColor();
+ }else{
+ cont = comp.createContext(srcCM, dstCM, null);
+ }
+
+ for(int i = 1; i < clipRects[0]; i += 4){
+ int _sx = srcX;
+ int _sy = srcY;
+
+ int _dx = dstX;
+ int _dy = dstY;
+
+ int _w = width;
+ int _h = height;
+
+ int cx = clipRects[i]; // Clipping left top X
+ int cy = clipRects[i + 1]; // Clipping left top Y
+ int cx2 = clipRects[i + 2]; // Clipping right bottom X
+ int cy2 = clipRects[i + 3]; // Clipping right bottom Y
+
+ if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) {
+ continue;
+ }
+
+ if(cx > _dx){
+ int shx = cx - _dx;
+ _w -= shx;
+ _dx = cx;
+ _sx += shx;
+ }
+
+ if(cy > _dy){
+ int shy = cy - _dy;
+ _h -= shy;
+ _dy = cy;
+ _sy += shy;
+ }
+
+ if(_dx + _w > cx2 + 1){
+ _w = cx2 - _dx + 1;
+ }
+
+ if(_dy + _h > cy2 + 1){
+ _h = cy2 - _dy + 1;
+ }
+
+ if(_sx > srcX2 || _sy > srcY2) {
+ continue;
+ }
+
+ if(isAlphaComp){
+ alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, rule, alpha, bgcolor);
+ }else if(isXORComp){
+ xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, xorcolor);
+ }else{
+ Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null);
+ WritableRaster dr = dstRast.createWritableChild(_dx, _dy,
+ _w, _h, 0, 0, null);
+ cont.compose(sr, dr, dr);
+ }
+ }
+ }
+
+ void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, int rule, float alpha, Color bgcolor){
+
+ Object srcPixel, dstPixel;
+ int srcConstAllpha = (int)(alpha * 255 + 0.5f);
+ int srcRGB, dstRGB = 0;
+
+ if(bgcolor != null){
+ dstRGB = bgcolor.getRGB();
+ }
+
+ for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){
+ for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){
+ srcPixel = srcRast.getDataElements(sx, sy, null);
+ srcRGB = srcCM.getRGB(srcPixel);
+ if(bgcolor == null){
+ dstPixel = dstRast.getDataElements(dx, dy, null);
+ dstRGB = dstCM.getRGB(dstPixel);
+ }
+
+ dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(),
+ dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(),
+ rule, srcConstAllpha);
+
+ dstPixel = dstCM.getDataElements(dstRGB, null);
+ dstRast.setDataElements(dx,dy,dstPixel);
+ }
+ }
+ }
+
+ void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Color xorcolor){
+
+ Object srcPixel, dstPixel;
+ int xorRGB = xorcolor.getRGB();
+ int srcRGB, dstRGB;
+
+ for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){
+ for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){
+ srcPixel = srcRast.getDataElements(sx, sy, null);
+ dstPixel = dstRast.getDataElements(dx, dy, null);
+
+ srcRGB = srcCM.getRGB(srcPixel);
+ dstRGB = dstCM.getRGB(dstPixel);
+ dstRGB = srcRGB ^ xorRGB ^ dstRGB;
+
+ dstRGB = 0xff000000 | dstRGB;
+ dstPixel = dstCM.getDataElements(dstRGB, dstPixel);
+ dstRast.setDataElements(dx,dy,dstPixel);
+
+ }
+ }
+
+ }
+
+ private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY,
+ ColorModel dstCM, WritableRaster dstR, int dstX, int dstY,
+ int width, int height, AffineTransform at, Composite comp,
+ Color bgcolor,MultiRectArea clip) {
+
+ Rectangle srcBounds = new Rectangle(width, height);
+ Rectangle dstBlitBounds = new Rectangle(dstX, dstY, srcR.getWidth(), srcR.getHeight());
+
+ Rectangle transSrcBounds = getBounds2D(at, srcBounds).getBounds();
+ Rectangle transDstBlitBounds = getBounds2D(at, dstBlitBounds).getBounds();
+
+ int translateX = transDstBlitBounds.x - transSrcBounds.x;
+ int translateY = transDstBlitBounds.y - transSrcBounds.y;
+
+ AffineTransform inv = null;
+ try {
+ inv = at.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ return;
+ }
+
+ double[] m = new double[6];
+ inv.getMatrix(m);
+
+ int clipRects[];
+ if(clip != null) {
+ clipRects = clip.rect;
+ } else {
+ clipRects = new int[]{5, 0, 0, dstR.getWidth(), dstR.getHeight()};
+ }
+
+ int compType = 0;
+ int srcConstAlpha = 0;
+ int rule = 0;
+ int bgRGB = bgcolor == null ? 0 : bgcolor.getRGB();
+ int srcRGB = 0, dstRGB = 0;
+ Object srcVal = null, dstVal = null;
+ if(comp instanceof AlphaComposite){
+ compType = AlphaCompositeMode;
+ AlphaComposite ac = (AlphaComposite) comp;
+ rule = ac.getRule();
+ srcConstAlpha = (int)(ac.getAlpha() * 255 + 0.5f);
+ }else if(comp instanceof XORComposite){
+ compType = XORMode;
+ XORComposite xor = (XORComposite) comp;
+ bgRGB = xor.getXORColor().getRGB();
+ }
+
+ for(int i = 1; i < clipRects[0]; i += 4){
+ Rectangle dstBounds = new Rectangle(clipRects[i], clipRects[i + 1], 0, 0);
+ dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 1]);
+ dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 3] + 1);
+ dstBounds.add(clipRects[i], clipRects[i + 3] + 1);
+
+ Rectangle bounds = dstBounds.intersection(transDstBlitBounds);
+
+ int minSrcX = srcBounds.x;
+ int minSrcY = srcBounds.y;
+ int maxSrcX = minSrcX + srcBounds.width;
+ int maxSrcY = minSrcY + srcBounds.height;
+
+ int minX = bounds.x;
+ int minY = bounds.y;
+ int maxX = minX + bounds.width;
+ int maxY = minY + bounds.height;
+
+ int hx = (int)((m[0] * 256) + 0.5);
+ int hy = (int)((m[1] * 256) + 0.5);
+ int vx = (int)((m[2] * 256) + 0.5);
+ int vy = (int)((m[3] * 256) + 0.5);
+ int sx = (int)((m[4] + m[0] * (bounds.x - translateX) + m[2] * (bounds.y - translateY)) * 256 + 0.5);
+ int sy = (int)((m[5] + m[1] * (bounds.x - translateX) + m[3] * (bounds.y - translateY)) * 256 + 0.5);
+
+ vx -= hx * bounds.width;
+ vy -= hy * bounds.width;
+
+ for(int y = minY; y < maxY; y++) {
+ for(int x = minX; x < maxX; x++) {
+ int px = sx >> 8;
+ int py = sy >> 8;
+ if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+ switch(compType){
+ case AlphaCompositeMode:
+ srcVal = srcR.getDataElements(px , py , null);
+ srcRGB = srcCM.getRGB(srcVal);
+ if(bgcolor != null){
+ dstRGB = bgRGB;
+ }else{
+ dstVal = dstR.getDataElements(x, y, null);
+ dstRGB = dstCM.getRGB(dstVal);
+ }
+ dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(),
+ dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(),
+ rule, srcConstAlpha);
+ dstVal = dstCM.getDataElements(dstRGB, null);
+ dstR.setDataElements(x, y, dstVal);
+ break;
+
+ case XORMode:
+ srcVal = srcR.getDataElements(px , py , null);
+ srcRGB = srcCM.getRGB(srcVal);
+ dstVal = dstR.getDataElements(x, y, null);
+ dstRGB = dstCM.getRGB(dstVal);
+ dstRGB = srcRGB ^ bgRGB;
+
+ dstRGB = 0xff000000 | dstRGB;
+ dstVal = dstCM.getDataElements(dstRGB, null);
+ dstR.setDataElements(x, y, dstVal);
+ break;
+
+ default:
+ // awt.37=Unknown composite type {0}
+ throw new IllegalArgumentException(Messages.getString("awt.37", //$NON-NLS-1$
+ comp.getClass()));
+ }
+ }
+ sx += hx;
+ sy += hy;
+ }
+ sx += vx;
+ sy += vy;
+ }
+ }
+
+ }
+
+ private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) {
+ int x = r.x;
+ int y = r.y;
+ int width = r.width;
+ int height = r.height;
+
+ float[] corners = {
+ x, y,
+ x + width, y,
+ x + width, y + height,
+ x, y + height
+ };
+
+ at.transform(corners, 0, corners, 0, 4);
+
+ Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+ bounds.add(corners[2], corners[3]);
+ bounds.add(corners[4], corners[5]);
+ bounds.add(corners[6], corners[7]);
+
+ return bounds;
+ }
+
+ private int compose(int srcRGB, boolean isSrcAlphaPre,
+ int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre,
+ int rule, int srcConstAlpha){
+
+ int sa, sr, sg, sb, da, dr, dg, db;
+
+ sa = (srcRGB >> 24) & 0xff;
+ sr = (srcRGB >> 16) & 0xff;
+ sg = (srcRGB >> 8) & 0xff;
+ sb = srcRGB & 0xff;
+
+ if(isSrcAlphaPre){
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[srcConstAlpha][sr] & 0xff;
+ sg = mulLUT[srcConstAlpha][sg] & 0xff;
+ sb = mulLUT[srcConstAlpha][sb] & 0xff;
+ }else{
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[sa][sr] & 0xff;
+ sg = mulLUT[sa][sg] & 0xff;
+ sb = mulLUT[sa][sb] & 0xff;
+ }
+
+ da = (dstRGB >> 24) & 0xff;
+ dr = (dstRGB >> 16) & 0xff;
+ dg = (dstRGB >> 8) & 0xff;
+ db = dstRGB & 0xff;
+
+ if(!isDstAlphaPre){
+ dr = mulLUT[da][dr] & 0xff;
+ dg = mulLUT[da][dg] & 0xff;
+ db = mulLUT[da][db] & 0xff;
+ }
+
+ int Fs = 0;
+ int Fd = 0;
+ switch(rule){
+ case AlphaComposite.CLEAR:
+ break;
+
+ case AlphaComposite.DST:
+ Fd = 255;
+ break;
+
+ case AlphaComposite.DST_ATOP:
+ Fs = 255 - da;
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_IN:
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_OUT:
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.DST_OVER:
+ Fs = 255 - da;
+ Fd = 255;
+ break;
+
+ case AlphaComposite.SRC:
+ Fs = 255;
+ break;
+
+ case AlphaComposite.SRC_ATOP:
+ Fs = da;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.SRC_IN:
+ Fs = da;
+ break;
+
+ case AlphaComposite.SRC_OUT:
+ Fs = 255 - da;
+ break;
+
+ case AlphaComposite.SRC_OVER:
+ Fs = 255;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.XOR:
+ Fs = 255 - da;
+ Fd = 255 - sa;
+ break;
+ }
+ dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff);
+ dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff);
+ db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff);
+
+ da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff);
+
+ if(!isDstAlphaPre){
+ if(da != 255){
+ dr = divLUT[da][dr] & 0xff;
+ dg = divLUT[da][dg] & 0xff;
+ db = divLUT[da][db] & 0xff;
+ }
+ }
+ if(!dstHasAlpha) {
+ da = 0xff;
+ }
+ dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db;
+
+ return dstRGB;
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
new file mode 100644
index 0000000..eb6f7b5
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
@@ -0,0 +1,760 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+public class JavaLineRasterizer {
+
+ /**
+ * LineDasher class provides dashing for particular dash style
+ */
+ public static class LineDasher {
+
+ int index;
+ float pos;
+ float phase;
+ float dash[];
+ float inv[];
+ boolean visible;
+
+ public LineDasher() {
+ }
+
+ public LineDasher(float dash[], float phase) {
+ this.dash = dash;
+ this.phase = phase;
+
+ inv = new float[dash.length];
+ int j = dash.length;
+ for (float element : dash) {
+ inv[--j] = element;
+ }
+ index = 0;
+ while (phase > dash[index]) {
+ phase -= dash[index];
+ index = (index + 1) % dash.length;
+ }
+ visible = index % 2 == 0;
+ }
+
+ void move(float step) { // main dasher
+ pos += step;
+ step += phase;
+ while(step >= dash[index]) {
+ step -= dash[index];
+ index = (index + 1) % dash.length;
+ visible = !visible;
+ }
+ phase = step;
+ }
+
+ float nextDash() {
+ phase = 0.0f;
+ index = (index + 1) % dash.length;
+ visible = !visible;
+ return dash[index];
+ }
+
+ LineDasher createDiagonal(double k, float length, boolean invert) {
+ LineDasher local = new LineDasher();
+ local.dash = new float[dash.length];
+ if (invert) { // inverted dasher
+ move(length);
+ local.phase = (float)((dash[index] - phase) * k);
+ local.visible = visible;
+ local.index = inv.length - index - 1;
+ for(int i = 0; i < inv.length; i++) {
+ local.dash[i] = (float)(inv[i] * k);
+ }
+ } else {
+ local.phase = (float)(phase * k);
+ local.visible = visible;
+ local.index = index;
+ for(int i = 0; i < dash.length; i++) {
+ local.dash[i] = (float)(dash[i] * k);
+ }
+ move(length);
+ }
+ return local;
+ }
+
+ LineDasher createOrtogonal(float length, boolean invert) {
+ LineDasher local = new LineDasher();
+ local.dash = new float[dash.length];
+ if (invert) { // inverted dasher
+ move(length);
+ local.phase = dash[index] - phase;
+ local.visible = visible;
+ local.index = inv.length - index - 1;
+ local.dash = inv;
+ } else {
+ local.phase = phase;
+ local.visible = visible;
+ local.index = index;
+ local.dash = dash;
+ move(length);
+ }
+ return local;
+ }
+
+ LineDasher createChild(float start) {
+ LineDasher child = new LineDasher();
+ child.phase = phase;
+ child.visible = visible;
+ child.index = index;
+ child.dash = dash;
+ child.move(start);
+ return child;
+ }
+
+ }
+
+ /**
+ * Line class provides rasterization for different line types
+ */
+ abstract static class Line {
+
+ int x1, y1, x2, y2;
+ int x, y;
+ MultiRectArea dst;
+
+ Line(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ this.dst = dst;
+ }
+
+ static abstract class Diag extends Line {
+ int dx, dy, adx, ady, sx, sy;
+ int eBase, ePos, eNeg;
+ int xcount;
+ int e;
+
+ Diag(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ dx = x2 - x1;
+ dy = y2 - y1;
+ sy = 1;
+ if (dx > 0) {
+ adx = dx;
+ sx = 1;
+ } else {
+ adx = -dx;
+ sx = -1;
+ }
+ ady = dy;
+ }
+
+ float getLength() {
+ return (float)Math.sqrt(dx * dx + dy * dy);
+ }
+
+ static class Hor extends Diag {
+
+ Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ eBase = ady + ady - adx;
+ ePos = 2 * (ady - adx);
+ eNeg = ady + ady;
+ xcount = adx;
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterize(xcount);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1));
+ x = nx1;
+ y = ny1;
+ rasterize(dx > 0 ? nx2 - nx1 : nx1 - nx2);
+ }
+
+ @Override
+ void rasterize(int count) {
+ int px = x;
+ while (count-- > 0) {
+ if (e >= 0) {
+ if (sx > 0) {
+ dst.addRect(px, y, x, y);
+ } else {
+ dst.addRect(x, y, px, y);
+ }
+ x += sx;
+ y += sy;
+ e += ePos;
+ px = x;
+ } else {
+ e += eNeg;
+ x += sx;
+ }
+ }
+ if (sx > 0) {
+ dst.addRect(px, y, x, y);
+ } else {
+ dst.addRect(x, y, px, y);
+ }
+ }
+
+ @Override
+ void skip(int count) {
+ while (count-- > 0) {
+ x += sx;
+ if (e >= 0) {
+ y += sy;
+ e += ePos;
+ } else {
+ e += eNeg;
+ }
+ }
+ }
+
+ }
+
+ static class Ver extends Diag {
+
+ Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ eBase = adx + adx - ady;
+ ePos = 2 * (adx - ady);
+ eNeg = adx + adx;
+ xcount = ady;
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterize(xcount);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1));
+ x = nx1;
+ y = ny1;
+ rasterize(ny2 - ny1);
+ }
+
+ @Override
+ void rasterize(int count) {
+ int py = y;
+ while (count-- > 0) {
+ if (e >= 0) {
+ dst.addRect(x, py, x, y);
+ x += sx;
+ y += sy;
+ e += ePos;
+ py = y;
+ } else {
+ y += sy;
+ e += eNeg;
+ }
+ }
+ dst.addRect(x, py, x, y);
+ }
+
+ @Override
+ void skip(int count) {
+ while (count-- > 0) {
+ y += sy;
+ if (e >= 0) {
+ x += sx;
+ e += ePos;
+ } else {
+ e += eNeg;
+ }
+ }
+ }
+
+ }
+
+ static class HorDashed extends Hor {
+
+ LineDasher local;
+
+ HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+ super(x1, y1, x2, y2, dst);
+ float length = getLength();
+ local = dasher.createDiagonal(xcount / length, length, invert);
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterizeDash(xcount, local);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1));
+ x = nx1;
+ y = ny1;
+ rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1)));
+ }
+
+ }
+
+ static class VerDashed extends Ver {
+
+ LineDasher local;
+
+ VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+ super(x1, y1, x2, y2, dst);
+ float length = getLength();
+ local = dasher.createDiagonal(xcount / length, length, invert);
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterizeDash(xcount, local);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1));
+ x = nx1;
+ y = ny1;
+ rasterizeDash(ny2 - ny1, local.createChild(ny1 - y1));
+ }
+
+ }
+
+ @Override
+ void rasterize(int[] clip, int index) {
+ int cx1 = clip[index + 0];
+ int cy1 = clip[index + 1];
+ int cx2 = clip[index + 2] + 1;
+ int cy2 = clip[index + 3] + 1;
+
+ int code1 =
+ (x1 < cx1 ? 1 : 0) | (x1 >= cx2 ? 2 : 0) |
+ (y1 < cy1 ? 8 : 0) | (y1 >= cy2 ? 4 : 0);
+ int code2 =
+ (x2 < cx1 ? 1 : 0) | (x2 >= cx2 ? 2 : 0) |
+ (y2 < cy1 ? 8 : 0) | (y2 >= cy2 ? 4 : 0);
+
+ // Outside
+ if ((code1 & code2) != 0) {
+ return;
+ }
+
+ // Inside
+ if (code1 == 0 && code2 == 0) {
+ rasterize();
+ return;
+ }
+
+ // Clip
+ int nx1 = x1;
+ int ny1 = y1;
+ int nx2 = x2;
+ int ny2 = y2;
+ // need to clip
+ cx1 -= x1; cx2 -= x1;
+ cy1 -= y1; cy2 -= y1;
+// int d;
+ int newx1 = 0, newy1 = 0, newx2 = 0, newy2 = 0;
+ if (code1 != 0) {
+ newx1 = Integer.MAX_VALUE;
+ if ((code1 & 8) != 0) {
+ // clip point 1 with top clip bound
+ newy1 = cy1;
+ newx1 = clipY(dx, dy, newy1, true);
+
+ } else if ((code1 & 4) != 0) {
+ // clip point 1 with bottom clip bound
+ newy1 = cy2 - 1;
+ newx1 = clipY(dx, dy, newy1, false);
+ }
+ if ((code1 & 1) != 0 && (cx1 > newx1 || newx1 == Integer.MAX_VALUE)) {
+ // clip point 1 with left clip bound
+ newx1 = cx1;
+ newy1 = clipX(dx, dy, newx1, false);
+ } else if ((code1 & 2) != 0 && (newx1 >= cx2 || newx1 == Integer.MAX_VALUE)) {
+ // clip point 1 with right clip bound
+ newx1 = cx2 - 1;
+ newy1 = clipX(dx, dy, newx1, false);
+ }
+ if (newx1 < cx1 || newx1 >= cx2 || newy1 < cy1 || newy1 >= cy2) {
+ return;
+ }
+// d = 2 * (ady * Math.abs(newx1) - adx * Math.abs(newy1)) + 2 * ady - adx;
+ } else {
+// d = (ady << 1) - adx;
+ }
+
+ if (code2 != 0) {
+ newx2=Integer.MAX_VALUE;
+ if ((code2 & 8) != 0) {
+ // clip point 2 with top clip bound
+ newy2 = cy1;
+ newx2 = clipY(dx, dy, newy2, true);
+ } else if ((code2 & 4) != 0) {
+ // clip point 2 with bottom clip bound
+ newy2 = cy2 - 1;
+ newx2 = clipY(dx, dy, newy2, false);
+ }
+ if ((code2 & 1) != 0 && (cx1 > newx2 || newx2 == Integer.MAX_VALUE)) {
+ // clip point 2 with left clip bound
+ newx2 = cx1;
+ newy2 = clipX(dx, dy, newx2, false);
+ } else if ((code2 & 2) != 0 && (newx2 >= cx2 || newx2 == Integer.MAX_VALUE)) {
+ // clip point 2 with right clip bound
+ newx2 = cx2 - 1;
+ newy2 = clipX(dx, dy, newx2, false);
+ }
+ if (newx2 < cx1 || newx2 >= cx2 || newy2 < cy1 || newy2 >= cy2) {
+ return;
+ }
+ nx2 = x1 + newx2;
+ ny2 = y1 + newy2;
+ }
+ nx1 = x1 + newx1;
+ ny1 = y1 + newy1;
+
+ rasterizeClipped(nx1, ny1, nx2, ny2);
+ }
+
+ abstract void rasterizeClipped(int nx1, int ny1, int nx2, int ny2);
+
+ }
+
+ static abstract class Ortog extends Line {
+
+ Ortog(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ }
+
+ static class Hor extends Ortog {
+
+ int dx;
+
+ Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ dx = x2 - x1;
+ }
+
+ @Override
+ void rasterize() {
+ if (dx > 0) {
+ dst.addRect(x1, y1, x2, y2);
+ } else {
+ dst.addRect(x2, y2, x1, y1);
+ }
+ }
+
+ @Override
+ void rasterize(int step) {
+ int px = x;
+ if (dx > 0) {
+ x += step;
+ dst.addRect(px, y1, x - 1, y2);
+ } else {
+ x -= step;
+ dst.addRect(x + 1, y2, px, y1);
+ }
+ }
+
+ @Override
+ void skip(int step) {
+ if (dx > 0) {
+ x += step;
+ } else {
+ x -= step;
+ }
+ }
+
+ void rasterizeClipped(int nx1, int nx2) {
+ if (nx1 < nx2) {
+ dst.addRect(nx1, y1, nx2, y1);
+ } else {
+ dst.addRect(nx2, y1, nx1, y1);
+ }
+ }
+
+ @Override
+ void rasterize(int[] clip, int index) {
+ if (y1 >= clip[index + 1] && y1 <= clip[index + 3]) {
+ int cx1 = clip[index + 0];
+ int cx2 = clip[index + 2];
+ if (x1 <= cx2 && x2 >= cx1) {
+ int nx1, nx2;
+ if (dx > 0) {
+ nx1 = Math.max(x1, cx1);
+ nx2 = Math.min(x2, cx2);
+ } else {
+ nx2 = Math.max(x2, cx1);
+ nx1 = Math.min(x1, cx2);
+ }
+ rasterizeClipped(nx1, nx2);
+ }
+ }
+ }
+
+ }
+
+ static class Ver extends Ortog {
+
+ int dy;
+
+ Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ dy = y2 - y1;
+ }
+
+ @Override
+ void rasterize() {
+ dst.addRect(x1, y1, x2, y2);
+ }
+
+ @Override
+ void rasterize(int step) {
+ int py = y;
+ y += step;
+ dst.addRect(x1, py, x2, y - 1);
+ }
+
+ @Override
+ void skip(int step) {
+ y += step;
+ }
+
+ void rasterizeClipped(int ny1, int ny2) {
+ dst.addRect(x1, ny1, x1, ny2);
+ }
+
+ @Override
+ void rasterize(int[] clip, int index) {
+ if (x1 >= clip[index] && x1 <= clip[index + 2]) {
+ int cy1 = clip[index + 1];
+ int cy2 = clip[index + 3];
+ if (y1 <= cy2 && y2 >= cy1) {
+ rasterizeClipped(Math.max(y1, cy1), Math.min(y2, cy2));
+ }
+ }
+ }
+
+ }
+
+ static class HorDashed extends Hor {
+
+ LineDasher local;
+
+ HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher) {
+ super(x1, y1, x2, y2, dst);
+ dx = x2 - x1;
+ local = dasher.createOrtogonal(Math.abs(dx), false);
+ }
+
+ @Override
+ void rasterize() {
+ x = x1;
+ y = y1;
+ rasterizeDash(Math.abs(dx), local);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int nx2) {
+ x = nx1;
+ y = y1;
+ rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1)));
+ }
+
+ }
+
+ static class VerDashed extends Ver {
+
+ LineDasher local;
+
+ VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+ super(x1, y1, x2, y2, dst);
+ dy = y2 - y1;
+ local = dasher.createOrtogonal(dy, invert);
+ }
+
+ @Override
+ void rasterize() {
+ x = x1;
+ y = y1;
+ rasterizeDash(dy, local);
+ }
+
+ @Override
+ void rasterizeClipped(int ny1, int ny2) {
+ x = x1;
+ y = ny1;
+ rasterizeDash(ny2 - ny1, local.createChild(ny1));
+ }
+
+ }
+
+ }
+
+ abstract void rasterize();
+ abstract void rasterize(int[] clip, int index);
+ abstract void rasterize(int count);
+ abstract void skip(int count);
+
+ void rasterizeDash(int count, LineDasher dasher) {
+ float delta = dasher.dash[dasher.index] - dasher.phase;
+ int step = (int)delta;
+ delta -= step;
+ while(count > step) {
+ if (dasher.visible) {
+ rasterize(step);
+ } else {
+ skip(step);
+ }
+ count -= step;
+ delta += dasher.nextDash();
+ step = (int)delta;
+ delta -= step;
+ }
+ if (count > 0 && dasher.visible) {
+ rasterize(count);
+ dasher.move(count);
+ }
+ }
+
+ }
+
+ /**
+ * Common clipping method
+ */
+ static int clip(int dX1, int dX2, int cX, boolean top) {
+ int adX1 = dX1 < 0 ? -dX1 : dX1;
+ int adX2 = dX2 < 0 ? -dX2 : dX2;
+ if (adX1 <= adX2) {
+ // obtuse intersection angle
+ return ((dX1 << 1) * cX + (dX1 > 0 ? dX2 : -dX2)) / (dX2 << 1);
+ }
+ int k;
+ if (top) {
+ k = -dX1 + (dX2 < 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
+ } else {
+ k = dX1 + (dX2 > 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
+ }
+
+ k += dX1 > 0 == dX2 > 0 ? -1 : 1;
+ return ((dX1 << 1) * cX + k) / (dX2 << 1);
+ }
+
+ /**
+ * Clipping along X axis
+ */
+ static int clipX(int dx, int dy, int cy, boolean top) {
+ return clip(dy, dx, cy, top);
+ }
+
+ /**
+ * Clipping along Y axis
+ */
+ static int clipY(int dx, int dy, int cx, boolean top) {
+ return clip(dx, dy, cx, top);
+ }
+
+ /**
+ * Rasterizes line using clippind and dashing style
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param clip - the MultiRectArea object of clipping area
+ * @param dasher - the dasher style
+ * @param invert - the invert indicator, always false
+ * @return a MultiRectArea of rasterizer line
+ */
+ public static MultiRectArea rasterize(int x1, int y1, int x2, int y2, MultiRectArea clip, LineDasher dasher, boolean invert) {
+
+ MultiRectArea dst = new MultiRectArea(false);
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ // Point
+ if (dx == 0 && dy == 0) {
+ if ((clip == null || clip.contains(x1, y1)) && (dasher == null || dasher.visible)) {
+ dst = new MultiRectArea(x1, y1, x1, y1);
+ }
+ return dst;
+ }
+
+ if (dy < 0) {
+ return rasterize(x2, y2, x1, y1, clip, dasher, true);
+ }
+
+ Line line;
+ if (dasher == null) {
+ if (dx == 0) {
+ line = new Line.Ortog.Ver(x1, y1, x2, y2, dst);
+ } else
+ if (dy == 0) {
+ line = new Line.Ortog.Hor(x1, y1, x2, y2, dst);
+ } else {
+ if (dy < Math.abs(dx)) {
+ line = new Line.Diag.Hor(x1, y1, x2, y2, dst);
+ } else {
+ line = new Line.Diag.Ver(x1, y1, x2, y2, dst);
+ }
+ }
+ } else {
+ if (dx == 0) {
+ line = new Line.Ortog.VerDashed(x1, y1, x2, y2, dst, dasher, invert);
+ } else
+ if (dy == 0) {
+ line = new Line.Ortog.HorDashed(x1, y1, x2, y2, dst, dasher);
+ } else {
+ if (dy < Math.abs(dx)) {
+ line = new Line.Diag.HorDashed(x1, y1, x2, y2, dst, dasher, invert);
+ } else {
+ line = new Line.Diag.VerDashed(x1, y1, x2, y2, dst, dasher, invert);
+ }
+ }
+ }
+
+
+ if (clip == null || clip.isEmpty()) {
+ line.rasterize();
+ } else {
+ for(int i = 1; i < clip.rect[0]; i += 4) {
+ line.rasterize(clip.rect, i);
+ }
+ }
+
+ return dst;
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
new file mode 100644
index 0000000..dbaaf53
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
@@ -0,0 +1,475 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class JavaShapeRasterizer {
+
+ static final int POINT_CAPACITY = 16;
+
+ int edgesCount;
+ int edgeCur;
+ int[] edgesX;
+ int[] edgesY;
+ int[] edgesYS; // Y coordinate of edge START point
+ int[] edgesN;
+ int[] edgesDY;
+ int[] bounds;
+ int boundCount;
+ boolean[] edgesExt; // Extremal points
+
+ int activeCount;
+ float[] activeX;
+ int[] activeYEnd;
+ float[] activeXStep;
+ int[] activeDY;
+ boolean[] activeExt;
+
+ int[] crossX;
+ int[] crossDY;
+
+ Filler filler;
+
+ /**
+ * Rasterization filler for different path rules
+ */
+ static abstract class Filler {
+
+ static class NonZero extends Filler {
+ @Override
+ void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) {
+
+ int[] dst = new int[length];
+ int dstLength = 1;
+ dst[0] = points[0];
+ int count = 0;
+ boolean inside = true;
+ for(int i = 0; i < length; i++) {
+ count += orient[i] > 0 ? 1 : -1;
+ if (count == 0) {
+ dst[dstLength++] = points[i];
+ inside = false;
+ } else {
+ if (!inside) {
+ dst[dstLength++] = points[i];
+ inside = true;
+ }
+ }
+
+ }
+
+ for(int i = 1; i < dstLength; i += 2) {
+ dst[i]--;
+ }
+
+ dstLength = excludeEmpty(dst, dstLength);
+// System.out.println("test");
+
+ dstLength = union(dst, dstLength);
+
+ rect.addLine(dst, dstLength);
+ }
+ }
+
+ static class EvenOdd extends Filler {
+ @Override
+ void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) {
+ /*
+ int[] buf = new int[length];
+ int j = 0;
+ for(int i = 0; i < length - 1; i++) {
+ if (points[i] != points[i + 1]) {
+ buf[j++] = points[i];
+ }
+ }
+ */
+ for(int i = 1; i < length; i += 2) {
+ points[i]--;
+ }
+
+ length = excludeEmpty(points, length);
+// System.out.println("test");
+
+ length = union(points, length);
+ rect.addLine(points, length);
+ /*
+ for(int i = 0; i < length;) {
+ rect.add(points[i++], y, points[i++], y);
+ }
+ */
+ }
+ }
+
+ abstract void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y);
+
+ static int excludeEmpty(int[] points, int length) {
+ int i = 0;
+ while(i < length) {
+ if (points[i] <= points[i + 1]) {
+ i += 2;
+ } else {
+ length -= 2;
+ System.arraycopy(points, i + 2, points, i, length - i);
+ }
+ }
+ return length;
+ }
+
+ static int union(int[] points, int length) {
+ int i = 1;
+ while(i < length - 1) {
+ if (points[i] < points[i - 1]) {
+ System.arraycopy(points, i + 1, points, i - 1, length - i - 1);
+ length -= 2;
+ } else
+ if (points[i] >= points[i + 1] - 1) {
+ System.arraycopy(points, i + 2, points, i, length - i - 2);
+ length -= 2;
+ } else {
+ i += 2;
+ }
+ }
+ return length;
+ }
+
+ }
+
+ public JavaShapeRasterizer() {
+ }
+
+ /**
+ * Checks buffer size and realloc if necessary
+ */
+ int[] checkBufSize(int[] buf, int size) {
+ if (size == buf.length) {
+ int[] tmp;
+ tmp = new int[size + POINT_CAPACITY];
+ System.arraycopy(buf, 0, tmp, 0, buf.length);
+ buf = tmp;
+ }
+ return buf;
+ }
+
+ /**
+ * Adds to the buffers new edge
+ */
+ void addEdge(int x, int y, int num) {
+ edgesX = checkBufSize(edgesX, edgesCount);
+ edgesY = checkBufSize(edgesY, edgesCount);
+ edgesN = checkBufSize(edgesN, edgesCount);
+ edgesX[edgesCount] = x;
+ edgesY[edgesCount] = y;
+ edgesN[edgesCount] = (num << 16) | edgesCount;
+ edgesCount++;
+ }
+
+ /**
+ * Prepare all buffers and variable to rasterize shape
+ */
+ void makeBuffer(PathIterator path, double flatness) {
+ edgesX = new int[POINT_CAPACITY];
+ edgesY = new int[POINT_CAPACITY];
+ edgesN = new int[POINT_CAPACITY];
+ bounds = new int[POINT_CAPACITY];
+ boundCount = 0;
+ edgesCount = 0;
+
+ if (path.getWindingRule() == PathIterator.WIND_EVEN_ODD) {
+ filler = new Filler.EvenOdd();
+ } else {
+ filler = new Filler.NonZero();
+ }
+ float[] coords = new float[2];
+ boolean closed = true;
+ while (!path.isDone()) {
+ switch(path.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!closed) {
+ boundCount++;
+ bounds = checkBufSize(bounds, boundCount);
+ bounds[boundCount] = edgesCount;
+ }
+ addEdge((int)coords[0], (int)coords[1], boundCount);
+ closed = false;
+ break;
+ case PathIterator.SEG_LINETO:
+ addEdge((int)coords[0], (int)coords[1], boundCount);
+ break;
+ case PathIterator.SEG_CLOSE:
+ boundCount++;
+ bounds = checkBufSize(bounds, boundCount);
+ bounds[boundCount] = edgesCount;
+ closed = true;
+ break;
+ default:
+ // awt.36=Wrong segment
+ throw new RuntimeException(Messages.getString("awt.36")); //$NON-NLS-1$
+ }
+ path.next();
+ }
+ if (!closed) {
+ boundCount++;
+ bounds = checkBufSize(bounds, boundCount);
+ bounds[boundCount] = edgesCount;
+ }
+ }
+
+ /**
+ * Sort buffers
+ */
+ void sort(int[] master, int[] slave, int length) {
+ for(int i = 0; i < length - 1; i++) {
+ int num = i;
+ int min = master[num];
+ for(int j = i + 1; j < length; j++) {
+ if (master[j] < min) {
+ num = j;
+ min = master[num];
+ }
+ }
+ if (num != i) {
+ master[num] = master[i];
+ master[i] = min;
+ min = slave[num];
+ slave[num] = slave[i];
+ slave[i] = min;
+ }
+ }
+ }
+
+ int getNext(int cur) {
+ int n = edgesN[cur];
+ int bound = n >> 16;
+ int num = (n & 0xFFFF) + 1;
+ if (num == bounds[bound + 1]) {
+ return bounds[bound];
+ }
+ return num;
+ }
+
+ int getPrev(int cur) {
+ int n = edgesN[cur];
+ int bound = n >> 16;
+ int num = (n & 0xFFFF) - 1;
+ if (num < bounds[bound]) {
+ return bounds[bound + 1] - 1;
+ }
+ return num;
+ }
+
+ int getNextShape(int cur) {
+ int bound = edgesN[cur] >> 16;
+ return bounds[bound + 1];
+ }
+
+ void init() {
+
+ edgesYS = new int[edgesCount];
+ System.arraycopy(edgesY, 0, edgesYS, 0, edgesCount);
+ // Create edgesDY
+ edgesDY = new int[edgesCount];
+ for(int i = 0; i < edgesCount; i++) {
+ int dy = edgesY[getNext(i)] - edgesY[i];
+ edgesDY[i] = dy;
+ }
+
+ // Create edgesExt
+ edgesExt = new boolean[edgesCount];
+ int prev = -1;
+ int i = 0;
+ int pos = 0;
+ while(i < edgesCount) {
+
+ TOP: {
+ do {
+ if (edgesDY[i] > 0) {
+ break TOP;
+ }
+ i = getNext(i);
+ } while (i != pos);
+ i = pos = getNextShape(i);
+ continue;
+ }
+
+ BOTTOM: {
+ do {
+ if (edgesDY[i] < 0) {
+ break BOTTOM;
+ }
+ if (edgesDY[i] > 0) {
+ prev = i;
+ }
+ i = getNext(i);
+ } while (i != pos);
+ i = pos = getNextShape(i);
+ continue;
+ }
+
+ if (prev != -1) {
+ edgesExt[prev] = true;
+ }
+ edgesExt[i] = true;
+ }
+
+ // Sort edgesY and edgesN
+ sort(edgesYS, edgesN, edgesCount);
+
+ edgeCur = 0;
+ activeCount = 0;
+ activeX = new float[edgesCount];
+ activeYEnd = new int[edgesCount];
+ activeXStep = new float[edgesCount];
+ activeDY = new int[edgesCount];
+ activeExt = new boolean[edgesCount];
+
+ crossX = new int[edgesCount];
+ crossDY = new int[edgesCount];
+ }
+
+ /**
+ * Marks edge as active
+ */
+ void addActiveEdge(int levelY, int start, int end, boolean back) {
+ int dy = back ? -edgesDY[end] : edgesDY[start];
+ if (dy <= 0) {
+ return;
+ }
+ int x1 = edgesX[start];
+ int dx = edgesX[end] - x1;
+ activeX[activeCount] = x1;
+ activeYEnd[activeCount] = edgesY[end];
+ activeXStep[activeCount] = dx / (float)dy;
+ activeDY[activeCount] = back ? -dy : dy;
+ activeExt[activeCount] = back ? edgesExt[end] : edgesExt[start];
+ activeCount++;
+ }
+
+ /**
+ * Find new active edges
+ */
+ int findActiveEdges(int levelY) {
+
+ int edgeActive = edgeCur;
+ while (edgeActive < edgesCount && edgesYS[edgeActive] == levelY) {
+ edgeActive++;
+ }
+
+ int activeNext = edgeActive;
+
+ while (edgeActive > edgeCur) {
+ edgeActive--;
+ int num = edgesN[edgeActive] & 0xFFFF;
+ addActiveEdge(levelY, num, getPrev(edgeActive), true);
+ addActiveEdge(levelY, num, getNext(edgeActive), false);
+ }
+
+ edgeCur = activeNext;
+
+ if (activeNext == edgesCount) {
+ return edgesY[edgesCount - 1];
+ }
+ return edgesYS[activeNext];
+ }
+
+ /**
+ * Rasterizes shape with particular flatness
+ * @param shape - the souze Shape to be rasterized
+ * @param flatness - the rasterization flatness
+ * @return a MultiRectArea of rasterized shape
+ */
+ public MultiRectArea rasterize(Shape shape, double flatness) {
+
+ PathIterator path = shape.getPathIterator(null, flatness);
+
+ // Shape is empty
+ if (path.isDone()) {
+ return new MultiRectArea();
+ }
+
+ makeBuffer(path, flatness);
+
+ init();
+
+ int y = edgesYS[0];
+ int nextY = y;
+ int crossCount;
+
+ MultiRectArea.LineCash rect = new MultiRectArea.LineCash(edgesCount);
+ rect.setLine(y);
+
+ while(y <= nextY) {
+
+ crossCount = 0;
+
+ if (y == nextY) {
+
+ int i = activeCount;
+ while(i > 0) {
+ i--;
+ if (activeYEnd[i] == y) {
+
+ activeCount--;
+ int length = activeCount - i;
+ if (length != 0) {
+ int pos = i + 1;
+ System.arraycopy(activeX, pos, activeX, i, length);
+ System.arraycopy(activeYEnd, pos, activeYEnd, i, length);
+ System.arraycopy(activeXStep, pos, activeXStep, i, length);
+ System.arraycopy(activeDY, pos, activeDY, i, length);
+ System.arraycopy(activeExt, pos, activeExt, i, length);
+ }
+ }
+ }
+
+ nextY = findActiveEdges(y);
+ }
+
+ // Get X crossings
+ for(int i = 0; i < activeCount; i++) {
+ crossX[crossCount] = (int)Math.ceil(activeX[i]);
+ crossDY[crossCount] = activeDY[i];
+ crossCount++;
+ }
+
+ if (crossCount == 0) {
+ rect.skipLine();
+ } else {
+ // Sort X crossings
+ sort(crossX, crossDY, crossCount);
+ filler.add(rect, crossX, crossDY, crossCount, y);
+ }
+
+ for(int i = 0; i < activeCount; i++) {
+ activeX[i] += activeXStep[i];
+ }
+
+ y++;
+ }
+
+ return rect;
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java b/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
new file mode 100644
index 0000000..322ba57
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
@@ -0,0 +1,263 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.*;
+import java.awt.image.*;
+
+
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+import org.apache.harmony.awt.gl.TextRenderer;
+import org.apache.harmony.awt.gl.font.CommonGlyphVector;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.Glyph;
+import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
+
+public class JavaTextRenderer extends TextRenderer {
+
+ public static final JavaTextRenderer inst = new JavaTextRenderer();
+
+ @Override
+ public void drawGlyphVector(Graphics2D g, GlyphVector glyphVector,
+ float x, float y) {
+
+ AffineTransform at = g.getTransform();
+ Rectangle c = g.getClipBounds();
+ if (at != null){
+ int atType = at.getType();
+ if (atType == AffineTransform.TYPE_TRANSLATION) {
+ c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
+ }
+ }
+
+ WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
+ ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
+
+ Rectangle rBounds = wr.getBounds();
+
+ Object color = cm.getDataElements(g.getColor().getRGB(), null);
+
+ drawClipGlyphVector(wr, color, glyphVector, (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
+ Math.max(c.x,rBounds.x),
+ Math.max(c.y,rBounds.y),
+ Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
+ Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
+
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void drawString(Graphics2D g, String str, float x, float y) {
+ AffineTransform at = g.getTransform();
+ Rectangle c = g.getClipBounds();
+ if (at != null){
+ int atType = at.getType();
+ if (atType == AffineTransform.TYPE_TRANSLATION) {
+ c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
+ }
+ }
+ WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
+ ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
+ Rectangle rBounds = wr.getBounds();
+
+ Object color = cm.getDataElements(g.getColor().getRGB(), null);
+
+ drawClipString(wr, color, str, (FontPeerImpl) (g.getFont().getPeer()),
+ (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
+ Math.max(c.x,rBounds.x),
+ Math.max(c.y,rBounds.y),
+ Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
+ Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
+
+ }
+
+ /**
+ *
+ * Draws string on specified raster at desired position.
+ *
+ * @param raster specified WritableRaster to draw at
+ * @param color color of the text
+ * @param glyphVector GlyphVector object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ * @param cMinX minimum x of the raster area to draw
+ * @param cMinY minimum y of the raster area to draw
+ * @param cMaxX maximum x of the raster area to draw
+ * @param cMaxY maximum y of the raster area to draw
+ */
+ public void drawClipGlyphVector(WritableRaster raster, Object color,
+ GlyphVector glyphVector, int x, int y,
+ int cMinX, int cMinY, int cMaxX, int cMaxY) {
+ // TODO: implement complex clipping
+
+ int xSrcSurf, ySrcSurf; // Start point in String rectangle
+ int xDstSurf, yDstSurf; // Start point in Surface rectangle
+ int clWidth, clHeight;
+
+ for (int i = 0; i < glyphVector.getNumGlyphs(); i++) {
+ Glyph gl = ((CommonGlyphVector) glyphVector).vector[i];
+
+ if (gl.getPointWidth() == 0) {
+ continue;
+ }
+
+ byte[] data = gl.getBitmap();
+ if (data != null) {
+ Point2D pos = glyphVector.getGlyphPosition(i);
+
+ xSrcSurf = 0;//gl.bmp_left;
+ ySrcSurf = 0;//gl.bmp_rows - gl.bmp_top;
+
+ xDstSurf = x + (int)pos.getX() + (int) gl.getGlyphPointMetrics().getLSB();// + gl.bmp_left;
+ yDstSurf = y - gl.bmp_top/*getPointHeight()*/ + (int) pos.getY();// - (gl.bmp_rows-gl.bmp_top);
+
+ int textWidth = gl.bmp_width;
+ int textHeight = gl.getPointHeight();
+
+ // if Regions don't intersect
+ if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
+ || (yDstSurf + textHeight < cMinY)) {
+ // Nothing to do
+ } else {
+ if (xDstSurf >= cMinX) {
+ clWidth = Math.min(textWidth, cMaxX - xDstSurf);
+ } else {
+ xSrcSurf += cMinX - xDstSurf;
+ clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
+ xDstSurf = cMinX;
+ }
+ if (yDstSurf >= cMinY) {
+ clHeight = Math.min(textHeight, cMaxY - yDstSurf);
+ } else {
+ ySrcSurf += cMinY - yDstSurf;
+ clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
+ yDstSurf = cMinY;
+ }
+ // Drawing on the Raster
+ for (int h=0; h<clHeight; h++){
+ for (int w=0; w < clWidth ; w++) {
+ byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
+ boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
+ if (emptyByte) {
+ raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
+ } else {
+ // Nothing to do
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Draws string on specified raster at desired position.
+ *
+ * @param raster specified WritableRaster to draw at
+ * @param color color of the text
+ * @param str text to draw
+ * @param font font peer to use for drawing text
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ * @param cMinX minimum x of the raster area to draw
+ * @param cMinY minimum y of the raster area to draw
+ * @param cMaxX maximum x of the raster area to draw
+ * @param cMaxY maximum y of the raster area to draw
+ */
+ public void drawClipString(WritableRaster raster, Object color, String str,
+ FontPeerImpl font, int x, int y, int cMinX, int cMinY, int cMaxX,
+ int cMaxY) {
+ // TODO: implement complex clipping
+
+ int xSrcSurf, ySrcSurf; // Start point in String rectangle
+ int xDstSurf, yDstSurf; // Start point in Surface rectangle
+ int clWidth, clHeight;
+
+ char[] chars = str.toCharArray();
+
+ int xBaseLine = x;
+ int yBaseLine = y;
+
+ for (char element : chars) {
+ Glyph gl = font.getGlyph(element);
+ GlyphMetrics pointMetrics = gl.getGlyphPointMetrics();
+ if (gl.getWidth() == 0) {
+ xBaseLine += pointMetrics.getAdvanceX();
+ continue;
+ }
+
+ byte[] data = gl.getBitmap();
+ if (data == null) {
+ xBaseLine += pointMetrics.getAdvanceX();
+ } else {
+
+ xSrcSurf = 0;
+ ySrcSurf = 0;
+
+ xDstSurf = Math.round(xBaseLine + gl.getGlyphPointMetrics().getLSB());
+ yDstSurf = yBaseLine - gl.bmp_top;
+
+ int textWidth = gl.bmp_width;
+ int textHeight = gl.getPointHeight();
+
+ // if Regions don't intersect
+ if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
+ || (yDstSurf + textHeight < cMinY)) {
+ // Nothing to do
+ } else {
+ if (xDstSurf >= cMinX) {
+ clWidth = Math.min(textWidth, cMaxX - xDstSurf);
+ } else {
+ xSrcSurf += cMinX - xDstSurf;
+ clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
+ xDstSurf = cMinX;
+ }
+ if (yDstSurf >= cMinY) {
+ clHeight = Math.min(textHeight, cMaxY - yDstSurf);
+ } else {
+ ySrcSurf += cMinY - yDstSurf;
+ clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
+ yDstSurf = cMinY;
+ }
+
+ // Drawing on the Raster
+ for (int h=0; h<clHeight; h++){
+ for (int w=0; w < clWidth ; w++) {
+ byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
+ boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
+ if (emptyByte) {
+ raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
+ } else {
+ // Nothing to do
+ }
+ }
+ }
+ }
+ xBaseLine += pointMetrics.getAdvanceX();
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java b/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
new file mode 100644
index 0000000..b0ebc97
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 26.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+
+/**
+ * This kind of blitters is intended for drawing one image on the buffered
+ * or volatile image. For the moment we can blit natively Buffered Images which
+ * have sRGB, Linear_RGB, Linear_Gray Color Space and type different
+ * from BufferedImage.TYPE_CUSTOM, Volatile Images and Images which received
+ * using Toolkit and Component classes.
+ */
+public class NativeImageBlitter implements Blitter {
+
+
+ final static NativeImageBlitter inst = new NativeImageBlitter();
+
+ public static NativeImageBlitter getInstance(){
+ return inst;
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+
+ if(!srcSurf.isNativeDrawable()){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, xform, comp, bgcolor, clip);
+ }else{
+ if(xform == null){
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ double scaledX = dstX / scaleX;
+ double scaledY = dstY / scaleY;
+ AffineTransform at = new AffineTransform();
+ at.setToTranslation(scaledX, scaledY);
+ xform.concatenate(at);
+ sysxform.concatenate(xform);
+ blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+ }
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+
+ if(!srcSurf.isNativeDrawable()){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ int type = sysxform.getType();
+ switch(type){
+ case AffineTransform.TYPE_TRANSLATION:
+ dstX += sysxform.getTranslateX();
+ dstY += sysxform.getTranslateY();
+ case AffineTransform.TYPE_IDENTITY:
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+ width, height, comp, bgcolor, clip);
+ break;
+ default:
+ // TODO Need to realize Affine Transformation
+ if(srcSurf instanceof ImageSurface){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY,
+ dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ BufferedImage tmp = new BufferedImage(w, h,
+ BufferedImage.TYPE_INT_RGB);
+ Surface tmpSurf = Surface.getImageSurface(tmp);
+ blit(0, 0, srcSurf, 0, 0, tmpSurf,
+ w, h, AlphaComposite.SrcOver, null, null);
+ JavaBlitter.inst.blit(srcX, srcY, tmpSurf, dstX, dstY,
+ dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+ }
+ }
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ if(!srcSurf.isNativeDrawable()){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ comp, bgcolor, clip);
+ }else{
+ long dstSurfStruct = dstSurf.getSurfaceDataPtr();
+ Object dstData = dstSurf.getData();
+ int clipRects[];
+ if(clip != null){
+ clipRects = clip.rect;
+ }else{
+ clipRects = new int[]{5, 0, 0, dstSurf.getWidth(),
+ dstSurf.getHeight()};
+ }
+
+ if(!(srcSurf instanceof ImageSurface)){
+ srcSurf = srcSurf.getImageSurface();
+ if(bgcolor != null){
+ bgcolor = null;
+ }
+ }
+
+ long srcSurfStruct = srcSurf.getSurfaceDataPtr();
+ Object srcData = srcSurf.getData();
+ if(comp instanceof AlphaComposite){
+ AlphaComposite ac = (AlphaComposite) comp;
+ int compType = ac.getRule();
+ float alpha = ac.getAlpha();
+ if(bgcolor != null){
+ bltBG(srcX, srcY, srcSurfStruct, srcData,
+ dstX, dstY, dstSurfStruct, dstData,
+ width, height, bgcolor.getRGB(),
+ compType, alpha, clipRects, srcSurf.invalidated());
+ dstSurf.invalidate();
+ srcSurf.validate();
+ }else{
+ blt(srcX, srcY, srcSurfStruct, srcData,
+ dstX, dstY, dstSurfStruct, dstData,
+ width, height, compType, alpha,
+ clipRects, srcSurf.invalidated());
+ dstSurf.invalidate();
+ srcSurf.validate();
+ }
+ }else if(comp instanceof XORComposite){
+ XORComposite xcomp = (XORComposite) comp;
+ xor(srcX, srcY, srcSurfStruct, srcData,
+ dstX, dstY, dstSurfStruct, dstData,
+ width, height, xcomp.getXORColor().getRGB(),
+ clipRects, srcSurf.invalidated());
+ dstSurf.invalidate();
+ srcSurf.validate();
+ }else{
+ if(srcSurf instanceof ImageSurface){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY,
+ dstSurf, width, height,
+ comp, bgcolor, clip);
+ }else{
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ BufferedImage tmp = new BufferedImage(w, h,
+ BufferedImage.TYPE_INT_RGB);
+ Surface tmpSurf = Surface.getImageSurface(tmp);
+ long tmpSurfStruct = tmpSurf.getSurfaceDataPtr();
+ Object tmpData = tmpSurf.getData();
+ int tmpClip[] = new int[]{5, 0, 0, srcSurf.getWidth(),
+ srcSurf.getHeight()};
+
+ blt(0, 0, srcSurfStruct, srcData, 0, 0,
+ tmpSurfStruct, tmpData, w, h,
+ AlphaComposite.SRC_OVER,
+ 1.0f, tmpClip, srcSurf.invalidated());
+ srcSurf.validate();
+ JavaBlitter.inst.blit(srcX, srcY, tmpSurf, dstX, dstY,
+ dstSurf, width, height,
+ comp, bgcolor, clip);
+ }
+ }
+ }
+
+ }
+
+ private native void bltBG(int srcX, int srcY, long srsSurfDataPtr,
+ Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+ Object dstData, int width, int height, int bgcolor,
+ int compType, float alpha, int clip[], boolean invalidated);
+
+ private native void blt(int srcX, int srcY, long srsSurfDataPtr,
+ Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+ Object dstData, int width, int height, int compType,
+ float alpha, int clip[], boolean invalidated);
+
+ private native void xor(int srcX, int srcY, long srsSurfDataPtr,
+ Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+ Object dstData, int width, int height, int xorcolor,
+ int clip[], boolean invalidated);
+
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/NullBlitter.java b/awt/org/apache/harmony/awt/gl/render/NullBlitter.java
new file mode 100644
index 0000000..9032e4e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/NullBlitter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 07.12.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+
+
+public class NullBlitter implements Blitter {
+
+ static Blitter inst = new NullBlitter();
+ public static Blitter getInstance(){
+ return inst;
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/im/InputMethodContext.java b/awt/org/apache/harmony/awt/im/InputMethodContext.java
new file mode 100644
index 0000000..45ed11f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/im/InputMethodContext.java
@@ -0,0 +1,563 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.im;
+
+//???AWT
+import java.awt.AWTEvent;
+import java.awt.Component;
+//import java.awt.KeyboardFocusManager;
+import java.awt.Rectangle;
+//import java.awt.Window;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.KeyEvent;
+import java.awt.font.TextHitInfo;
+import java.awt.im.InputContext;
+import java.awt.im.InputMethodRequests;
+import java.awt.im.spi.InputMethod;
+import java.awt.im.spi.InputMethodDescriptor;
+import java.lang.Character.Subset;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+//???AWT
+//import javax.swing.JFrame;
+
+import org.apache.harmony.awt.wtk.NativeIM;
+
+/**
+ * Implementation of InputMethodContext
+ * interface, also provides all useful
+ * functionality of InputContext
+ *
+ */
+public class InputMethodContext extends InputContext implements
+ java.awt.im.spi.InputMethodContext {
+
+ //???AWT
+ private InputMethod inputMethod; // current IM
+ private Component client; // current "active" client component
+ //???AWT: private CompositionWindow composeWindow; // composition Window
+ private final Map<InputMethodDescriptor, InputMethod> imInstances; // Map<InputMethodDescriptor, InputMethod>
+ private final Map<Locale, InputMethod> localeIM; // Map<Locale, InputMethod> last user-selected IM for locale
+ private final Set<InputMethod> notifyIM; // set of IMs to notify of client window bounds changes
+
+ /**
+ * a flag indicating that IM should be notified of client window
+ * position/visibility changes as soon as it is activated(new client
+ * appears)
+ */
+ private boolean pendingClientNotify;
+ private Component nextComp; // component to gain focus after endComposition()
+ //???AWT: private final Set<Window> imWindows; // set of all IM windows created by this instance
+ private final NativeIM nativeIM;
+
+
+
+ public InputMethodContext() {
+ notifyIM = new HashSet<InputMethod>();
+//???AWT: imWindows = new HashSet<Window>();
+ imInstances = new HashMap<InputMethodDescriptor, InputMethod>();
+ localeIM = new HashMap<Locale, InputMethod>();
+ selectInputMethod(Locale.US); // not default?
+ nativeIM = (NativeIM) inputMethod;
+ }
+
+ //???AWT
+ /*
+ @Override
+ public void dispatchEvent(AWTEvent event) {
+ int id = event.getID();
+ if ((id >= FocusEvent.FOCUS_FIRST) && (id <=FocusEvent.FOCUS_LAST)) {
+ dispatchFocusEvent((FocusEvent) event);
+ } else {
+ // handle special KEY_PRESSED
+ // event to show IM selection menu
+ if (id == KeyEvent.KEY_PRESSED) {
+ KeyEvent ke = (KeyEvent) event;
+ IMManager.selectIM(ke, this,
+ IMManager.getWindow(ke.getComponent()));
+ }
+ // dispatch all input events to the current IM:
+ if (inputMethod != null) {
+ inputMethod.dispatchEvent(event);
+ }
+ }
+ }
+
+ private void dispatchFocusEvent(FocusEvent fe) {
+ switch (fe.getID()) {
+ case FocusEvent.FOCUS_LOST:
+ if (inputMethod != null) {
+ inputMethod.deactivate(fe.isTemporary());
+ }
+ break;
+ case FocusEvent.FOCUS_GAINED:
+
+ Component comp = fe.getComponent();
+ if (imWindows.contains(comp)) {
+ // prevent activating when IM windows
+ // attached to this context gain focus
+ return;
+ }
+ InputMethodContext lastActive = IMManager.getLastActiveIMC();
+ if ((lastActive != this) && (lastActive != null)) {
+ lastActive.hideWindows();
+ }
+ if (inputMethod != null) {
+ activateIM(inputMethod);
+ if (!getCompositionWindow().isEmpty()) {
+ IMManager.showCompositionWindow(composeWindow);
+ }
+ if (client == comp) {
+ if (nextComp != null) {
+ // temporarily got focus to
+ // end composition
+ endComposition();
+
+ // transfer focus to new client
+ client = nextComp;
+ nextComp = null;
+ client.requestFocusInWindow();
+ }
+ } else if ((client != null) && getCompositionWindow().isVisible()) {
+ // temporarily return focus back
+ // to previous client to be able
+ // to end composition
+ nextComp = comp;
+ client.requestFocusInWindow();
+ } else {
+ client = comp;
+ }
+ }
+ if (pendingClientNotify) {
+ notifyClientWindowChange(IMManager.getWindow(comp).getBounds());
+ }
+ break;
+ }
+
+ }
+
+ private void activateIM(InputMethod im) {
+ im.activate();
+ if ((nativeIM != null) && (im != nativeIM)) {
+ // when Java IM is active
+ // native input method editor must be
+ // explicitly disabled
+ nativeIM.disableIME();
+ }
+ IMManager.setLastActiveIMC(this);
+ }
+
+ @SuppressWarnings("deprecation")
+ private void hideWindows() {
+ if (inputMethod != null) {
+ inputMethod.hideWindows();
+ }
+ if (composeWindow != null) {
+ composeWindow.hide();
+ }
+ }
+
+ private void createCompositionWindow() {
+ composeWindow = new CompositionWindow(client);
+ }
+
+ private CompositionWindow getCompositionWindow() {
+ if (composeWindow == null) {
+ createCompositionWindow();
+ }
+ composeWindow.setClient(client);
+ return composeWindow;
+ }
+ */
+
+ /**
+ * Gets input method requests for the current client
+ * irrespective of input style.
+ * @return input method requests of composition window if
+ * client is passive,
+ * otherwise input method requests of client
+ */
+ private InputMethodRequests getIMRequests() {
+ InputMethodRequests imRequests = null;
+
+ if (client != null) {
+ imRequests = client.getInputMethodRequests();
+ //???AWT
+ /*
+ if (imRequests == null) {
+ imRequests = getCompositionWindow().getInputMethodRequests();
+ }
+ */
+ }
+
+ return imRequests;
+ }
+
+ /**
+ * Gets input method requests for the current client & input style.
+ * @return input method requests of composition window if
+ * input style is "below-the-spot"(or client is passive),
+ * otherwise client input method requests
+ */
+ private InputMethodRequests getStyleIMRequests() {
+ //???AWT
+ /*
+ if (IMManager.belowTheSpot()) {
+ return getCompositionWindow().getInputMethodRequests();
+ }
+ */
+ return getIMRequests();
+ }
+
+ @Override
+ public void dispose() {
+ if (inputMethod != null) {
+ closeIM(inputMethod);
+ inputMethod.dispose();
+ }
+ notifyIM.clear();
+ super.dispose();
+ }
+
+ @Override
+ public void endComposition() {
+ if (inputMethod != null) {
+ inputMethod.endComposition();
+ }
+ super.endComposition();
+ }
+
+ @Override
+ public Object getInputMethodControlObject() {
+ if (inputMethod != null) {
+ return inputMethod.getControlObject();
+ }
+ return super.getInputMethodControlObject();
+ }
+
+ @Override
+ public Locale getLocale() {
+ if (inputMethod != null) {
+ return inputMethod.getLocale();
+ }
+ return super.getLocale();
+ }
+
+ @Override
+ public boolean isCompositionEnabled() {
+ if (inputMethod != null) {
+ return inputMethod.isCompositionEnabled();
+ }
+ return super.isCompositionEnabled();
+ }
+
+ @Override
+ public void reconvert() {
+ if (inputMethod != null) {
+ inputMethod.reconvert();
+ }
+ super.reconvert();
+ }
+
+ //???AWT
+ /*
+ @Override
+ public void removeNotify(Component client) {
+ if ((inputMethod != null) && (client == this.client)) {
+ inputMethod.removeNotify();
+ client = null;
+ // set flag indicating that IM should be notified
+ // as soon as it is activated(new client appears)
+ pendingClientNotify = true;
+ }
+
+ super.removeNotify(client);
+ }
+ */
+
+ @Override
+ public boolean selectInputMethod(Locale locale) {
+
+ if ((inputMethod != null) && inputMethod.setLocale(locale)) {
+ return true;
+ }
+ // first
+ // take last user-selected IM for locale
+ InputMethod newIM = localeIM.get(locale);
+
+ // if not found search through IM descriptors
+ // and take already created instance if exists
+ // or create, store new IM instance in descriptor->instance map
+ //???AWT
+ /*
+ if (newIM == null) {
+ try {
+ newIM = getIMInstance(IMManager.getIMDescriptors().iterator(),
+ locale);
+ } catch (Exception e) {
+ // ignore exceptions - just return false
+ }
+ }
+ */
+
+ return switchToIM(locale, newIM);
+ }
+
+ private boolean switchToIM(Locale locale, InputMethod newIM) {
+ //???AWT
+ /*
+ if (newIM != null) {
+ closeIM(inputMethod);
+ client = KeyboardFocusManager.
+ getCurrentKeyboardFocusManager().getFocusOwner();
+ initIM(newIM, locale);
+ inputMethod = newIM;
+
+ return true;
+ }
+ */
+ return false;
+ }
+
+ /**
+ * Is called when IM is selected from UI
+ */
+ void selectIM(InputMethodDescriptor imd, Locale locale) {
+ try {
+ switchToIM(locale, getIMInstance(imd));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets input method instance for the given
+ * locale from the given list of descriptors
+ * @param descriptors iterator of the list of IM descriptors
+ * @param locale the locale to be supported by the IM
+ * @return input method instance
+ * @throws Exception
+ */
+ private InputMethod getIMInstance(Iterator<InputMethodDescriptor> descriptors,
+ Locale locale) throws Exception {
+ while (descriptors.hasNext()) {
+ InputMethodDescriptor desc = descriptors.next();
+ Locale[] locs = desc.getAvailableLocales();
+ for (Locale element : locs) {
+ if (locale.equals(element)) {
+ return getIMInstance(desc);
+ }
+ }
+ }
+ return null;
+ }
+
+ private InputMethod getIMInstance(InputMethodDescriptor imd) throws Exception {
+ InputMethod im = imInstances.get(imd);
+ if (im == null) {
+ im = imd.createInputMethod();
+ im.setInputMethodContext(this);
+ imInstances.put(imd, im);
+ }
+ return im;
+ }
+
+ private void initIM(InputMethod im, Locale locale) {
+ if (im == null) {
+ return;
+ }
+ im.setLocale(locale);
+ im.setCharacterSubsets(null);
+ //???AWT: activateIM(im);
+ try {
+ im.setCompositionEnabled(inputMethod != null ?
+ inputMethod.isCompositionEnabled() : true);
+ } catch (UnsupportedOperationException uoe) {
+
+ }
+
+ }
+
+ private void closeIM(InputMethod im) {
+ if (im == null) {
+ return;
+ }
+ if (im.isCompositionEnabled()) {
+ im.endComposition();
+ }
+
+ im.deactivate(true);
+ im.hideWindows();
+
+ }
+
+ @Override
+ public void setCharacterSubsets(Subset[] subsets) {
+ if (inputMethod != null) {
+ inputMethod.setCharacterSubsets(subsets);
+ }
+ super.setCharacterSubsets(subsets);
+ }
+
+ @Override
+ public void setCompositionEnabled(boolean enable) {
+ if (inputMethod != null) {
+ inputMethod.setCompositionEnabled(enable);
+ }
+ super.setCompositionEnabled(enable);
+ }
+
+ //???AWT
+ /*
+ public JFrame createInputMethodJFrame(String title,
+ boolean attachToInputContext) {
+ JFrame jf = new IMJFrame(title, attachToInputContext ? this : null);
+ imWindows.add(jf);
+ return jf;
+ }
+
+ public Window createInputMethodWindow(String title,
+ boolean attachToInputContext) {
+ Window w = new IMWindow(title, attachToInputContext ? this : null);
+ imWindows.add(w);
+ return w;
+ }
+ */
+
+ @SuppressWarnings("deprecation")
+ public void dispatchInputMethodEvent(int id,
+ AttributedCharacterIterator text,
+ int committedCharacterCount,
+ TextHitInfo caret,
+ TextHitInfo visiblePosition) {
+ if (client == null) {
+ return;
+ }
+ //???AWT
+ /*
+ InputMethodEvent ime = new InputMethodEvent(client, id, text,
+ committedCharacterCount,
+ caret, visiblePosition);
+
+
+ if ((client.getInputMethodRequests() != null) &&
+ !IMManager.belowTheSpot()) {
+
+ client.dispatchEvent(ime);
+ } else {
+
+ // show/hide composition window if necessary
+ if (committedCharacterCount < text.getEndIndex()) {
+ IMManager.showCompositionWindow(getCompositionWindow());
+ } else {
+ getCompositionWindow().hide();
+ }
+ composeWindow.getActiveClient().dispatchEvent(ime);
+ }
+ */
+
+ }
+
+ public void enableClientWindowNotification(InputMethod inputMethod,
+ boolean enable) {
+ if (enable) {
+ notifyIM.add(inputMethod);
+ //???AWT
+ /*
+ if (client != null) {
+ notifyClientWindowChange(IMManager.getWindow(client).getBounds());
+ } else {
+ pendingClientNotify = true;
+ }
+ */
+ } else {
+ notifyIM.remove(inputMethod);
+ }
+
+ }
+
+ public AttributedCharacterIterator cancelLatestCommittedText(
+ Attribute[] attributes) {
+ return getIMRequests().cancelLatestCommittedText(attributes);
+ }
+
+ public AttributedCharacterIterator getCommittedText(int beginIndex,
+ int endIndex,
+ Attribute[] attributes) {
+ return getIMRequests().getCommittedText(beginIndex, endIndex,
+ attributes);
+ }
+
+ public int getCommittedTextLength() {
+ return getIMRequests().getCommittedTextLength();
+ }
+
+ public int getInsertPositionOffset() {
+ return getIMRequests().getInsertPositionOffset();
+ }
+
+ public TextHitInfo getLocationOffset(int x, int y) {
+ InputMethodRequests imr = getStyleIMRequests();
+ if (imr != null) {
+ return imr.getLocationOffset(x, y);
+ }
+ return null;
+ }
+
+ public AttributedCharacterIterator getSelectedText(Attribute[] attributes) {
+ return getIMRequests().getSelectedText(attributes);
+ }
+
+ public Rectangle getTextLocation(TextHitInfo offset) {
+ return getStyleIMRequests().getTextLocation(offset);
+ }
+
+ /**
+ * To be called by AWT when client Window's bounds/visibility/state
+ * change
+ */
+ public void notifyClientWindowChange(Rectangle bounds) {
+ if (notifyIM.contains(inputMethod)) {
+ inputMethod.notifyClientWindowChange(bounds);
+ }
+ pendingClientNotify = false;
+ }
+
+ public final InputMethod getInputMethod() {
+ return inputMethod;
+ }
+
+ public final Component getClient() {
+ return client;
+ }
+
+ public final NativeIM getNativeIM() {
+ return nativeIM;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/internal/nls/Messages.java b/awt/org/apache/harmony/awt/internal/nls/Messages.java
new file mode 100644
index 0000000..96762c9
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/Messages.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.awt.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+// BEGIN android-deleted
+/*
+ * For Android, this module is a separate library and not part of the
+ * boot classpath, so its resources won't be found on the boot classpath
+ * as is assumed by MsgHelp.getString(). We instead use a local MsgHelp
+ * which bottoms out in a call to the useful part of its lower-level
+ * namesake.
+ */
+//import org.apache.harmony.kernel.vm.VM;
+//import org.apache.harmony.luni.util.MsgHelp;
+// END android-deleted
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.awt.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ // BEGIN android-deleted
+ //private static final String sResource =
+ // "org.apache.harmony.awt.internal.nls.messages";
+ // END android-deleted
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(msg, args);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java b/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
new file mode 100644
index 0000000..b57fe11
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This implementation is based on the class of the same name in
+ * org.apache.harmony.luni.util.
+ */
+
+package org.apache.harmony.awt.internal.nls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Logger;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.MissingResourceException;
+
+/**
+ * This class contains helper methods for loading resource bundles and
+ * formatting external message strings.
+ */
+public final class MsgHelp {
+ /** name of the resource for this class */
+ private static final String RESOURCE_NAME =
+ "/org/apache/harmony/awt/internal/nls/messages.properties";
+
+ /** the resource bundle for this class */
+ private static final ResourceBundle THE_BUNDLE;
+
+ static {
+ ResourceBundle rb = null;
+
+ try {
+ InputStream in = MsgHelp.class.getResourceAsStream(
+ RESOURCE_NAME);
+ rb = new PropertyResourceBundle(in);
+ } catch (IOException ex) {
+ Logger.global.warning("Couldn't read resource bundle: " +
+ ex);
+ } catch (RuntimeException ex) {
+ // Shouldn't happen, but deal at least somewhat gracefully.
+ Logger.global.warning("Couldn't find resource bundle: " +
+ ex);
+ }
+
+ THE_BUNDLE = rb;
+ }
+
+ public static String getString(String msg) {
+ if (THE_BUNDLE == null) {
+ return msg;
+ }
+ try {
+ return THE_BUNDLE.getString(msg);
+ } catch (MissingResourceException e) {
+ return "Missing message: " + msg;
+ }
+ }
+
+ static public String getString(String msg, Object[] args) {
+ String format = msg;
+ if (THE_BUNDLE != null) {
+ try {
+ format = THE_BUNDLE.getString(msg);
+ } catch (MissingResourceException e) {
+ }
+ }
+
+ return org.apache.harmony.luni.util.MsgHelp.format(format, args);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/state/MenuItemState.java b/awt/org/apache/harmony/awt/state/MenuItemState.java
new file mode 100644
index 0000000..b13e50b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/MenuItemState.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+/**
+ * State of menu item
+ */
+
+public interface MenuItemState {
+
+ String getText();
+ Rectangle getTextBounds();
+ void setTextBounds(int x, int y, int w, int h);
+
+ String getShortcut();
+ Rectangle getShortcutBounds();
+ void setShortcutBounds(int x, int y, int w, int h);
+
+ Rectangle getItemBounds();
+ void setItemBounds(int x, int y, int w, int h);
+
+ boolean isMenu();
+ boolean isChecked();
+ boolean isEnabled();
+
+ boolean isCheckBox();
+ boolean isSeparator();
+
+ Dimension getMenuSize();
+}
diff --git a/awt/org/apache/harmony/awt/state/MenuState.java b/awt/org/apache/harmony/awt/state/MenuState.java
new file mode 100644
index 0000000..564a49a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/MenuState.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+
+/**
+ * State of pop-up or drop-down menu
+ */
+
+public interface MenuState {
+ int getWidth();
+ int getHeight();
+ Point getLocation();
+
+ void setSize(int w, int h);
+
+ Font getFont();
+ boolean isFontSet();
+ FontMetrics getFontMetrics(Font f);
+
+ int getItemCount();
+ int getSelectedItemIndex();
+
+ MenuItemState getItem(int index);
+}
diff --git a/awt/org/apache/harmony/awt/state/State.java b/awt/org/apache/harmony/awt/state/State.java
new file mode 100644
index 0000000..4b8706d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/State.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+
+/**
+ * State of the component
+ */
+public interface State {
+
+ boolean isEnabled();
+ boolean isVisible();
+ boolean isFocused();
+
+ Font getFont();
+ boolean isFontSet();
+ FontMetrics getFontMetrics();
+
+ Color getBackground();
+ boolean isBackgroundSet();
+
+ Color getTextColor();
+ boolean isTextColorSet();
+
+ Rectangle getBounds();
+ Dimension getSize();
+
+ Dimension getDefaultMinimumSize();
+ void setDefaultMinimumSize(Dimension size);
+
+ long getWindowId();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/CreationParams.java b/awt/org/apache/harmony/awt/wtk/CreationParams.java
new file mode 100644
index 0000000..63c581d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/CreationParams.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * This class describes cross-platform NativeWindow creation params
+ * See also WindowFactory.createWindow
+ */
+public class CreationParams {
+ /**
+ * Initial state is maximized verticaly
+ */
+ public final long MAXIMIZED_VERT = 1;
+ /**
+ * Initial state is maximized horizontaly
+ */
+ public final long MAXIMIZED_HORIZ = 2;
+ /**
+ * Initial state is maximized both
+ * horizontaly and verticaly
+ */
+ public final long MAXIMIZED = 3;
+
+ /**
+ * The top-level window that has all possible decorations,
+ * has no owner and is displayed in taskbar
+ */
+ public final static int DECOR_TYPE_FRAME = 1;
+ /**
+ * The dialog window
+ */
+ public final static int DECOR_TYPE_DIALOG = 2;
+ /**
+ * The transient undecorated pop-up window
+ */
+ public final static int DECOR_TYPE_POPUP = 3;
+ /**
+ * The undecoraded pop-up window
+ */
+ public final static int DECOR_TYPE_UNDECOR = 4;
+ /**
+ * Non-MDI child window
+ */
+ public final static int DECOR_TYPE_NONE = 0;
+
+ /**
+ * Initial x.
+ */
+ public int x = 0;
+ /**
+ * Initial y.
+ */
+ public int y = 0;
+ /**
+ * Initial width.
+ */
+ public int w = 1;
+ /**
+ * Initial height.
+ */
+ public int h = 1;
+ /**
+ * The decoration type of the top-level window. The possible values are:
+ * DECOR_TYPE_FRAME, DECOR_TYPE_DIALOG, DECOR_TYPE_POPUP and DECOR_TYPE_UNDECOR
+ */
+ public int decorType = DECOR_TYPE_NONE;
+ /**
+ * Window is child of parent, otherwise it's
+ * toplevel(child of desktop) window owned by parent.
+ */
+ public boolean child = false;
+ /**
+ * Window is resizable
+ */
+ public boolean resizable = true;
+ /**
+ * The window has no decorations
+ */
+ public boolean undecorated = false;
+ /**
+ * Initial visibility state.
+ */
+ public boolean visible = false;
+ /**
+ * Window is ALWAYS topmost in Z order.
+ */
+ public boolean topmost = false;
+ /**
+ * Window is disabled.
+ */
+ public boolean disabled = false;
+ /**
+ * Window initially iconified.
+ */
+ public boolean iconified = false;
+ /**
+ * Bitwise OR of MAXIMIZED_* constants.
+ * Means if window is initially maximized.
+ */
+ public int maximizedState = 0;
+ /**
+ * Tells that window position should be determined by native windowing system
+ */
+ public boolean locationByPlatform = false;
+ /**
+ * Id of parent or owner window, see child field
+ * For non-child window without owner equals 0.
+ */
+ public long parentId = 0;
+ /**
+ * Name wich is displayed on titlebar, taskbar and visible
+ * for system requests.
+ */
+ public String name = null;
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/wtk/CursorFactory.java b/awt/org/apache/harmony/awt/wtk/CursorFactory.java
new file mode 100644
index 0000000..35e7d33
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/CursorFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Dimension;
+import java.awt.Image;
+
+/**
+ * Provides factory for NativeCursor
+ */
+public abstract class CursorFactory {
+ protected NativeCursor[] systemCursors = {
+ null, null, null, null,
+ null, null, null, null,
+ null, null, null, null,
+ null, null,
+ };
+ /**
+ * Creates and returns NativeCursor for predefined
+ * Java Cursor
+ *
+ * @param type - type of predefined Java Cursor
+ * @return created cursor
+ */
+ public abstract NativeCursor createCursor(int type);
+
+ /**
+ * Gets a cached instance of system(predefined) native cursor
+ * or creates a new one. This is a platform-independent method.
+ *
+ * @param type - type of predefined Java Cursor
+ * @return created cursor
+ */
+ public NativeCursor getCursor(int type) {
+ if (type >= 0 && type < systemCursors.length) {
+ NativeCursor cursor = systemCursors[type];
+ if (cursor == null) {
+ cursor = createCursor(type);
+ systemCursors[type] = cursor;
+ }
+ return cursor;
+ }
+ return null;
+ }
+ /**
+ * Creates and returns custom NativeCursor from image
+ *
+ * @param img - image(source) to create cursor from
+ * @param xHotSpot - x coordinate of the hotspot relative to the source's origin
+ * @param yHotSpot - y coordinate of the hotspot relative to the source's origin
+ * @return created cursor
+ */
+ public abstract NativeCursor createCustomCursor(Image img, int xHotSpot, int yHotSpot);
+
+ /**
+ * Query native system for the best cursor size closest to specified dimensions
+ * @param prefWidth - preferred width
+ * @param prefHeight - preferred height
+ * @return closest supported dimensions to ones specified
+ */
+ public abstract Dimension getBestCursorSize(int prefWidth, int prefHeight);
+
+ /**
+ * @return maximum number of colors supported by custom cursors
+ */
+ public abstract int getMaximumCursorColors();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java b/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
new file mode 100644
index 0000000..0d7c84f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov, Alexey A. Petrenko, Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.peer.FontPeer;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.font.FontManager;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+
+/**
+ * GraphicsFactory interface defines methods for Graphics2D
+ * and font stuff instances factories.
+ */
+public interface GraphicsFactory {
+ static final FontMetrics cacheFM[] = new FontMetrics[10];
+
+ /**
+ * This method creates Graphics2D instance for specified native window.
+ *
+ * @param win Native window to draw
+ * @param translateX Translation along X axis
+ * @param translateY Translation along Y axis
+ * @param clip Clipping area for a new Graphics2D instance
+ * @return New Graphics2D instance for specified native window
+ * @deprecated
+ */
+ @Deprecated
+ Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, MultiRectArea clip);
+
+ /**
+ * This method creates Graphics2D instance for specified native window.
+ *
+ * @param win Native window to draw
+ * @param translateX Translation along X axis
+ * @param translateY Translation along Y axis
+ * @param width Width of drawing area
+ * @param height Height of drawing area
+ * @return New Graphics2D instance for specified native window
+ */
+ Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, int width, int height);
+ // ???AWT: not standard harmony
+ Graphics2D getGraphics2D(Canvas c, Paint p);
+
+ /**
+ * Creates instance of GraphicsEnvironment for specified WindowFactory
+ *
+ * @param wf WindowFactory
+ * @return New instance of GraphicsEnvironment
+ */
+ GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf);
+
+ // Font methods
+ FontMetrics getFontMetrics(Font font);
+ FontManager getFontManager();
+ FontPeer getFontPeer(Font font);
+ Font embedFont(String fontFilePath);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/KeyInfo.java b/awt/org/apache/harmony/awt/wtk/KeyInfo.java
new file mode 100644
index 0000000..1f8a29a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/KeyInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.event.KeyEvent;
+
+/**
+ * Keystroke information
+ */
+
+public final class KeyInfo {
+
+ public int vKey;
+ public int keyLocation;
+ public final StringBuffer keyChars;
+
+ public static final int DEFAULT_VKEY = KeyEvent.VK_UNDEFINED;
+ public static final int DEFAULT_LOCATION = KeyEvent.KEY_LOCATION_STANDARD;
+
+ public KeyInfo() {
+ vKey = DEFAULT_VKEY;
+ keyLocation = DEFAULT_LOCATION;
+ keyChars = new StringBuffer();
+ }
+
+ public void setKeyChars(char ch) {
+ keyChars.setLength(0);
+ keyChars.append(ch);
+ }
+
+ public void setKeyChars(StringBuffer sb) {
+ keyChars.setLength(0);
+ keyChars.append(sb);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeCursor.java b/awt/org/apache/harmony/awt/wtk/NativeCursor.java
new file mode 100644
index 0000000..2c6eb1e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeCursor.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * The interface provides access to platform dependent functionality
+ * for the class java.awt.Cursor.
+ */
+public interface NativeCursor {
+ /**
+ * Sets the current cursor shape
+ * to this cursor when a pointer is inside
+ * @param winID - window(currently used only on X11)
+ */
+ void setCursor(long winID);
+ /**
+ * Destroys the native resource associated with
+ * this cursor
+ */
+ void destroyCursor();
+
+ /**
+ * @return Native handle associated with this cursor
+ */
+ long getId();
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEvent.java b/awt/org/apache/harmony/awt/wtk/NativeEvent.java
new file mode 100644
index 0000000..1471c1a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEvent.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+/**
+ * The interface describing cross-platform translation of system
+ * messages.
+ *
+ * <p/>Some messages can appear only on specific platform,
+ * but they still can have cross-platform interpretation if the
+ * application should be aware of them and can react using
+ * cross-platform API.
+ *
+ */
+public abstract class NativeEvent {
+
+ /**
+ * Message has no common cross-platform
+ * interpretation and should be skipped.
+ */
+ public static final int ID_PLATFORM = 0;
+
+ /**
+ * Window bounds have changed.
+ */
+ public static final int ID_BOUNDS_CHANGED = -1;
+
+ /**
+ * Window decoration size has changed.
+ */
+ public static final int ID_INSETS_CHANGED = -2;
+
+ /**
+ * Window was just created (WM_CREATE on Windows)
+ */
+ public static final int ID_CREATED = -3;
+
+ /**
+ * Mouse grab was canceled by the native system
+ */
+ public static final int ID_MOUSE_GRAB_CANCELED = -4;
+
+ /**
+ * System color scheme or visual theme was changed
+ */
+ public static final int ID_THEME_CHANGED = -5;
+
+ protected long windowId;
+ protected int eventId;
+ protected long otherWindowId;
+
+ protected Point screenPos;
+ protected Point localPos;
+ protected Rectangle windowRect;
+
+ protected int modifiers;
+ protected int mouseButton;
+ protected int wheelRotation;
+
+ protected KeyInfo keyInfo = new KeyInfo();
+
+ protected int windowState = -1;
+ protected long time;
+
+ /**
+ * Returns the system window id of the event recipient.
+ * @return HWND on Windows, xwindnow on X
+ */
+ public long getWindowId() {
+ return windowId;
+ }
+
+ /**
+ * Returns cross-platform event id
+ * should be one of ID_* constants or
+ * id constants from java.awt.AWTEvent subclasess
+ * @return cross-platform event id
+ */
+ public int getEventId() {
+ return eventId;
+ }
+
+ /**
+ * Returns the position of cursor when event occured relative to
+ * top-left corner of recipient window
+ * @return position of cursor in local coordinates
+ */
+ public Point getLocalPos() {
+ return localPos;
+ }
+
+ /**
+ * Returns the position of cursor when event occured
+ * in screen coordinates.
+ * @return position of cursor in screen coordinates
+ */
+ public Point getScreenPos() {
+ return screenPos;
+ }
+
+ /**
+ * The recipient window bounds when the event occured
+ * @return window bounds
+ */
+ public Rectangle getWindowRect() {
+ return windowRect;
+ }
+
+ /**
+ * Returns the state of keyboard and mouse buttons when the event
+ * occured if event from mouse or keyboard, for other events can
+ * return junk values. The value is bitwise OR of
+ * java.awt.event.InputEvent *_DOWN constants.
+ *
+ * Method is aware of system mouse button swap for left-hand
+ * mouse and return swapped values.
+ * @return bitwise OR of java.awt.event.InputEvent *_DOWN constants
+ */
+ public int getInputModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Returns the iconified/maximized state of recipient window if
+ * event is state related, for other events can junk values.
+ * The value has the same meaning as Frame.getExtendedState
+ * It's bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT
+ * @return bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT
+ */
+ public int getWindowState() {
+ return windowState;
+ }
+
+ /**
+ * The same meaning as java.awt.event.getKeyCode
+ * @return java.awt.event VK_* constant
+ */
+ public int getVKey() {
+ return (keyInfo != null) ? keyInfo.vKey : KeyInfo.DEFAULT_VKEY;
+ }
+
+ /**
+ * The same meaning as java.awt.event.getKeyLocation
+ * @return java.awt.event KEY_LOCATION_* constant
+ */
+ public int getKeyLocation() {
+ return (keyInfo != null) ? keyInfo.keyLocation : KeyInfo.DEFAULT_LOCATION;
+ }
+
+ /**
+ * Return the string of characters associated with the event
+ * Has meaning only for KEY_PRESSED as should be translated to
+ * serie of KEY_TYPED events. For dead keys and input methods
+ * one key press can generate multiple key chars.
+ * @return string of characters
+ */
+ public StringBuffer getKeyChars() {
+ if (keyInfo == null) {
+ return null;
+ }
+ if (keyInfo.vKey == KeyEvent.VK_ENTER) {
+ keyInfo.keyChars.setLength(0);
+ keyInfo.setKeyChars('\n');
+ }
+ return keyInfo.keyChars;
+ }
+
+ public char getLastChar() {
+ if (keyInfo == null || keyInfo.keyChars.length() == 0) {
+ return KeyEvent.CHAR_UNDEFINED;
+ }
+ return keyInfo.keyChars.charAt(keyInfo.keyChars.length()-1);
+ }
+
+ /**
+ * Returns the number of mouse button which changed it's state,
+ * otherwise 0.
+ * Left button is 1, middle button is 2, right button is 3.
+ *
+ * Method is aware of system mouse button swap for left-hand
+ * mouse and return swapped values.
+ * @return mouse button number
+ */
+ public int getMouseButton() {
+ return mouseButton;
+ }
+
+ /**
+ * Returns time when the message was received
+ * @return time in milliseconds
+ */
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * For the focus event contains the oposite window.
+ * This means it lost focus if recipient gains it,
+ * or will gain focus if recipient looses it.
+ * @return HWND on Windows, xwindnow on X
+ */
+ public long getOtherWindowId() {
+ return otherWindowId;
+ }
+
+ /**
+ * Returns the "dirty" area of the window as set of non-intersecting
+ * rectangles. This area is to be painted.
+ * @return non-empty array of null if empty
+ */
+ public abstract MultiRectArea getClipRects();
+
+ /**
+ * Returns the "dirty" area of the window as one rectangle.
+ * This area is to be painted.
+ * @return non-null Rectangle
+ */
+ public abstract Rectangle getClipBounds();
+
+ /**
+ * Returns the window insets. Insets is area which belongs to
+ * window somehow but is outside of it's client area,
+ * it usually contains system provided border and titlebar.
+ * @return non-null java.awt.Insets
+ */
+ public abstract Insets getInsets();
+
+ /**
+ * Returns true if event is popup menu trigger.
+ * @return boolean flag
+ */
+ public abstract boolean getTrigger();
+
+ /**
+ * Returns the number of "clicks" the mouse wheel was rotated.
+ * @return negative values if the mouse wheel was rotated up/away from the user,
+ * and positive values if the mouse wheel was rotated down/ towards the user
+ */
+ public int getWheelRotation() {
+ return wheelRotation;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java b/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
new file mode 100644
index 0000000..0738cd1
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.util.LinkedList;
+
+
+/**
+ * Describes the cross-platform native event queue interface
+ *
+ * <p/> The implementation constructor should remember thread it was
+ * created. All other methods would be called obly from this thread,
+ * except awake().
+ */
+public abstract class NativeEventQueue {
+
+ private ShutdownWatchdog shutdownWatchdog;
+ private class EventMonitor {}
+ private final Object eventMonitor = new EventMonitor();
+ private final LinkedList<NativeEvent> eventQueue = new LinkedList<NativeEvent>();
+
+ public static abstract class Task {
+ public volatile Object returnValue;
+
+ public abstract void perform();
+ }
+
+ /**
+ * Blocks current thread until native event queue is not empty
+ * or awaken from other thread by awake().
+ *
+ * <p/>Should be called only on tread which
+ * will process native events.
+ *
+ * @return if event loop should be stopped
+ */
+ public abstract boolean waitEvent();
+
+ /**
+ * Determines whether or not the native event queue is empty.
+ * An queue is empty if it contains no messages waiting.
+ *
+ * @return true if the queue is empty; false otherwise
+ */
+ public boolean isEmpty() {
+ synchronized(eventQueue) {
+ return eventQueue.isEmpty();
+ }
+ }
+
+ public NativeEvent getNextEvent() {
+ synchronized (eventQueue) {
+ if (eventQueue.isEmpty()) {
+ shutdownWatchdog.setNativeQueueEmpty(true);
+ return null;
+ }
+ return eventQueue.remove(0);
+ }
+ }
+
+ protected void addEvent(NativeEvent event) {
+ synchronized (eventQueue) {
+ eventQueue.add(event);
+ shutdownWatchdog.setNativeQueueEmpty(false);
+ }
+ synchronized (eventMonitor) {
+ eventMonitor.notify();
+ }
+ }
+
+ public final Object getEventMonitor() {
+ return eventMonitor;
+ }
+
+ public abstract void awake();
+
+ /**
+ * Gets AWT system window ID.
+ *
+ * @return AWT system window ID
+ */
+ public abstract long getJavaWindow();
+
+ /**
+ * Add NativeEvent to the queue
+ */
+ public abstract void dispatchEvent();
+
+ public abstract void performTask(Task task);
+
+ public abstract void performLater(Task task);
+
+ public final void setShutdownWatchdog(ShutdownWatchdog watchdog) {
+ synchronized (eventQueue) {
+ shutdownWatchdog = watchdog;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEventThread.java b/awt/org/apache/harmony/awt/wtk/NativeEventThread.java
new file mode 100644
index 0000000..d50add4
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEventThread.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+
+/**
+ * NativeEventThread
+ */
+public class NativeEventThread extends Thread {
+
+ public interface Init {
+ WTK init();
+ }
+
+ NativeEventQueue nativeQueue;
+ Init init;
+
+ private WTK wtk;
+
+ public NativeEventThread() {
+ super("AWT-NativeEventThread"); //$NON-NLS-1$
+ setDaemon(true);
+ }
+
+ @Override
+ public void run() {
+ synchronized (this) {
+ try {
+ wtk = init.init();
+ nativeQueue = wtk.getNativeEventQueue();
+ } finally {
+ notifyAll();
+ }
+ }
+
+ runModalLoop();
+ }
+
+ void runModalLoop() {
+ while (nativeQueue.waitEvent()) {
+ nativeQueue.dispatchEvent();
+ }
+ }
+
+ public void start(Init init) {
+ synchronized (this) {
+ this.init = init;
+ super.start();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public WTK getWTK() {
+ return wtk;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeIM.java b/awt/org/apache/harmony/awt/wtk/NativeIM.java
new file mode 100644
index 0000000..1626f4a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeIM.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.im.spi.InputMethod;
+import java.awt.im.spi.InputMethodContext;
+import java.awt.im.spi.InputMethodDescriptor;
+import java.lang.Character.Subset;
+import java.util.Locale;
+
+/**
+ * A cross-platform interface for native input
+ * method sub-system functionality.
+ */
+public abstract class NativeIM implements InputMethod, InputMethodDescriptor {
+ protected InputMethodContext imc;
+
+ public void activate() {
+
+ }
+
+ public void deactivate(boolean isTemporary) {
+
+ }
+
+ public void dispatchEvent(AWTEvent event) {
+
+ }
+
+ public void dispose() {
+
+ }
+
+ public void endComposition() {
+
+ }
+
+ public Object getControlObject() {
+ return null;
+ }
+
+ public Locale getLocale() {
+ return null;
+ }
+
+ public void hideWindows() {
+
+ }
+
+ public boolean isCompositionEnabled() {
+ return false;
+ }
+
+ public void notifyClientWindowChange(Rectangle bounds) {
+
+ }
+
+ public void reconvert() {
+
+ }
+
+ public void removeNotify() {
+
+ }
+
+ public void setCharacterSubsets(Subset[] subsets) {
+
+ }
+
+ public void setCompositionEnabled(boolean enable) {
+
+ }
+
+ public void setInputMethodContext(InputMethodContext context) {
+ imc = context;
+ }
+
+ public boolean setLocale(Locale locale) {
+ return false;
+ }
+
+ public Locale[] getAvailableLocales() throws AWTException {
+ return new Locale[]{Locale.getDefault(), Locale.ENGLISH};
+ //return new Locale[]{Locale.getDefault(), Locale.US};
+ }
+
+ public InputMethod createInputMethod() throws Exception {
+ return this;
+ }
+
+ public String getInputMethodDisplayName(Locale inputLocale,
+ Locale displayLanguage) {
+ return "System input methods"; //$NON-NLS-1$
+ }
+
+ public Image getInputMethodIcon(Locale inputLocale) {
+ return null;
+ }
+
+ public boolean hasDynamicLocaleList() {
+ return false;
+ }
+
+ public abstract void disableIME();
+
+// public abstract void disableIME(long id);
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java b/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
new file mode 100644
index 0000000..0696975
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Point;
+
+/**
+ * The interface provides access to platform dependent functionality
+ * for classes java.awt.PointerInfo & java.awt.MouseInfo.
+ */
+public interface NativeMouseInfo {
+
+ /**
+ * Returns the Point that represents
+ * the coordinates of the pointer on the screen.
+ */
+ Point getLocation();
+
+ /**
+ * Returns the number of buttons on the mouse.
+ * If no mouse is installed returns -1.
+ */
+ int getNumberOfButtons();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeRobot.java b/awt/org/apache/harmony/awt/wtk/NativeRobot.java
new file mode 100644
index 0000000..0b354d0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeRobot.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * A cross-platform interface for java.awt.Robot implementation
+ */
+public interface NativeRobot {
+
+ /**
+ * @see java.awt.Robot#createScreenCapture(Rectangle)
+ * @param screenRect rectangle to capture in screen coordinates
+ * @return the captured image or null if
+ * capture failed.
+ */
+ BufferedImage createScreenCapture(Rectangle screenRect);
+
+ /**
+ * @see java.awt.Robot#getPixelColor(int, int)
+ */
+ Color getPixel(int x, int y);
+
+ /**
+ * Generate a native system keyboard input event.
+ * @param keycode A Java virtual key code
+ * @param press A key is pressed if true, released otherwise
+ * @see java.awt.Robot#keyPress(int)
+ * @throws IllegalArgumentException if keycode is invalid in the native system
+ */
+ void keyEvent(int keycode, boolean press);
+
+ /**
+ * Generate a native system mouse button(s) press or release event.
+ * @param buttons A mask of Java mouse button flags
+ * @param press buttons are pressed if true, released otherwise
+ * @see java.awt.Robot#mousePress(int)
+ */
+ void mouseButton(int buttons, boolean press);
+
+ /**
+ * Generate a native system mouse motion event.
+ *
+ * @see java.awt.Robot#mouseMove(int, int)
+ */
+ void mouseMove(int x, int y);
+
+ /**
+ * Generate a native system mouse wheel event.
+ *
+ * @see java.awt.Robot#mouseWheel(int)
+ */
+ void mouseWheel(int wheelAmt);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeWindow.java b/awt/org/apache/harmony/awt/wtk/NativeWindow.java
new file mode 100644
index 0000000..73fd6c0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeWindow.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+/**
+ * Provides cross-platform way to manipulate native window.
+ *
+ * Results of methods are reported through native messages.
+ */
+public interface NativeWindow {
+ /**
+ * Returns system id of the associated window
+ * @return HWND on Windows, xwindow on X
+ */
+ long getId();
+
+ /**
+ * Shows/hides window
+ * @param v - new visibility
+ */
+ void setVisible(boolean v);
+
+ /**
+ * Means only size should be changed
+ */
+ static final int BOUNDS_NOMOVE = 1;
+
+ /**
+ * Means only position should be changed
+ */
+ static final int BOUNDS_NOSIZE = 2;
+
+ /**
+ * Tries to set desired window bounds. It's not gurantied the
+ * property will have the desired value. The value change
+ * should be reported by system event (as for other properties).
+ *
+ * <p/> If child, position is relative to parent window.
+ * @param x - desired x
+ * @param y - desired y
+ * @param w - desired width
+ * @param h - desired height
+ * @param boundsMask - bitwise OR of BOUNDS_* constants.
+ * Governs the new bounds interpretation.
+ */
+ void setBounds(int x, int y, int w, int h, int boundsMask);
+
+ /**
+ * Returns last notified window bounds. This means the last bounds
+ * reported by system event.
+ *
+ * <p/> If child, position is relative to parent window.
+ * @return last notified window bounds
+ */
+ Rectangle getBounds();
+
+ /**
+ * Returns last notified insets. This means the last insets
+ * reported by system event. Insets are margins around client area
+ * ocupied by system provided decor, ususally border and titlebar.
+ * @return last notified insets
+ */
+ Insets getInsets();
+
+ /**
+ * Enables/disables processing of input (key, mouse) event
+ * by window. If disabled input events are ignored.
+ * @param value - if enabled
+ */
+ void setEnabled(boolean value);
+
+ /**
+ * Sets the "focusable" window state.
+ * @param value - if true makes window focusable
+ */
+ void setFocusable(boolean value);
+
+ /**
+ *
+ * @return current focusable window state
+ */
+ boolean isFocusable();
+
+ /**
+ * Tries to set application input focus to the window or clear
+ * current focus from focused window.
+ *
+ * <p/> For toplevel windows it's not gurantied focus will land in
+ * desired window even if function returns true. Focus traversal should be tracked
+ * by processing system events.
+ *
+ * @param focus - if true sets focus, else clears focus
+ * @return if success
+ */
+ boolean setFocus(boolean focus);
+
+ /**
+ * Destroys the asscoiated window.
+ * Attempts to use it thereafter can result in
+ * unpredictable bechavior.
+ */
+ void dispose();
+
+ /**
+ * Changes window Z-order to place this window under, If w is null
+ * places places this window on the top. Z-order is per parent.
+ * Toplevels a children of desktop in terms of Z-order.
+ * @param w - window to place under.
+ */
+ void placeAfter(NativeWindow w);
+
+ /**
+ * Places window on top of Z-order
+ */
+ void toFront();
+
+ /**
+ * Places window on bottom of Z-order
+ */
+ void toBack();
+
+ /**
+ * Makes the window resizable/not resizable by user
+ * @param value - if resizable
+ */
+ void setResizable(boolean value);
+
+ /**
+ * Sets the window caption
+ * @param title - caption text
+ */
+ void setTitle(String title);
+
+ /**
+ * Activate the mouse event capturing
+ */
+ void grabMouse();
+
+ /**
+ * Deactivate mouse event capturing
+ */
+ void ungrabMouse();
+
+ /**
+ * Set extended state for top-level window.
+ *
+ * @param state - new state, bitmask of ICONIFIED, MAXIMIZED_BOTH, etc.
+ */
+ void setState(int state);
+
+ /**
+ * Set the image to be displayed in the minimized icon for
+ * top-level [decorated] window.
+ * @param image the icon image to be displayed
+ */
+ void setIconImage(Image image);
+
+ /**
+ * Makes window top-most if value is true,
+ * non-topmost(normal) otherwise.
+ */
+ void setAlwaysOnTop(boolean value);
+
+ /**
+ * Set desired [top-level] window bounds when being in maximized state.
+ * Fields set to Integer.MAX_VALUE are ignored[system-supplied values are
+ * used instead]
+ */
+ void setMaximizedBounds(Rectangle bounds);
+
+ /**
+ * Get absolute position on the screen
+ */
+ Point getScreenPos();
+
+ /**
+ * Set a window "packed" flag:
+ * the flag indicates that if insets change
+ * client area shouldn't be resized, but frame
+ * must be resized instead
+ */
+ void setPacked(boolean packed);
+
+ /**
+ * Make window an "input method window" by setting
+ * special window style, e. g. small title bar, no
+ * close, minimize/maximize buttons. For internal
+ * use by input method framework.
+ *
+ */
+ void setIMStyle();
+
+ MultiRectArea getObscuredRegion(Rectangle part);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/ShutdownThread.java b/awt/org/apache/harmony/awt/wtk/ShutdownThread.java
new file mode 100644
index 0000000..701eb46
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/ShutdownThread.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public final class ShutdownThread extends Thread {
+
+ public static final class Watchdog {
+ }
+
+ public ShutdownThread() {
+ setName("AWT-Shutdown"); //$NON-NLS-1$
+ setDaemon(false);
+ }
+
+ private boolean shouldStop = false;
+
+ @Override
+ public void run() {
+ synchronized (this) {
+ notifyAll(); // synchronize the startup
+
+ while (true) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+
+ if (shouldStop) {
+ notifyAll(); // synchronize the shutdown
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void start() {
+ synchronized (this) {
+ super.start();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // awt.26=Shutdown thread was interrupted while starting
+ throw new RuntimeException(
+ Messages.getString("awt.26")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public void shutdown() {
+ synchronized (this) {
+ shouldStop = true;
+ notifyAll();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // awt.27=Shutdown thread was interrupted while stopping
+ throw new RuntimeException(
+ Messages.getString("awt.27")); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java b/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
new file mode 100644
index 0000000..6efa519
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * Shutdown Watchdog
+ */
+public final class ShutdownWatchdog {
+
+ private boolean nativeQueueEmpty = true;
+ private boolean awtQueueEmpty = true;
+ private boolean windowListEmpty = true;
+
+ private boolean forcedShutdown = false;
+
+ private ShutdownThread thread;
+
+ public synchronized void setNativeQueueEmpty(boolean empty) {
+ nativeQueueEmpty = empty;
+ checkShutdown();
+ }
+
+ public synchronized void setAwtQueueEmpty(boolean empty) {
+ awtQueueEmpty = empty;
+ checkShutdown();
+ }
+
+ public synchronized void setWindowListEmpty(boolean empty) {
+ windowListEmpty = empty;
+ checkShutdown();
+ }
+
+ public synchronized void forceShutdown() {
+ forcedShutdown = true;
+ shutdown();
+ }
+
+ public synchronized void start() {
+ keepAlive();
+ }
+
+ private void checkShutdown() {
+ if (canShutdown()) {
+ shutdown();
+ } else {
+ keepAlive();
+ }
+ }
+
+ private boolean canShutdown() {
+ return (nativeQueueEmpty && awtQueueEmpty && windowListEmpty) ||
+ forcedShutdown;
+ }
+
+ private void keepAlive() {
+ if (thread == null) {
+ thread = new ShutdownThread();
+ thread.start();
+ }
+ }
+
+ private void shutdown() {
+ if (thread != null) {
+ thread.shutdown();
+ thread = null;
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/Synchronizer.java b/awt/org/apache/harmony/awt/wtk/Synchronizer.java
new file mode 100644
index 0000000..3eeaa0b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/Synchronizer.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.util.Hashtable;
+import java.util.LinkedList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Class synchronizer is to protect AWT state integrity in multithreading environment.
+ * It is supposed to have a child class per native platform.
+ * The only instance is created on the first use of one of the core AWT classes.
+ * Registers WTK on the dispatch thread startup.
+ * It is just a special kind of mutex.
+ *
+ */
+
+public class Synchronizer {
+ //TODO: think about java.util.concurrent use for faster blocking/awaking operations
+ //TODO: think about all synchronized methods. Is there need to synchronize everything?
+
+ /**
+ * This field holds the counter of lock operation.
+ * To free synchronizer unlock method must be called $acquestCounter times.
+ * Equals to 0 when synchronizer is free.
+ */
+ protected int acquestCounter;
+
+ /**
+ * This field holds the owner of synchronizer.
+ * Owner of synchronizer is a last thread that successfully locked synchronizer and
+ * still havn't freed it. Equals to null when synchronizer is free.
+ */
+ protected Thread owner;
+
+ /**
+ * This field holds the wait queue.
+ * Wait queue is a queue where thread wait for synchronizer access.
+ * Empty when synchronizer is free.
+ */
+ protected final LinkedList<Thread> waitQueue = new LinkedList<Thread>();
+
+ /**
+ * The event dispatch thread
+ */
+ protected Thread dispatchThread;
+
+ private final Hashtable<Thread, Integer> storedStates = new Hashtable<Thread, Integer>();
+
+ /**
+ * Acquire the lock for this synchronizer. Nested lock is supported.
+ * If the mutex is already locked by another thread, the current thread will be put
+ * into wait queue until the lock becomes available.
+ * All user threads are served in FIFO order. Dispatch thread has higher priority.
+ * Supposed to be used in Toolkit.lockAWT() only.
+ */
+ public void lock() {
+ synchronized (this) {
+ Thread curThread = Thread.currentThread();
+
+ if (acquestCounter == 0) {
+ acquestCounter = 1;
+ owner = curThread;
+ } else {
+ if (owner == curThread) {
+ acquestCounter++;
+ } else {
+ if (curThread == dispatchThread) {
+ waitQueue.addFirst(curThread);
+ } else {
+ waitQueue.addLast(curThread);
+ }
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ if (owner != curThread) {
+ waitQueue.remove(curThread);
+ // awt.1F=Waiting for resource access thread interrupted not from unlock method.
+ throw new RuntimeException(Messages
+ .getString("awt.1F")); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Release the lock for this synchronizer.
+ * If wait queue is not empty the first waiting thread acquires the lock.
+ * Supposed to be used in Toolkit.unlockAWT() only.
+ */
+ public void unlock() {
+ synchronized (this) {
+ if (acquestCounter == 0) {
+ // awt.20=Can't unlock not locked resource.
+ throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$
+ }
+ if (owner != Thread.currentThread()) {
+ // awt.21=Not owner can't unlock resource.
+ throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$
+ }
+
+ acquestCounter--;
+ if (acquestCounter == 0) {
+ if (waitQueue.size() > 0) {
+ acquestCounter = 1;
+ owner = waitQueue.removeFirst();
+ owner.interrupt();
+ } else {
+ owner = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Stores state of this synchronizer and frees it.
+ * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
+ * lockAndRestoreState().
+ * Do not call it directly.
+ */
+ public void storeStateAndFree() {
+ synchronized (this) {
+ Thread curThread = Thread.currentThread();
+
+ if (owner != curThread) {
+ // awt.22=Not owner can't free resource.
+ throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$
+ }
+ if (storedStates.containsKey(curThread)) {
+ // awt.23=One thread can't store state several times in a row.
+ throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$
+ }
+
+ storedStates.put(curThread, new Integer(acquestCounter));
+ acquestCounter = 1;
+ unlock();
+ }
+ }
+
+ /**
+ * Locks this synchronizer and restores it's state.
+ * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
+ * storeStateAndFree().
+ * Do not call it directly.
+ */
+ public void lockAndRestoreState() {
+ synchronized (this) {
+ Thread curThread = Thread.currentThread();
+
+ if (owner == curThread) {
+ // awt.24=Owner can't overwrite resource state. Lock operations may be lost.
+ throw new RuntimeException(
+ Messages.getString("awt.24")); //$NON-NLS-1$
+ }
+ if (!storedStates.containsKey(curThread)) {
+ // awt.25=No state stored for current thread.
+ throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$
+ }
+
+ lock();
+ acquestCounter = storedStates.get(curThread).intValue();
+ storedStates.remove(curThread);
+ }
+ }
+
+ /**
+ * Sets references to WTK and event dispatch thread.
+ * Called on toolkit startup.
+ *
+ * @param wtk - reference to WTK instance
+ * @param dispatchThread - reference to event dispatch thread
+ */
+ public void setEnvironment(WTK wtk, Thread dispatchThread) {
+ synchronized (this) {
+ this.dispatchThread = dispatchThread;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/SystemProperties.java b/awt/org/apache/harmony/awt/wtk/SystemProperties.java
new file mode 100644
index 0000000..6b59f0e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/SystemProperties.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Font;
+import java.awt.font.TextAttribute;
+import java.awt.im.InputMethodHighlight;
+import java.util.Map;
+
+/**
+ * NativeProperties
+ */
+
+public interface SystemProperties {
+
+ /**
+ * Get current value of a system color
+ * @param index - one of java.awt.SystemColor constants
+ * @return ARGB value of requested system color
+ */
+ int getSystemColorARGB(int index);
+
+ /**
+ * Get default font for GUI elements such as menus and buttons
+ * @return the font object
+ */
+ Font getDefaultFont();
+
+ /**
+ * Fill the given Map with system properties
+ */
+ void init(Map<String, ?> desktopProperties);
+
+ /**
+ * Fills the given map with system-dependent visual text
+ * attributes for the abstract description
+ * of the given input method highlight
+ * @see java.awt.Toolkit.mapInputMethodHighlight()
+ */
+ void mapInputMethodHighlight(InputMethodHighlight highlight, Map<TextAttribute, ?> map);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/WTK.java b/awt/org/apache/harmony/awt/wtk/WTK.java
new file mode 100644
index 0000000..4162fbd
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/WTK.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.GraphicsDevice;
+
+
+public abstract class WTK {
+
+ public abstract GraphicsFactory getGraphicsFactory();
+ public abstract NativeEventQueue getNativeEventQueue();
+ public abstract WindowFactory getWindowFactory();
+
+ /**
+ * Returns platform specific implementation of the interface
+ * org.apache.harmony.awt.wtk.CursorFactory.
+ * @return implementation of CursorFactory
+ */
+ public abstract CursorFactory getCursorFactory();
+
+ /**
+ * Returns platform specific implementation of the interface
+ * org.apache.harmony.awt.wtk.NativeMouseInfo.
+ * @return implementation of NativeMouseInfo
+ */
+ public abstract NativeMouseInfo getNativeMouseInfo();
+
+ public abstract SystemProperties getSystemProperties();
+
+ /**
+ * Returns platform specific implementation of the interface
+ * org.apache.harmony.awt.wtk.NativeRobot.
+ * @return implementation of NativeRobot
+ */
+ public abstract NativeRobot getNativeRobot(GraphicsDevice screen);
+
+ /**
+ * Returns platform specific implementation of the abstract
+ * class org.apache.harmony.awt.wtk.NativeIM.
+ * @return implementation of NativeIM
+ */
+ public abstract NativeIM getNativeIM();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/WindowFactory.java b/awt/org/apache/harmony/awt/wtk/WindowFactory.java
new file mode 100644
index 0000000..23604da
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/WindowFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+/**
+ * Provides factory for NativeWindow
+ */
+public interface WindowFactory {
+ /**
+ * Creates and returns NativeWindow with desired
+ * creation params
+ *
+ * @param p - initial window properties
+ * @return created window
+ */
+ NativeWindow createWindow(CreationParams p);
+ /**
+ * Create NativeWindow instance connected to existing native resource
+ * @param nativeWindowId - id of existing window
+ * @return created NativeWindow instance
+ */
+ NativeWindow attachWindow(long nativeWindowId);
+ /**
+ * Returns NativeWindow instance if created by this instance of
+ * WindowFactory, otherwise null
+ *
+ * @param id - HWND on Windows xwindow on X
+ * @return NativeWindow or null if unknown
+ */
+ NativeWindow getWindowById(long id);
+ /**
+ * Returns NativeWindow instance of the top-level window
+ * that contains a specified point and was
+ * created by this instance of WindowFactory
+ * @param p - Point to check
+ * @return NativeWindow or null if the point is
+ * not within a window created by this WindowFactory
+ */
+ NativeWindow getWindowFromPoint(Point p);
+
+ /**
+ * Returns whether native system supports the state for windows.
+ * This method tells whether the UI concept of, say, maximization or iconification is supported.
+ * It will always return false for "compound" states like Frame.ICONIFIED|Frame.MAXIMIZED_VERT.
+ * In other words, the rule of thumb is that only queries with a single frame state
+ * constant as an argument are meaningful.
+ *
+ * @param state - one of named frame state constants.
+ * @return true is this frame state is supported by this Toolkit implementation, false otherwise.
+ */
+ boolean isWindowStateSupported(int state);
+
+ /**
+ * @see org.apache.harmony.awt.ComponentInternals
+ */
+ void setCaretPosition(int x, int y);
+
+ /**
+ * Request size of arbitrary native window
+ * @param id - window ID
+ * @return window size
+ */
+ Dimension getWindowSizeById(long id);
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/beans/internal/nls/Messages.java b/awt/org/apache/harmony/beans/internal/nls/Messages.java
new file mode 100644
index 0000000..727c757
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/Messages.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.beans.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.kernel.vm.VM;
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.beans.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ private static final String sResource =
+ "org.apache.harmony.beans.internal.nls.messages"; //$NON-NLS-1$
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(sResource, msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(sResource, msg, args);
+ }
+}
diff --git a/awt/org/apache/harmony/beans/internal/nls/messages.properties b/awt/org/apache/harmony/beans/internal/nls/messages.properties
new file mode 100644
index 0000000..72b1c8c
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/messages.properties
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+beans.00=no getter for {0} property
+beans.01=no property for name {0} is found
+beans.02=in DefaultPersistenceDelegate.mutatesTo() {0} : {1}
+beans.03=Target Bean class is null
+beans.04=bad property name
+beans.05=Modifier for setter method should be public.
+beans.06=Number of parameters in setter method is not equal to 1.
+beans.07=Parameter type in setter method does not corresponds to predefined.
+beans.08=Number of parameters in getter method is not equal to 0.
+beans.09=Parameter type in getter method does not corresponds to predefined.
+beans.0A=Modifier for getter method should be public.
+beans.0B=Exception in command execution
+beans.0C=source is null
+beans.0D=Error in expression: {0}
+beans.0E=Changes are null
+beans.0F=The new BeanContext can not be set
+beans.10=no node is found for statement with target = {0}
+beans.11=no getter for property {0} found
+beans.12=cannot access property {0} getter
+beans.13=no setter for property {0} found
+beans.14=Exception while finding property descriptor
+beans.15=The listener is null
+beans.16=The provider is null
+beans.17=The child is null
+beans.18=The requestor is null
+beans.19=The service class is null
+beans.1A=The service selector is null
+beans.1B=The service is null
+beans.1C=The event is null
+beans.1D=bean is null
+beans.1E=Illegal class name: {0}
+beans.1F=Method not found: get{0}
+beans.20=Method not found: set{0}
+beans.21=Modifier for indexed getter method should be public.
+beans.22=Number of parameters in getter method is not equal to 1.
+beans.23=Parameter in indexed getter method is not of integer type.
+beans.24=Parameter type in indexed getter method does not correspond to predefined.
+beans.25=Modifier for indexed setter method should be public.
+beans.26=Number of parameters in indexed setter method is not equal to 2.
+beans.27=First parameter type in indexed setter method should be int.
+beans.28=Second parameter type in indexed setter method does not corresponds to predefined.
+beans.29=Membership listener is null
+beans.2A=Target child can not be null
+beans.2B=Resource name can not be null
+beans.2C=The child can not be null
+beans.2D=Invalid resource
+beans.2E=PropertyVetoException was thrown while removing a child: {0}; Original error message:{1}
+beans.2F=Target child is null
+beans.30=PropertyVetoException was thrown while adding a child: {0}; Original error message:{1}
+beans.31=No valid method {0} for {1} found.
+beans.32=Cannot acquire event type from {0} listener.
+beans.33={0} does not return <void>
+beans.34={0} should have a single input parameter
+beans.35=Single parameter does not match to {0} class
+beans.36=No input params are allowed for getListenerMethod
+beans.37=Return type of getListenerMethod is not an array of listeners
+beans.38=Add and remove methods are not available
+beans.39=Cannot generate event set descriptor for name {0}.
+beans.3A=Event type with name {0} is not found.
+beans.3B=skipping expression {0}...
+beans.3C=Unknown method name for array
+beans.3D=First parameter in array getter(setter) is not of Integer type
+beans.3E=Illegal number of arguments in array getter
+beans.3F=Illegal number of arguments in array setter
+beans.40=No constructor for class {0} found
+beans.41=No method with name {0} is found
+beans.42=target is not generated: classname {0} is not found
+beans.43=Cannot convert {0} to char
+beans.44=for property {0} no getter(setter) is found
+beans.45=method name is not generated: error in getMethodName()
+beans.46=Not a valid child
+beans.47=Unable to instantiate property editor
+beans.48=Property editor is not assignable from the PropertyEditor interface
+beans.49=Child cannot implement both BeanContextChild and BeanContextProxy
+beans.4A=newInstance is null
+beans.4B=type is null
+beans.4C=encoder is null
+beans.4D=Invalid method call
+beans.4E=stopClass is not ancestor of beanClass
+beans.4F=search path is null
+beans.50=not an indexed property
+beans.51=Listener method {0} should have parameter of type {1}
+beans.52=listenerMethodName(s) is null
+beans.53=eventSetName is null
+beans.54=listenerType is null
+beans.55=Method is null
diff --git a/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
new file mode 100644
index 0000000..498e1bb
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.x.imageio.internal.nls;
+
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.x.imageio.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ private static final String sResource =
+ "org.apache.harmony.x.imageio.internal.nls.messages"; //$NON-NLS-1$
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(sResource, msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(sResource, msg, args);
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties b/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
new file mode 100644
index 0000000..8a49dd8
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+imageio.1=Wrong bitDepth-numBands composition \ No newline at end of file
diff --git a/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java b/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
new file mode 100644
index 0000000..caeefdd5
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.metadata;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.imageio.metadata.IIOMetadataFormat;
+import javax.imageio.metadata.IIOMetadataFormatImpl;
+
+public class IIOMetadataUtils {
+ private IIOMetadataUtils() {}
+
+ public static IIOMetadataFormat instantiateMetadataFormat(
+ String formatName, boolean standardFormatSupported,
+ String nativeMetadataFormatName, String nativeMetadataFormatClassName,
+ String [] extraMetadataFormatNames, String [] extraMetadataFormatClassNames
+ ) {
+ if (formatName == null) {
+ throw new IllegalArgumentException("formatName == null!");
+ }
+ if (formatName.equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
+ if (standardFormatSupported) {
+ return IIOMetadataFormatImpl.getStandardFormatInstance();
+ }
+ }
+
+ String className = null;
+
+ if (formatName.equals(nativeMetadataFormatName)) {
+ className = nativeMetadataFormatClassName;
+ } else if (extraMetadataFormatNames != null) {
+ for (int i = 0; i < extraMetadataFormatNames.length; i++) {
+ if (formatName.equals(extraMetadataFormatNames[i])) {
+ className = extraMetadataFormatClassNames[i];
+ break;
+ }
+ }
+ }
+
+ if (className == null) {
+ throw new IllegalArgumentException("Unsupported format name");
+ }
+
+ // Get the context class loader and try to use it first
+ ClassLoader contextClassloader = AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+
+ Class cls;
+
+ try {
+ cls = Class.forName(className, true, contextClassloader);
+ } catch (ClassNotFoundException e) {
+ try {
+ // Use current class loader
+ cls = Class.forName(className);
+ } catch (ClassNotFoundException e1) {
+ throw new IllegalStateException ("Can't obtain format");
+ }
+ }
+
+ try {
+ //???AWT:
+ //Method getInstance = cls.getMethod("getInstance");
+ //return (IIOMetadataFormat) getInstance.invoke(null);
+ return null;
+ } catch (Exception e) {
+ IllegalStateException e1 = new IllegalStateException("Can't obtain format");
+ e1.initCause(e); // Add some details to the message
+ throw e1;
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
new file mode 100644
index 0000000..051f906
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This allows usage of the java2d jpegdecoder with ImageInputStream in
+ * the JPEGImageReader. Temporary, only to make JPEGImageReader#read(..)
+ * working.
+ *
+ */
+public class IISDecodingImageSource extends DecodingImageSource {
+
+ private final InputStream is;
+
+ public IISDecodingImageSource(ImageInputStream iis) {
+ is = new IISToInputStreamWrapper(iis);
+ }
+
+ @Override
+ protected boolean checkConnection() {
+ return true;
+ }
+
+ @Override
+ protected InputStream getInputStream() {
+ return is;
+ }
+
+ static class IISToInputStreamWrapper extends InputStream {
+
+ private ImageInputStream input;
+
+ public IISToInputStreamWrapper(ImageInputStream input) {
+ this.input=input;
+ }
+
+ @Override
+ public int read() throws IOException {
+ return input.read();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return input.read(b);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return input.read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return input.skipBytes(n);
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true; // This is orig
+
+ // ???AWT: FIXME
+ // This is an error in Harmony. Not all input streams
+ // have mark support and it is not ok to just return true.
+ // There should be an input.markSupported(). However, if
+ // this call returns false, nothing works anymore.
+
+ // The backside is that BitmapFactory uses a call to markSupport()
+ // to find out if it needs to warp the stream in a
+ // BufferedInputStream to get mark support, and this fails!
+
+ // Currently, the hack is in BitmapFactory, where we always
+ // wrap the stream in a BufferedInputStream.
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ input.mark();
+ }
+
+ @Override
+ public void reset() throws IOException {
+ input.reset();
+ }
+
+ @Override
+ public void close() throws IOException {
+ input.close();
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
new file mode 100644
index 0000000..067a825
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+public class JPEGConsts {
+
+ private JPEGConsts() {}
+
+ public static final int SOI = 0xD8;
+
+ //-- IJG (Independed JPEG Group) color spaces
+ public static final int JCS_UNKNOW = 0;
+ public static final int JCS_GRAYSCALE = 1;
+ public static final int JCS_RGB = 2;
+ public static final int JCS_YCbCr = 3;
+ public static final int JCS_CMYK = 4;
+ public static final int JCS_YCC = 5;
+ public static final int JCS_RGBA = 6;
+ public static final int JCS_YCbCrA = 7;
+ public static final int JCS_YCCA = 10;
+ public static final int JCS_YCCK = 11;
+
+ public static int[][] BAND_OFFSETS = {{}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}};
+
+ public static final float DEFAULT_JPEG_COMPRESSION_QUALITY = 0.75f;
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
new file mode 100644
index 0000000..110ed23
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.4 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+
+import javax.imageio.ImageReader;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageReaderSpi;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+/**
+ * This implementation uses org.apache.harmony.awt.gl.image.JpegDecoder to read
+ * an image. The only implemented method is read(..);
+ *
+ * TODO: Implements generic decoder to be used by javad2 and imageio
+ *
+ * @see org.apache.harmony.awt.gl.image.JpegDecoder
+ * @see org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource
+ */
+public class JPEGImageReader extends ImageReader {
+
+ ImageInputStream iis;
+
+ public JPEGImageReader(ImageReaderSpi imageReaderSpi) {
+ super(imageReaderSpi);
+ }
+
+ @Override
+ public int getHeight(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public int getWidth(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public int getNumImages(boolean b) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public Iterator<ImageTypeSpecifier> getImageTypes(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getStreamMetadata() throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getImageMetadata(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException {
+ if (iis == null) {
+ throw new IllegalArgumentException("input stream == null");
+ }
+
+ DecodingImageSource source = new IISDecodingImageSource(iis);
+ OffscreenImage image = new OffscreenImage(source);
+ source.addConsumer(image);
+ source.load();
+ // The interrupted flag should be cleared because ImageDecoder interrupts
+ // current thread while decoding. The same technique is used in
+ // ImageLoader#run(). Another solution can be to create
+ // a separate decoding thread. However, decoder keeps its own pool
+ // of threads so creating a new thread will be just a waste of resources.
+ Thread.interrupted();
+ return image.getBufferedImage();
+ }
+
+ @Override
+ public BufferedImage read(int i) throws IOException {
+ return read(i, null);
+ }
+
+ @Override
+ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+ super.setInput(input, seekForwardOnly, ignoreMetadata);
+ iis = (ImageInputStream) input;
+ }
+
+ @Override
+ public ImageReadParam getDefaultReadParam() {
+ return new JPEGImageReadParam();
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
new file mode 100644
index 0000000..c719ce7
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.imageio.ImageReader;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.stream.ImageInputStream;
+
+public class JPEGImageReaderSpi extends ImageReaderSpi {
+
+ public JPEGImageReaderSpi() {
+ super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+ JPEGSpiConsts.names, JPEGSpiConsts.suffixes,
+ JPEGSpiConsts.MIMETypes, JPEGSpiConsts.readerClassName,
+ STANDARD_INPUT_TYPE, JPEGSpiConsts.writerSpiNames,
+ JPEGSpiConsts.supportsStandardStreamMetadataFormat,
+ JPEGSpiConsts.nativeStreamMetadataFormatName,
+ JPEGSpiConsts.nativeStreamMetadataFormatClassName,
+ JPEGSpiConsts.extraStreamMetadataFormatNames,
+ JPEGSpiConsts.extraStreamMetadataFormatClassNames,
+ JPEGSpiConsts.supportsStandardImageMetadataFormat,
+ JPEGSpiConsts.nativeImageMetadataFormatName,
+ JPEGSpiConsts.nativeImageMetadataFormatClassName,
+ JPEGSpiConsts.extraImageMetadataFormatNames,
+ JPEGSpiConsts.extraImageMetadataFormatClassNames);
+ }
+
+
+ @Override
+ public boolean canDecodeInput(Object source) throws IOException {
+ ImageInputStream markable = (ImageInputStream) source;
+ try {
+ markable.mark();
+
+ byte[] signature = new byte[3];
+ markable.seek(0);
+ markable.read(signature, 0, 3);
+ markable.reset();
+
+ if ((signature[0] & 0xFF) == 0xFF &&
+ (signature[1] & 0xFF) == JPEGConsts.SOI &&
+ (signature[2] & 0xFF) == 0xFF) { // JPEG
+ return true;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ @Override
+ public ImageReader createReaderInstance(Object extension) throws IOException {
+ return new JPEGImageReader(this);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "DRL JPEG decoder";
+ }
+
+ @Override
+ public void onRegistration(ServiceRegistry registry, Class<?> category) {
+ // super.onRegistration(registry, category);
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
new file mode 100644
index 0000000..ae3e876
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import com.android.internal.awt.ImageOutputStreamWrapper;
+
+import javax.imageio.ImageWriter;
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.metadata.IIOMetadata;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.awt.image.*;
+import java.awt.*;
+import java.awt.color.ColorSpace;
+
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+public class JPEGImageWriter extends ImageWriter {
+
+ // /* ???AWT: Debugging
+ private static final boolean DEBUG = false;
+ private static Bitmap bm;
+ public static Bitmap getBitmap() {
+ return bm;
+ }
+ private static BufferedImage bufImg;
+ public static BufferedImage getBufImage() {
+ return bufImg;
+ }
+ static private RenderedImage renImg;
+ static public RenderedImage getRenImage() {
+ return renImg;
+ }
+ // */
+
+ private long cinfo;
+ private RenderedImage image;
+ private Raster sourceRaster;
+ private WritableRaster scanRaster;
+ private int srcXOff = 0;
+ private int srcYOff = 0;
+ private int srcWidth;
+ private int srcHeight;
+
+ //-- y step for image subsampling
+ private int deltaY = 1;
+ //-- x step for image subsampling
+ private int deltaX = 1;
+
+ private ImageOutputStream ios;
+
+ public JPEGImageWriter(ImageWriterSpi imageWriterSpi) {
+ super(imageWriterSpi);
+ //???AWT: cinfo = initCompressionObj();
+ cinfo = System.currentTimeMillis();
+ }
+
+ static {
+ //???AWT
+ /*
+ System.loadLibrary("jpegencoder");
+ initWriterIds(ImageOutputStream.class);
+ */
+ }
+
+ @Override
+ public void write(IIOMetadata iioMetadata, IIOImage iioImage, ImageWriteParam param)
+ throws IOException {
+
+ if (ios == null) {
+ throw new IllegalArgumentException("ios == null");
+ }
+ if (iioImage == null) {
+ throw new IllegalArgumentException("Image equals null");
+ }
+
+ RenderedImage img = null;
+ if (!iioImage.hasRaster()) {
+ img = iioImage.getRenderedImage();
+ if (img instanceof BufferedImage) {
+ sourceRaster = ((BufferedImage) img).getRaster();
+ } else {
+ sourceRaster = img.getData();
+ }
+ } else {
+ sourceRaster = iioImage.getRaster();
+ }
+
+ // AWT???: Debugging
+ if (DEBUG) {
+ if( img==null ) {
+ System.out.println("****J: Image is NULL");
+ } else {
+ renImg = img;
+ bufImg = (BufferedImage)img;
+ }
+ }
+
+ int numBands = sourceRaster.getNumBands();
+ int sourceIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getSourceCSType(img);
+
+ srcWidth = sourceRaster.getWidth();
+ srcHeight = sourceRaster.getHeight();
+
+ int destWidth = srcWidth;
+ int destHeight = srcHeight;
+
+ boolean progressive = false;
+
+ if (param != null) {
+ Rectangle reg = param.getSourceRegion();
+ if (reg != null) {
+ srcXOff = reg.x;
+ srcYOff = reg.y;
+
+ srcWidth = reg.width + srcXOff > srcWidth
+ ? srcWidth - srcXOff
+ : reg.width;
+ srcHeight = reg.height + srcYOff > srcHeight
+ ? srcHeight - srcYOff
+ : reg.height;
+ }
+
+ //-- TODO uncomment when JPEGImageWriteParam be implemented
+ //-- Only default progressive mode yet
+ // progressive = param.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT;
+
+ //-- def is 1
+ deltaX = param.getSourceXSubsampling();
+ deltaY = param.getSourceYSubsampling();
+
+ //-- def is 0
+ int offsetX = param.getSubsamplingXOffset();
+ int offsetY = param.getSubsamplingYOffset();
+
+ srcXOff += offsetX;
+ srcYOff += offsetY;
+ srcWidth -= offsetX;
+ srcHeight -= offsetY;
+
+ destWidth = (srcWidth + deltaX - 1) / deltaX;
+ destHeight = (srcHeight + deltaY - 1) / deltaY;
+ }
+
+ //-- default DQTs (see JPEGQTable java doc and JPEG spec K1 & K2 tables)
+ //-- at http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ //-- Only figuring out how to set DQT in IJG library for future metadata
+ //-- support. IJG def tables are the same.
+ //JPEGQTable[] dqt = new JPEGQTable[2];
+// int[][] dqt = null;
+// int[][] dqt = new int[2][];
+// dqt[0] = JPEGQTable.K1Div2Luminance.getTable();
+// dqt[1] = JPEGQTable.K2Div2Chrominance.getTable();
+
+ //???AWT: I think we don't need this amymore
+ /*
+ //-- using default color space
+ //-- TODO: Take destination cs from param or use default if there is no cs
+ int destIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getDestinationCSType(img);
+
+ DataBufferByte dbuffer = new DataBufferByte(numBands * srcWidth);
+
+ scanRaster = Raster.createInterleavedRaster(dbuffer, srcWidth, 1,
+ numBands * srcWidth, numBands, JPEGConsts.BAND_OFFSETS[numBands], null);
+
+ encode(dbuffer.getData(), srcWidth, destWidth, destHeight, deltaX,
+ sourceIJGCs, destIJGCs, numBands, progressive,
+ null, cinfo);
+ */
+
+ SampleModel model = sourceRaster.getSampleModel();
+
+ if (model instanceof SinglePixelPackedSampleModel) {
+ DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer();
+ int[] pixels = ibuf.getData();
+
+ // Create a bitmap with the pixel
+ bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
+
+ // Use Bitmap.compress() to write the image
+ ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios);
+ bm.compress(CompressFormat.JPEG, 100, iosw);
+ } else {
+ // ???AWT: Add support for other color models
+ throw new RuntimeException("Color model not supported yet");
+ }
+
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (cinfo != 0) {
+ //???AWT: dispose(cinfo);
+ cinfo = 0;
+ ios = null;
+ }
+ }
+
+
+ public IIOMetadata getDefaultStreamMetadata(ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ @Override
+ public IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ @Override
+ public IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ @Override
+ public void setOutput(Object output) {
+ super.setOutput(output);
+ ios = (ImageOutputStream) output;
+ //???AWT: setIOS(ios, cinfo);
+ sourceRaster = null;
+ scanRaster = null;
+ srcXOff = 0;
+ srcYOff = 0;
+ srcWidth = 0;
+ srcHeight = 0;
+ deltaY = 1;
+ }
+
+ /**
+ * Frees resources
+ * @param structPointer
+ */
+ //???AWT: private native void dispose(long structPointer);
+
+ /**
+ * Inits methods Ids for native to java callbacks
+ * @param iosClass
+ */
+ //???AWT: private native static void initWriterIds(Class<ImageOutputStream> iosClass);
+
+ /**
+ * Inits compression objects
+ * @return pointer to the native structure
+ */
+ //???AWT: private native long initCompressionObj();
+
+ /**
+ * Sets image output stream in IJG layer
+ * @param stream
+ */
+ //???AWT: private native void setIOS(ImageOutputStream stream, long structPointer);
+
+ /**
+ * Runs encoding process.
+ *
+ * @param data image data buffer to encode
+ * @param srcWidth - source width
+ * @param width - destination width
+ * @param height destination height
+ * @param deltaX - x subsampling step
+ * @param inColorSpace - original color space
+ * @param outColorSpace - destination color space
+ * @param numBands - number of bands
+ * @param cinfo - native handler
+ * @return
+ */
+ //???AWT:
+ /*
+ private native boolean encode(byte[] data, int srcWidth,
+ int width, int height, int deltaX,
+ int inColorSpace, int outColorSpace,
+ int numBands, boolean progressive,
+ int[][] dqt,
+ long cinfo);
+ */
+
+ /**
+ * Callback for getting a next scanline
+ * @param scanline scan line number
+ */
+ @SuppressWarnings("unused")
+ private void getScanLine(int scanline) {
+ //-- TODO: processImageProgress in ImageWriter
+ Raster child = sourceRaster.createChild(srcXOff,
+ srcYOff + scanline * deltaY, srcWidth, 1, 0, 0, null);
+
+ scanRaster.setRect(child);
+ }
+
+ /**
+ * Maps color space types to IJG color spaces
+ * @param image
+ * @return
+ */
+ private int getSourceCSType(RenderedImage image) {
+ int type = JPEGConsts.JCS_UNKNOW;
+ ColorModel cm = image.getColorModel();
+
+ if (null == cm) {
+ return type;
+ }
+
+ if (cm instanceof IndexColorModel) {
+ throw new UnsupportedOperationException("IndexColorModel is not supported yet");
+ }
+
+ boolean hasAlpha = cm.hasAlpha();
+ ColorSpace cs = cm.getColorSpace();
+ switch(cs.getType()) {
+ case ColorSpace.TYPE_GRAY:
+ type = JPEGConsts.JCS_GRAYSCALE;
+ break;
+ case ColorSpace.TYPE_RGB:
+ type = hasAlpha ? JPEGConsts.JCS_RGBA : JPEGConsts.JCS_RGB;
+ break;
+ case ColorSpace.TYPE_YCbCr:
+ type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+ break;
+ case ColorSpace.TYPE_3CLR:
+ type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
+ break;
+ case ColorSpace.TYPE_CMYK:
+ type = JPEGConsts.JCS_CMYK;
+ break;
+ }
+ return type;
+ }
+
+ /**
+ * Returns destination color space.
+ * (YCbCr[A] for RGB)
+ *
+ * @param image
+ * @return
+ */
+ private int getDestinationCSType(RenderedImage image) {
+ int type = JPEGConsts.JCS_UNKNOW;
+ ColorModel cm = image.getColorModel();
+ if (null != cm) {
+ boolean hasAlpha = cm.hasAlpha();
+ ColorSpace cs = cm.getColorSpace();
+
+ switch(cs.getType()) {
+ case ColorSpace.TYPE_GRAY:
+ type = JPEGConsts.JCS_GRAYSCALE;
+ break;
+ case ColorSpace.TYPE_RGB:
+ type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+ break;
+ case ColorSpace.TYPE_YCbCr:
+ type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+ break;
+ case ColorSpace.TYPE_3CLR:
+ type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
+ break;
+ case ColorSpace.TYPE_CMYK:
+ type = JPEGConsts.JCS_CMYK;
+ break;
+ }
+ }
+ return type;
+ }
+
+ public ImageWriteParam getDefaultWriteParam() {
+ return new JPEGImageWriteParam(getLocale());
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
new file mode 100644
index 0000000..b7990e0
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.ImageWriter;
+import javax.imageio.ImageTypeSpecifier;
+import java.io.IOException;
+import java.util.Locale;
+
+public class JPEGImageWriterSpi extends ImageWriterSpi {
+
+ public JPEGImageWriterSpi() {
+ super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+ JPEGSpiConsts.names, JPEGSpiConsts.suffixes, JPEGSpiConsts.MIMETypes,
+ JPEGSpiConsts.writerClassName, STANDARD_OUTPUT_TYPE,
+ JPEGSpiConsts.readerSpiNames, JPEGSpiConsts.supportsStandardStreamMetadataFormat /*TODO: support st. metadata format*/,
+ JPEGSpiConsts.nativeStreamMetadataFormatName, JPEGSpiConsts.nativeStreamMetadataFormatClassName,
+ JPEGSpiConsts.extraStreamMetadataFormatNames, JPEGSpiConsts.extraStreamMetadataFormatClassNames,
+ JPEGSpiConsts.supportsStandardImageMetadataFormat, JPEGSpiConsts.nativeImageMetadataFormatName, JPEGSpiConsts.nativeImageMetadataFormatClassName,
+ JPEGSpiConsts.extraImageMetadataFormatNames, JPEGSpiConsts.extraImageMetadataFormatClassNames);
+ }
+
+ @Override
+ public boolean canEncodeImage(ImageTypeSpecifier imageTypeSpecifier) {
+ return true;
+ }
+
+ @Override
+ public ImageWriter createWriterInstance(Object o) throws IOException {
+ return new JPEGImageWriter(this);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "DRL JPEG Encoder";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
new file mode 100644
index 0000000..c3b4a50
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+public class JPEGSpiConsts {
+ private JPEGSpiConsts() {}
+
+ public static final String vendorName = "Intel Corporation";
+ public static final String version = "0.1 beta";
+
+ static final String readerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReader";
+ static final String writerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriter";
+
+ static final String[] names = {"jpeg", "jpg", "JPEG", "JPG"};
+ static final String[] suffixes = {"jpeg", "jpg"};
+ static final String[] MIMETypes = {"image/jpeg"};
+
+ static final String[] writerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi"};
+ static final String[] readerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi"};
+
+ //-- TODO fill this stuff with correct data
+ static final boolean supportsStandardStreamMetadataFormat = false;
+ static final String nativeStreamMetadataFormatName = null;
+ static final String nativeStreamMetadataFormatClassName = null;
+ static final String[] extraStreamMetadataFormatNames = null;
+ static final String[] extraStreamMetadataFormatClassNames = null;
+ static final boolean supportsStandardImageMetadataFormat = false;
+ static final String nativeImageMetadataFormatName =
+ "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata_1.0";
+ static final String nativeImageMetadataFormatClassName =
+ "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata";
+ static final String[] extraImageMetadataFormatNames = null;
+ static final String[] extraImageMetadataFormatClassNames = null;
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
new file mode 100644
index 0000000..480041c
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.plugins.png;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+import org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource;
+
+import javax.imageio.ImageReader;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageReadParam;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import java.io.IOException;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+public class PNGImageReader extends ImageReader {
+ ImageInputStream iis;
+
+ public PNGImageReader(ImageReaderSpi imageReaderSpi) {
+ super(imageReaderSpi);
+ }
+
+ public int getNumImages(boolean allowSearch) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ public int getWidth(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ public int getHeight(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getStreamMetadata() throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException {
+ if (iis == null) {
+ throw new IllegalArgumentException("input stream == null");
+ }
+
+ DecodingImageSource source = new IISDecodingImageSource(iis);
+ OffscreenImage image = new OffscreenImage(source);
+ source.addConsumer(image);
+ source.load();
+ // The interrupted flag should be cleared because ImageDecoder interrupts
+ // current thread while decoding (due its architecture).
+ Thread.interrupted();
+ return image.getBufferedImage();
+ }
+
+ @Override
+ public BufferedImage read(int i) throws IOException {
+ return read(i, null);
+ }
+
+ @Override
+ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+ super.setInput(input, seekForwardOnly, ignoreMetadata);
+ iis = (ImageInputStream) input;
+ }
+
+ @Override
+ public ImageReadParam getDefaultReadParam() {
+ return new ImageReadParam();
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
new file mode 100644
index 0000000..50f8b10
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.plugins.png;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGSpiConsts;
+
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import java.io.IOException;
+import java.util.Locale;
+
+public class PNGImageReaderSpi extends ImageReaderSpi {
+ static final String PNG_NAMES[] = new String[] {"png", "PNG"};
+ static final String PNG_SUFFIXES[] = new String[] {"png"};
+ static final String PNG_MIME_TYPES[] = new String[] {"image/png"};
+ static final String PNG_READER_CLASS_NAME = "org.apache.harmony.x.imageio.plugins.png.PNGImageReader";
+ static final String PNG_READER_SPI_NAMES[] = {"org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi"};
+
+ public PNGImageReaderSpi() {
+ super(
+ JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+ PNG_NAMES, PNG_SUFFIXES,
+ PNG_MIME_TYPES, PNG_READER_CLASS_NAME,
+ STANDARD_INPUT_TYPE, null,
+ false, null,
+ null, null,
+ null, false,
+ null, null,
+ null, null
+ );
+ }
+
+ @Override
+ public boolean canDecodeInput(Object source) throws IOException {
+ ImageInputStream markable = (ImageInputStream) source;
+ markable.mark();
+
+ byte[] signature = new byte[8];
+ markable.seek(0);
+
+ int nBytes = markable.read(signature, 0, 8);
+ if(nBytes != 8) markable.read(signature, nBytes, 8-nBytes);
+ markable.reset();
+
+ // PNG signature: 137 80 78 71 13 10 26 10
+ return (signature[0] & 0xFF) == 137 &&
+ (signature[1] & 0xFF) == 80 &&
+ (signature[2] & 0xFF) == 78 &&
+ (signature[3] & 0xFF) == 71 &&
+ (signature[4] & 0xFF) == 13 &&
+ (signature[5] & 0xFF) == 10 &&
+ (signature[6] & 0xFF) == 26 &&
+ (signature[7] & 0xFF) == 10;
+ }
+
+ @Override
+ public ImageReader createReaderInstance(Object extension) throws IOException {
+ return new PNGImageReader(this);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "DRL PNG decoder";
+ }
+
+ @Override
+ public void onRegistration(ServiceRegistry registry, Class<?> category) {
+ super.onRegistration(registry, category);
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
new file mode 100644
index 0000000..e2a8d7d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import com.android.internal.awt.ImageOutputStreamWrapper;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.ImageOutputStream;
+
+import org.apache.harmony.x.imageio.internal.nls.Messages;
+
+import org.apache.harmony.luni.util.NotImplementedException;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+
+public class PNGImageWriter extends ImageWriter {
+
+ // /* ???AWT: Debugging
+ private static final boolean DEBUG = false;
+ private static Bitmap bm;
+ public static Bitmap getBitmap() {
+ return bm;
+ }
+ // */
+
+ private static int[][] BAND_OFFSETS = {
+ {}, {
+ 0 }, {
+ 0, 1 }, {
+ 0, 1, 2 }, {
+ 0, 1, 2, 3 } };
+
+ // Each pixel is a grayscale sample.
+ private static final int PNG_COLOR_TYPE_GRAY = 0;
+ // Each pixel is an R,G,B triple.
+ private static final int PNG_COLOR_TYPE_RGB = 2;
+ // Each pixel is a palette index, a PLTE chunk must appear.
+ private static final int PNG_COLOR_TYPE_PLTE = 3;
+ // Each pixel is a grayscale sample, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+ // Each pixel is an R,G,B triple, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+ //???AWT: private static native void initIDs(Class<ImageOutputStream> iosClass);
+
+ static {
+ //???AWT
+ /*
+ System.loadLibrary("pngencoder"); //$NON-NLS-1$
+ initIDs(ImageOutputStream.class);
+ */
+ }
+
+ /*
+ private native int encode(byte[] input, int bytesInBuffer, int bytePixelSize, Object ios, int imageWidth,
+ int imageHeight, int bitDepth, int colorType, int[] palette, int i, boolean b);
+ */
+
+ protected PNGImageWriter(ImageWriterSpi iwSpi) {
+ super(iwSpi);
+ }
+
+ @Override
+ public IIOMetadata convertStreamMetadata(IIOMetadata arg0, ImageWriteParam arg1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IIOMetadata convertImageMetadata(IIOMetadata arg0, ImageTypeSpecifier arg1, ImageWriteParam arg2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier arg0, ImageWriteParam arg1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IIOMetadata getDefaultStreamMetadata(ImageWriteParam arg0) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void write(IIOMetadata streamMetadata, IIOImage iioImage, ImageWriteParam param) throws IOException {
+ if (output == null) {
+ throw new IllegalStateException("Output not been set");
+ }
+ if (iioImage == null) {
+ throw new IllegalArgumentException("Image equals null");
+ }
+ // AWT???: I think this is not needed anymore
+ // if (iioImage.hasRaster() && !canWriteRasters()) {
+ // throw new UnsupportedOperationException("Can't write raster");
+ //}// ImageOutputStreamImpl
+
+ Raster sourceRaster;
+ RenderedImage img = null;
+ if (!iioImage.hasRaster()) {
+ img = iioImage.getRenderedImage();
+ if (img instanceof BufferedImage) {
+ sourceRaster = ((BufferedImage) img).getRaster();
+ } else {
+ sourceRaster = img.getData();
+ }
+ } else {
+ sourceRaster = iioImage.getRaster();
+ }
+
+ SampleModel model = sourceRaster.getSampleModel();
+ int srcWidth = sourceRaster.getWidth();
+ int srcHeight = sourceRaster.getHeight();
+ int numBands = model.getNumBands();
+
+ ColorModel colorModel = img.getColorModel();
+ int pixelSize = colorModel.getPixelSize();
+ int bytePixelSize = pixelSize / 8;
+ int bitDepth = pixelSize / numBands;
+
+ // byte per band
+ int bpb = bitDepth > 8 ? 2 : 1;
+
+ boolean isInterlace = true;
+ if (param instanceof PNGImageWriterParam) {
+ isInterlace = ((PNGImageWriterParam) param).getInterlace();
+ }
+
+ int colorType = PNG_COLOR_TYPE_GRAY;
+ int[] palette = null;
+
+ if (colorModel instanceof IndexColorModel) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+ if (numBands != 1) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+
+ IndexColorModel icm = (IndexColorModel) colorModel;
+ palette = new int[icm.getMapSize()];
+ icm.getRGBs(palette);
+ colorType = PNG_COLOR_TYPE_PLTE;
+ }
+ else if (numBands == 1) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_GRAY;
+ }
+ else if (numBands == 2) {
+ if (bitDepth != 8 && bitDepth != 16) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
+ }
+ else if (numBands == 3) {
+ if (bitDepth != 8 && bitDepth != 16) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_RGB;
+ }
+ else if (numBands == 4) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ //Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_RGBA;
+ }
+
+ /* ???AWT: I think this is not needed anymore
+ int dbufferLenght = bytePixelSize * imageHeight * imageWidth;
+ DataBufferByte dbuffer = new DataBufferByte(dbufferLenght);
+
+ WritableRaster scanRaster = Raster.createInterleavedRaster(dbuffer, imageWidth, imageHeight, bpb * numBands
+ * imageWidth, bpb * numBands, BAND_OFFSETS[numBands], null);
+
+ scanRaster.setRect(((BufferedImage) image).getRaster()// image.getData()
+ .createChild(0, 0, imageWidth, imageHeight, 0, 0, null));
+ */
+
+ if (DEBUG) {
+ System.out.println("**** raster:" + sourceRaster);
+ System.out.println("**** model:" + model);
+ System.out.println("**** type:" + colorType);
+ }
+
+ if (model instanceof SinglePixelPackedSampleModel) {
+ DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer();
+ int[] pixels = ibuf.getData();
+
+ // Create a bitmap with the pixel
+ bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
+
+ // Use Bitmap.compress() to write the image
+ ImageOutputStream ios = (ImageOutputStream) getOutput();
+ ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios);
+ bm.compress(CompressFormat.PNG, 100, iosw);
+ } else {
+ // ???AWT: Add support for other color models
+ throw new RuntimeException("Color model not supported yet");
+ }
+ }
+
+ public ImageWriteParam getDefaultWriteParam() {
+ return new PNGImageWriterParam();
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
new file mode 100644
index 0000000..bf3a000
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import javax.imageio.ImageWriteParam;
+
+public class PNGImageWriterParam extends ImageWriteParam {
+
+ private boolean isInterlace = true;
+
+ public PNGImageWriterParam() {
+ super();
+ }
+
+ public boolean getInterlace() {
+ return isInterlace;
+ }
+
+ public void setInterlace(boolean b) {
+ isInterlace = b;
+ }
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
new file mode 100644
index 0000000..6eed14d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import javax.imageio.spi.ImageWriterSpi;
+
+public class PNGImageWriterSpi extends ImageWriterSpi {
+
+ public PNGImageWriterSpi() {
+ super("Intel Corporation",// vendorName
+ "1.0",// version
+ new String[] {
+ "png", "PNG" },// names
+ new String[] {
+ "png", "PNG" },// suffixes
+ new String[] {
+ "image/png" },// MIMETypes
+ "org.apache.harmony.x.imageio.plugins.png.PNGImageWriter",// writerClassName
+ STANDARD_OUTPUT_TYPE,// outputTypes
+ new String[] {
+ "org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi" },// readerSpiNames
+ false,// supportsStandardStreamMetadataFormat
+ null,// nativeStreamMetadataFormatName
+ null,// nativeStreamMetadataFormatClassName
+ null,// extraStreamMetadataFormatNames
+ null,// extraStreamMetadataFormatClassNames
+ false,// supportsStandardImageMetadataFormat
+ null,// nativeImageMetadataFormatName
+ null,// nativeImageMetadataFormatClassName
+ null,// extraImageMetadataFormatNames
+ null// extraImageMetadataFormatClassNames
+ );
+ }
+
+ @Override
+ public boolean canEncodeImage(ImageTypeSpecifier type) {
+ boolean canEncode = true;
+
+ int numBands = type.getSampleModel().getNumBands();
+
+ ColorModel colorModel = type.getColorModel();
+
+ int bitDepth = colorModel.getPixelSize() / numBands;
+
+ if (colorModel instanceof IndexColorModel) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
+ canEncode = false;
+ }
+ if (numBands != 1) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 1) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 2) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 3) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 4) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+
+ return canEncode;
+ }
+
+ @Override
+ public ImageWriter createWriterInstance(Object arg0) throws IOException {
+ return new PNGImageWriter(this);
+ }
+
+ @Override
+ public String getDescription(Locale arg0) {
+ return "DRL PNG encoder";
+ }
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
new file mode 100644
index 0000000..d4fdd76
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import javax.imageio.stream.FileImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+public class FileIISSpi extends ImageInputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public FileIISSpi() {
+ super(vendor, ver, File.class);
+ }
+
+ @Override
+ public ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+ File cacheDir) throws IOException {
+ if (File.class.isInstance(input)) {
+ return new FileImageInputStream((File) input);
+ }
+ throw new IllegalArgumentException("input is not an instance of java.io.File");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "File IIS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
new file mode 100644
index 0000000..acda6a1
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+public class FileIOSSpi extends ImageOutputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public FileIOSSpi() {
+ super(vendor, ver, File.class);
+ }
+
+ @Override
+ public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+ File cacheDir) throws IOException {
+ if (output instanceof File) {
+ return new FileImageOutputStream((File) output);
+ }
+ throw new IllegalArgumentException("output is not instance of File");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "File IOS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
new file mode 100644
index 0000000..ed2fef0
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.*;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+public class InputStreamIISSpi extends ImageInputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public InputStreamIISSpi() {
+ super(vendor, ver, InputStream.class);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "Output Stream IOS Spi";
+ }
+
+ @Override
+ public boolean canUseCacheFile() {
+ return true;
+ }
+
+ @Override
+ public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) throws IOException {
+ if (input instanceof InputStream) {
+ if (useCache) {
+ return new FileCacheImageInputStream((InputStream) input, cacheDir);
+ } else {
+ return new MemoryCacheImageInputStream((InputStream) input);
+ }
+ }
+ throw new IllegalArgumentException("Output is not an instance of InputStream");
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
new file mode 100644
index 0000000..dd1e88d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileCacheImageOutputStream;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Locale;
+
+public class OutputStreamIOSSpi extends ImageOutputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public OutputStreamIOSSpi() {
+ super(vendor, ver, OutputStream.class);
+ }
+
+ @Override
+ public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) throws IOException {
+ if (output instanceof OutputStream) {
+ if (useCache) {
+ return new FileCacheImageOutputStream((OutputStream) output, cacheDir);
+ } else {
+ return new MemoryCacheImageOutputStream((OutputStream) output);
+ }
+ }
+ throw new IllegalArgumentException("Output is not an instance of OutputStream");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "Output Stream IOS Spi";
+ }
+
+ @Override
+ public boolean canUseCacheFile() {
+ return true;
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
new file mode 100644
index 0000000..f97eb87
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.FileImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Locale;
+
+public class RAFIISSpi extends ImageInputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public RAFIISSpi() {
+ super(vendor, ver, RandomAccessFile.class);
+ }
+
+ @Override
+ public ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+ File cacheDir) throws IOException {
+ if (RandomAccessFile.class.isInstance(input)) {
+ return new FileImageInputStream((RandomAccessFile) input);
+ }
+ throw new IllegalArgumentException(
+ "input is not an instance of java.io.RandomAccessFile");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "RandomAccessFile IIS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
new file mode 100644
index 0000000..a9d3649
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Locale;
+
+public class RAFIOSSpi extends ImageOutputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public RAFIOSSpi() {
+ super(vendor, ver, RandomAccessFile.class);
+ }
+
+ @Override
+ public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+ File cacheDir) throws IOException {
+ if (output instanceof RandomAccessFile) {
+ return new FileImageOutputStream((RandomAccessFile) output);
+ }
+ throw new IllegalArgumentException("output is not instance of java.io.RandomAccessFile");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "RandomAccessFile IOS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java b/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
new file mode 100644
index 0000000..64f7b2a
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.stream;
+
+import java.util.ArrayList;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class RandomAccessMemoryCache {
+ private static final int BLOCK_SHIFT = 9;
+ private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT;
+ private static final int BLOCK_MASK = BLOCK_SIZE - 1;
+
+ private long length;
+
+ private int firstUndisposed = 0;
+
+ private ArrayList<byte[]> blocks = new ArrayList<byte[]>();
+
+ public RandomAccessMemoryCache() {
+ }
+
+ public long length() {
+ return length;
+ }
+
+ public void close() {
+ blocks.clear();
+ length = 0;
+ }
+
+ private void grow(long pos) {
+ int blocksNeeded = (int)(pos >> BLOCK_SHIFT) - blocks.size() + 1;
+ for (int i=0; i < blocksNeeded; i++) {
+ blocks.add(new byte[BLOCK_SIZE]);
+ }
+
+ length = pos + 1;
+ }
+
+ public void putData(int oneByte, long pos) {
+ if (pos >= length) {
+ grow(pos);
+ }
+
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ block[(int)(pos & BLOCK_MASK)] = (byte) oneByte;
+ }
+
+ public void putData(byte[] buffer, int offset, int count, long pos) {
+ if (count > buffer.length - offset || count < 0 || offset < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (count == 0){
+ return;
+ }
+
+ long lastPos = pos + count - 1;
+ if (lastPos >= length) {
+ grow(lastPos);
+ }
+
+ while (count > 0) {
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ int blockOffset = (int)(pos & BLOCK_MASK);
+ int toCopy = Math.min(BLOCK_SIZE - blockOffset, count);
+ System.arraycopy(buffer, offset, block, blockOffset, toCopy);
+ pos += toCopy;
+ count -= toCopy;
+ offset += toCopy;
+ }
+ }
+
+ public int getData(long pos) {
+ if (pos >= length) {
+ return -1;
+ }
+
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ return block[(int)(pos & BLOCK_MASK)] & 0xFF;
+ }
+
+ public int getData(byte[] buffer, int offset, int count, long pos) {
+ if (count > buffer.length - offset || count < 0 || offset < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (count == 0) {
+ return 0;
+ }
+ if (pos >= length) {
+ return -1;
+ }
+
+ if (count + pos > length) {
+ count = (int) (length - pos);
+ }
+
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ int nbytes = Math.min(count, BLOCK_SIZE - (int)(pos & BLOCK_MASK));
+ System.arraycopy(block, (int)(pos & BLOCK_MASK), buffer, offset, nbytes);
+
+ return nbytes;
+ }
+ /*
+ public void seek(long pos) throws IOException {
+ if (pos < 0) {
+ throw new IOException("seek position is negative");
+ }
+ this.pos = pos;
+ }
+
+ public void readFully(byte[] buffer) throws IOException {
+ readFully(buffer, 0, buffer.length);
+ }
+
+ public void readFully(byte[] buffer, int offset, int count) throws IOException {
+ if (0 <= offset && offset <= buffer.length && 0 <= count && count <= buffer.length - offset) {
+ while (count > 0) {
+ int result = read(buffer, offset, count);
+ if (result >= 0) {
+ offset += result;
+ count -= result;
+ } else {
+ throw new EOFException();
+ }
+ }
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public long getFilePointer() {
+ return pos;
+ }
+*/
+
+ public void freeBefore(long pos) {
+ int blockIdx = (int)(pos >> BLOCK_SHIFT);
+ if (blockIdx <= firstUndisposed) { // Nothing to do
+ return;
+ }
+
+ for (int i = firstUndisposed; i < blockIdx; i++) {
+ blocks.set(i, null);
+ }
+
+ firstUndisposed = blockIdx;
+ }
+
+ public int appendData(InputStream is, int count) throws IOException {
+ if (count <= 0) {
+ return 0;
+ }
+
+ long startPos = length;
+ long lastPos = length + count - 1;
+ grow(lastPos); // Changes length
+
+ int blockIdx = (int)(startPos >> BLOCK_SHIFT);
+ int offset = (int) (startPos & BLOCK_MASK);
+
+ int bytesAppended = 0;
+
+ while (count > 0) {
+ byte[] block = blocks.get(blockIdx);
+ int toCopy = Math.min(BLOCK_SIZE - offset, count);
+ count -= toCopy;
+
+ while (toCopy > 0) {
+ int bytesRead = is.read(block, offset, toCopy);
+
+ if (bytesRead < 0) {
+ length -= (count - bytesAppended);
+ return bytesAppended;
+ }
+
+ toCopy -= bytesRead;
+ offset += bytesRead;
+ }
+
+ blockIdx++;
+ offset = 0;
+ }
+
+ return count;
+ }
+
+ public void getData(OutputStream os, int count, long pos) throws IOException {
+ if (pos + count > length) {
+ throw new IndexOutOfBoundsException("Argument out of cache");
+ }
+
+ int blockIdx = (int)(pos >> BLOCK_SHIFT);
+ int offset = (int) (pos & BLOCK_MASK);
+ if (blockIdx < firstUndisposed) {
+ throw new IndexOutOfBoundsException("The requested data are already disposed");
+ }
+
+ while (count > 0) {
+ byte[] block = blocks.get(blockIdx);
+ int toWrite = Math.min(BLOCK_SIZE - offset, count);
+ os.write(block, offset, toWrite);
+
+ blockIdx++;
+ offset = 0;
+ count -= toWrite;
+ }
+ }
+}
diff --git a/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties b/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
new file mode 100644
index 0000000..9f647e9
--- /dev/null
+++ b/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
@@ -0,0 +1,495 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+awt.00=FontRenderContext is null
+awt.01='{0}' parameter is null
+awt.02='{0}' parameter has zero length
+awt.03='{0}' iterator parameter is null
+awt.04='{0}' iterator parameter has zero length
+awt.05=Operation cannot be null
+awt.06=Unexpected type of the internal data buffer
+awt.07=Transfer data is not available
+awt.08=xfld parse string error: {0}
+awt.09=min range bound value is greater than max range bound
+awt.0A=Cannot use SinglePixedPackedSampleModel for bpp = {0}
+awt.0B=Wrong color model created for drawable
+awt.0C=Unknown visual class
+awt.0D=Invalid transparency
+awt.0E=Dimensions of the image should be positive
+awt.0F=Cannot open display '{0}'
+awt.10=Only 32-bit format is supported for window state operations.
+awt.11=Invalid key code
+awt.12=XTest is not supported by your X server\!
+awt.13=Cannot allocate color named '{0}'
+awt.14=Transfer data is not available
+awt.15=Can not get monitor info
+awt.16=Can not create DC for device
+awt.17=Unknown Composite type : {0}
+awt.18=Transparency is not supported
+awt.19=Illegal size of volatile image
+awt.1A=Failed to register window class {0} GetLastError returned {1}
+awt.1B=Invalid key code
+awt.1C=Failure to create JavaWindow GetLastError returned {0}
+awt.1D=Cannot get data from OLE clipboard
+awt.1E=Attempt to replace WindowProc handler
+awt.1F=Waiting for resource access thread interrupted not from unlock method
+awt.20=Can't unlock not locked resource
+awt.21=Not owner can't unlock resource
+awt.22=Not owner can't free resource
+awt.23=One thread can't store state several times in a row
+awt.24=Owner can't overwrite resource state. Lock operations may be lost
+awt.25=No state stored for current thread
+awt.26=Shutdown thread was interrupted while starting
+awt.27=Shutdown thread was interrupted while stopping
+awt.28=bad index: {0}
+awt.29=Invalid range
+awt.2A=Position not represented by view
+awt.2B=No word at {0}
+awt.2C=Invalid position: {0}
+awt.2D=Invalid direction
+awt.2E={0} not in range {1},{2}
+awt.2F=No more words
+awt.30=wrong number of elements to copy: {0}, size: {1}
+awt.31=no room to copy: {0}, size: {1}
+awt.32=String: '{0}' does not fit
+awt.33=index is out of range
+awt.34=Initial offset in the destination array is wrong: {0}
+awt.35=Wrong number of elements to copy: {0}
+awt.36=Wrong segment
+awt.37=Unknown composite type {0}
+awt.38=Property name is not defined
+awt.39=This method is not implemented for image obtained from ImageProducer
+awt.3A=Color Model is null
+awt.3B=Incorrect ImageConsumer completion status
+awt.3C=Unknown PNG color type
+awt.3D=Unknown colorspace
+awt.3E=Clone not supported
+awt.3F=Invalid baseline index
+awt.40=Wrong number of metrics\!
+awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
+awt.42=TextHitInfo out of range
+awt.43=glyphIndex is out of vector's limits
+awt.44=beginGlyphIndex is out of vector's range
+awt.45=numEntries is out of vector's range
+awt.46=length of setPositions array differs from the length of positions array
+awt.47=First argument should be byte or short array
+awt.48=The srcIn raster is incompatible with src ColorModel
+awt.49=The dstIn raster is incompatible with dst ColorModel
+awt.4A=The dstOut raster is incompatible with dst ColorModel
+awt.4B=Iterator out of bounds
+awt.4C=Invalid MultiRectArea in method {0}
+awt.4D=The raster is incompatible with this ColorModel
+awt.4E=Unknown native platform.
+awt.4F=Data is not available
+awt.50=Iterator is read-only
+awt.51=Component expected to be a parent
+awt.52=Time interval can't be <= 0
+awt.53=Handler can't be null
+awt.54=Key event for unfocused component
+awt.55=Double mouse enter event for component
+awt.56=Double mouse exit event for component
+awt.57=Double focus gained event for component
+awt.58=Double focus lost event for component
+awt.59=Application has run out of context thread group
+awt.5A=Default class for PrinterJob is not found
+awt.5B=No access to default class for PrinterJob
+awt.5C=Instantiation exception for PrinterJob
+awt.5D={0} is not supported
+awt.5E=pageIndex is more than book size
+awt.5F=wrong orientation
+awt.60=Width and Height mustn't be equal zero both
+awt.61=Unsupported data type: {0}
+awt.62=Wrong mask : {0}
+awt.63=Coordinates are not in bounds
+awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+awt.65=null argument
+awt.66=Invalid format
+awt.67=subclass is not derived from AWTKeyStroke
+awt.68=subclass could not be instantiated
+awt.69=columns less than zero.
+awt.6A=rows less than zero.
+awt.6B=Queue stack is empty
+awt.6C=Event queue stack is broken
+awt.6D=Point is null
+awt.6E=Color is null
+awt.6F=Index less than zero
+awt.70=MenuItem is null
+awt.71=Parent is null
+awt.72=Key event for unfocused component
+awt.73=no such item
+awt.74=Input parameters a and b should not be null
+awt.75=rows and cols cannot both be zero
+awt.76=rows and cols cannot be negative
+awt.77=default focus traversal policy cannot be null
+awt.78=invalid focus traversal key identifier
+awt.79=cannot set null focus traversal key
+awt.7A=focus traversal keys cannot map to KEY_TYPED events
+awt.7B=focus traversal keys must be unique for a Component
+awt.7C=this KeyboardFocusManager is not installed in the current thread's context
+awt.7D=Property name is null
+awt.7E=invalid hotSpot
+awt.7F=AddLayoutComponent: attempt to add null component
+awt.80=AddLayoutComponent: constraint object must be GridBagConstraints
+awt.81=AddLayoutComponent: {0}
+awt.82=RemoveLayoutComponent: attempt to remove null component
+awt.83=SetConstraints: attempt to get constraints of null component
+awt.84=SetConstraints: attempt to set null constraints
+awt.85=SetConstraints: {0}
+awt.86=MinimumLayoutSize: {0}
+awt.87=PreferredLayoutSize: {0}
+awt.88=LayoutContainer: {0}
+awt.89=LookupConstraints: attempt to get constraints of null component
+awt.8A=AdjustForGravity: attempt to use null constraints
+awt.8B=AdjustForGravity: attempt to use null rectangle
+awt.8C=AdjustForGravity: {0}
+awt.8D=REMINDER component expected after RELATIVE one
+awt.8E=component is out of grid's range
+awt.8F=Weights' overrides array is too long
+awt.90=Lengths' overrides array is too long
+awt.91=Unsupported constraints object: {0}
+awt.92=Constraints object must be String
+awt.93=cannot get component: invalid constraint: {0}
+awt.94=transform can not be null
+awt.95=Wrong start index: {0}
+awt.96=Wrong finish index: {0}
+awt.97=Wrong range length: {0}
+awt.98=Wrong count value, can not be negative: {0}
+awt.99=Wrong [start + count] is out of range: {0}
+awt.9A=Unsupported font format
+awt.9B=Can't create font - bad font data
+awt.9C=wrong value of GridBagConstraints: {0}
+awt.9D=relative grid size parameter goes after absolute grid coordinate
+awt.9E=wrong values sum of GridBagConstraints' gridwidth and gridx
+awt.9F=wrong values sum of GridBagConstraints' gridheight and gridy
+awt.100=component has RELATIVE width and height
+awt.101=position less than zero.
+awt.102=columns less than zero.
+awt.103=item is null
+awt.104=item doesn't exist in the choice menu
+awt.105=index less than zero
+awt.106=specified position is greater than the number of items
+awt.107=Color parameter outside of expected range: component {0}
+awt.108=Alpha value outside of expected range
+awt.109=Color parameter outside of expected range
+awt.10A=Priority must be a value between 0 and 1, inclusive
+awt.10B=aContainer and aComponent cannot be null
+awt.10C=aContainer is not a focus cycle root of aComponent
+awt.10D=aContainer should be focus cycle root or focus traversal policy provider
+awt.10E=focusCycleRoot cannot be null
+awt.10F=improper alignment: {0}
+awt.110=Iterator out of bounds
+awt.111=Parameter npoints is greater than array length
+awt.112=Negative number of points
+awt.113=illegal scrollbar orientation
+awt.114=Image is null
+awt.115=Anchor is null
+awt.116=Invalid value for media
+awt.117=Invalid value for orientationRequested
+awt.118=Invalid value for printerResolution
+awt.119=Invalid value for origin
+awt.11A=Invalid value for printQuality
+awt.11B=Invalid value for printerResolution[]
+awt.11C=Invalid value for color
+awt.11D=Unknown rule
+awt.11E=Wrong alpha value
+awt.11F=parent is not a component
+awt.120=origin is not a descendant of parent
+awt.121=parent must be showing on the screen
+awt.122=Does not support display mode changes
+awt.123=Unsupported display mode: {0}
+awt.124=Cannot change the modality while the dialog is visible
+awt.125=null owner window
+awt.126=Window is showing
+awt.127=Cannot change the decorations while the window is visible
+awt.128=Graphics environment is headless
+awt.129=Not a screen device
+awt.12A=illegal component position
+awt.12B=adding container to itself
+awt.12C=adding container's parent to itself
+awt.12D=adding a window to a container
+awt.12E=Unknown component event id
+awt.12F=Attempt to start nested mouse grab
+awt.130=Attempt to grab mouse in not displayable window
+awt.131=AddLayoutComponent: constraint object must be String
+awt.132=wrong parent for CardLayout
+awt.133=Negative width
+awt.134=Illegal cap
+awt.135=Illegal join
+awt.136=miterLimit less than 1.0f
+awt.137=Negative dashPhase
+awt.138=Zero dash length
+awt.139=Negative dash[{0}]
+awt.13A=All dash lengths zero
+awt.13B=offset off is out of range
+awt.13C=number of elemets len is out of range
+awt.13D=Rectangle width and height must be > 0
+awt.13E=Cannot call method from the event dispatcher thread
+awt.13F=Delay must be to 0 to 60,000ms
+awt.140=Invalid combination of button flags
+awt.141=failed to parse hotspot property for cursor:
+awt.142=Exception: class {0} {1} occurred while loading: {2}
+awt.143=illegal cursor type
+awt.144=Can be set by scrollpane only
+awt.145=illegal file dialog mode
+awt.146=illegal scrollbar display policy
+awt.147=position greater than 0
+awt.148=child is null
+awt.149=ScrollPane controls layout
+awt.14A=Can not create VolatileImage with specified capabilities
+awt.14B=Only Canvas or Window is allowed
+awt.14C=Number of buffers must be greater than one
+awt.14D=Buffer capabilities should support flipping
+awt.14E=Component should be displayable
+awt.14F=invalid focus traversal key identifier
+awt.150=no parent
+awt.151=component must be showing on the screen to determine its location
+awt.152=Invalid number of copies
+awt.153=Invalid value for maxPage
+awt.154=Invalid value for minPage
+awt.155=Invalid value for fromPage
+awt.156=Invalid value for toPage
+awt.157=Invalid value for pageRanges
+awt.158=Invalid value for destination
+awt.159=Invalid value for dialog
+awt.15A=Invalid value for defaultSelection
+awt.15B=Invalid value for multipleDocumentHandling
+awt.15C=Invalid value for attribute sides
+awt.15D=Invalid colorspace
+awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT.
+awt.15F=Profile class does not comply with ICC specification
+awt.160=Color space doesn't comply with ICC specification
+awt.161=Unable to open file {0}
+awt.162=Invalid ICC Profile Data
+awt.163=Can't open color profile
+awt.164=Not a predefined color space
+awt.165=Color space doesn't comply with ICC specification
+awt.166=TRC is not a simple gamma value
+awt.167=TRC is a gamma value, not a table
+awt.168=Invalid profile class
+awt.169=Component index out of range
+awt.16A=Invalid component index: {0}
+awt.16B=Not a predefined colorspace
+awt.16C=Can't load class: {0}
+awt.16D=Can't parse MIME type: {0}
+awt.16E=Transferable has null data
+awt.16F=Can't create reader for this representation class
+awt.170=Can't create default D&D cursor: {0}
+awt.171=Attempt to start a drag while an existing drag operation is still executing
+awt.172=Drag source is null
+awt.173=One listener is already exist
+awt.174=dgl is not current listener
+awt.175=Listener mismatch
+awt.176=DropTarget cannot be added as listener to itself
+awt.177=Invalid user action
+awt.178=Invalid source action
+awt.179=Context peer is null
+awt.17A=Trigger event is null
+awt.17B=Can't init ACTION_NONE drag
+awt.17C=Image offset is null
+awt.17D=Transferable is null
+awt.17E=Component associated with the trigger event is null
+awt.17F=DragSource for the trigger event is null
+awt.180=Source actions for the DragGestureRecognizer associated with the trigger event are equal to DnDConstants.ACTION_NONE
+awt.181=Attempt to register context as its listener
+awt.182=dsl is not current listener
+awt.183=Invalid status
+awt.184=Invalid action
+awt.185=Component is null
+awt.186=DragSource is null
+awt.187=Origin is null
+awt.188=Event list is null
+awt.189=Event list is empty
+awt.18A=Context is null
+awt.18B=Invalid button value
+awt.18C=Cannot invoke null runnable
+awt.18D=Source is null
+awt.18E=Wrong event id
+awt.18F=Text must be null for CARET_POSITION_CHANGED
+awt.190=Wrong committedCharacterCount
+awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED
+awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED
+awt.193=Listener can't be zero
+awt.194=Unknown attribute name
+awt.195=Offset is out of bounds
+awt.196=Justification impossible, layout already justified
+awt.197=Endpoints are out of range
+awt.198=Illegal alignment argument
+awt.199=Illegal range argument value: {0}
+awt.19A=start or count arguments are out of text range
+awt.19B=count argument must be positive
+awt.19C=weight must be a positive number
+awt.19D=growLeftLimit must be a positive number
+awt.19E=growRightLimit must be a positive number
+awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+awt.201=shrinkLeftLimit must be a positive number
+awt.202=shrinkRightLimit must be a positive number
+awt.203=Offset limit should be greater than current position
+awt.204=Determinant is zero
+awt.205=Invalid type of Arc: {0}
+awt.206=Flatness is less then zero
+awt.207=Limit is less then zero
+awt.208=Path is null
+awt.209=Invalid winding rule value
+awt.20A=First segment should be SEG_MOVETO type
+awt.20B=unknown input method highlight state
+awt.20C=Number of Bits equals to zero
+awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries
+awt.20E=Data Bit offset is not a multiple of pixel bit stride
+awt.20F=Number of bands must be only 1
+awt.210=The component value for this ColorModel is signed
+awt.211=Pixel values for this ColorModel are not conveniently representable as a single int
+awt.212=There is more than one component in this ColorModel
+awt.213=This ComponentColorModel does not support the unnormalized form
+awt.214=This Color Model doesn't support this transferType
+awt.215=transferType is not one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE
+awt.216=The components array is not large enough to hold all the color and alpha components
+awt.217=The transfer type of this ComponentColorModel is not one of the following transfer types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+awt.218=The components array is not large enough to hold all the color and alpha components
+awt.219=This transferType is not supported by this color model
+awt.21A=This ComponentColorModel does not support this transferType
+awt.21B=The length of normComponents minus normOffset is less than numComponents
+awt.21C=The number of scale factors should not be zero
+awt.21D=Number of src bands ({0}) does not match number of dst bands ({1})
+awt.21E=Number of scaling constants is not equal to the number of bands
+awt.21F=Unable to transform source
+awt.220=Source should not have IndexColorModel
+awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries
+awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
+awt.223=The imageType is not compatible with ColorModel
+awt.224=Unknown image type
+awt.225=Property name is null
+awt.226=Both tileX and tileY are not equal to 0
+awt.227=This image type can't have alpha
+awt.228=minX or minY of this raster not equal to zero
+awt.229=Number of components in the LUT does not match the number of bands
+awt.22A=Wrong type of pixels array
+awt.22B=Length of data should not be less than width*height
+awt.22C=Unknown data type {0}
+awt.22D=This transferType ( {0} ) is not supported by this color model
+awt.22E=w or h is less than or equal to zero
+awt.22F=The product of w and h is greater than Integer.MAX_VALUE
+awt.230=dataType is not one of the supported data types
+awt.231=Number of bands must be more then 0
+awt.232=Offset should be not less than zero
+awt.233=Number of components should be positive
+awt.234=Width or Height equals zero
+awt.235=Wrong Data Buffer type : {0}
+awt.236=The bits is less than 1 or greater than 32
+awt.237=Source and destinations rasters do not have the same number of bands
+awt.238=The number of arrays in the LookupTable does not meet the restrictions
+awt.239=The space is not a TYPE_RGB space
+awt.23A=The min/max normalized component values are not 0.0/1.0
+awt.23B=The mask of the {0} component is not contiguous
+awt.23C=The mask of the alpha component is not contiguous
+awt.23D=The mask of the red component is not contiguous
+awt.23E=The mask of the green component is not contiguous
+awt.23F=The mask of the blue component is not contiguous
+awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
+awt.241=Any offset between bands is greater than the Scanline stride
+awt.242=Pixel stride is less than any offset between bands
+awt.243=Product of Pixel stride and w is greater than Scanline stride
+awt.244=Width or Height of child Raster is less than or equal to zero
+awt.245=parentX disposes outside Raster
+awt.246=parentY disposes outside Raster
+awt.247=parentX + w results in integer overflow
+awt.248=parentY + h results in integer overflow
+awt.249=childMinX + w results in integer overflow
+awt.24A=childMinY + h results in integer overflow
+awt.24B=Pixel stride must be >= 0
+awt.24C=Scanline stride must be >= 0
+awt.24D=Bank Indices length must be equal Bank Offsets length
+awt.24E=Index of {0} bank must be >= 0
+awt.24F=Unable to invert transform {0}
+awt.250=Unknown interpolation type: {0}
+awt.251=Transformed width ({0}) and height ({1}) should be greater than 0
+awt.252=Source can't be same as the destination
+awt.253=Different number of bands in source and destination
+awt.254=Number of bands in the source raster ({0}) is incompatible with the matrix [{1}x{2}]
+awt.255=Number of bands in the destination raster ({0}) is incompatible with the matrix [{1}x{2}]
+awt.256=Source raster is null
+awt.257=Source raster is equal to destination
+awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1})
+awt.259=Source image is null
+awt.25A=Source equals to destination
+awt.25B=Null ColorSpace passed as a parameter
+awt.25C=Null profiles passed as a parameter
+awt.25D=Source or destination color space is not defined
+awt.25E=Incorrect number of source raster bands. Should be equal to the number of color components of source colorspace.
+awt.25F=Incorrect number of destination raster bands. Should be equal to the number of color components of destination colorspace.
+awt.260=Incompatible rasters - width or height differs
+awt.261=Destination color space is undefined
+awt.262=Destionation color space should be defined
+awt.263=Incompatible images - width or height differs
+awt.264=Size of the color map is less than 1
+awt.265=The raster argument is not compatible with this IndexColorModel
+awt.266=The number of bits in a pixel is greater than 16
+awt.267=The transferType is invalid
+awt.268=The pixel is not a primitive array of type transferType
+awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
+awt.26A=Incorrect ImageConsumer completion status
+awt.26B=The number of bits in the pixel values is less than 1
+awt.26C=bits is null
+awt.26D=The elements in bits is less than 0
+awt.26E=The sum of the number of bits in bits is less than 1
+awt.26F=The cspace is null
+awt.270=The transparency is not a valid value
+awt.271=The number of bits in bits is less than 1
+awt.272=The length of components minus offset is less than numComponents
+awt.273=The length of normComponents minus normOffset is less than numComponents
+awt.274=componentIdx is greater than the number of components or less than zero
+awt.275=This pixel representation is not suuported by tis Color Model
+awt.276=location.x + w or location.y + h results in integer overflow
+awt.277=bankIndices or bandOffsets is null
+awt.278=dataBuffer is null
+awt.279=bands is less than 1
+awt.27A=dataBuffer has more than one bank
+awt.27B=bandOffsets is null
+awt.27C=bandMasks is null
+awt.27D=bitsPerBand or bands is not greater than zero
+awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType
+awt.27F=SampleModel or DataBuffer is null
+awt.280=SampleModel is null
+awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null
+awt.282=aRegion has width or height less than or equal to zero
+awt.283=Overflow X coordinate of Raster
+awt.284=Overflow Y coordinate of Raster
+awt.285=Width or Height of child Raster is less than or equal to zero
+awt.286=parentX disposes outside Raster
+awt.287=parentY disposes outside Raster
+awt.288=parentX + width results in integer overflow
+awt.289=parentY + height results in integer overflow
+awt.28A=childMinX + width results in integer overflow
+awt.28B=childMinY + height results in integer overflow
+awt.28C=Rect is null
+awt.28D=Length of dataArray[{0}] is less than size + offset[{1}]
+awt.28E=Length of dataArray is less than size + offset
+awt.28F=Source and destination rasters do not have the same width!
+awt.290=Source and destination rasters do not have the same height!
+awt.291=Source and destination images do not have the same width!
+awt.292=Source and destination images do not have the same height!
+awt.294=pixel is null
+awt.295=data is null
+awt.296=can't allocate memory on video card to create new display list
+awt.297=Invalid keyLocation
+awt.298=dataBuffer is too small
+
+awt.err.00=file dialog {0} error!
+awt.err.01=error: {0}
+awt.err.02=GDIPlus DrawDriverString error status = {0}
+awt.err.03=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0}
+awt.err.04=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0}