From edbf3b6af777b721cd2a1ef461947e51e88241e1 Mon Sep 17 00:00:00 2001
From: The Android Open Source Project
Date: Tue, 3 Mar 2009 19:31:44 -0800
Subject: [PATCH] auto import from //depot/cupcake/@135843
---
MODULE_LICENSE_APACHE2 | 0
NOTICE | 222 +
awt/Android.mk | 31 +
.../internal/awt/AndroidGraphics2D.java | 1354 ++++
.../awt/AndroidGraphicsConfiguration.java | 96 +
.../internal/awt/AndroidGraphicsFactory.java | 87 +
.../internal/awt/AndroidImageDecoder.java | 274 +
.../internal/awt/AndroidJavaBlitter.java | 536 ++
.../internal/awt/AndroidNativeEventQueue.java | 75 +
awt/com/android/internal/awt/AndroidWTK.java | 88 +
awt/com/android/internal/awt/AwtFactory.java | 52 +
.../awt/ImageOutputStreamWrapper.java | 66 +
awt/java/awt/AWTEvent.java | 681 ++
awt/java/awt/AWTException.java | 47 +
awt/java/awt/AWTKeyStroke.java | 712 ++
awt/java/awt/AWTListenerList.java | 47 +
awt/java/awt/AWTPermission.java | 61 +
awt/java/awt/ActiveEvent.java | 39 +
awt/java/awt/Adjustable.java | 166 +
awt/java/awt/AlphaComposite.java | 352 +
awt/java/awt/BasicStroke.java | 2443 +++++++
awt/java/awt/BufferCapabilities.java | 195 +
awt/java/awt/Color.java | 990 +++
awt/java/awt/Component.java | 6020 +++++++++++++++++
awt/java/awt/ComponentBehavior.java | 56 +
awt/java/awt/ComponentOrientation.java | 154 +
awt/java/awt/Composite.java | 51 +
awt/java/awt/CompositeContext.java | 54 +
awt/java/awt/Cursor.java | 427 ++
awt/java/awt/Dimension.java | 201 +
awt/java/awt/Dispatcher.java | 723 ++
awt/java/awt/DisplayMode.java | 165 +
awt/java/awt/Event.java | 596 ++
awt/java/awt/EventDispatchThread.java | 118 +
awt/java/awt/EventQueue.java | 320 +
awt/java/awt/EventQueueCore.java | 253 +
awt/java/awt/Font.java | 1541 +++++
awt/java/awt/FontFormatException.java | 47 +
awt/java/awt/FontMetrics.java | 466 ++
awt/java/awt/GradientPaint.java | 255 +
awt/java/awt/GradientPaintContext.java | 204 +
awt/java/awt/Graphics.java | 924 +++
awt/java/awt/Graphics2D.java | 513 ++
awt/java/awt/GraphicsConfiguration.java | 226 +
awt/java/awt/GraphicsDevice.java | 196 +
awt/java/awt/GraphicsEnvironment.java | 212 +
awt/java/awt/HeadlessException.java | 54 +
awt/java/awt/HeadlessGraphicsEnvironment.java | 72 +
awt/java/awt/HeadlessToolkit.java | 226 +
.../awt/IllegalComponentStateException.java | 55 +
awt/java/awt/Image.java | 205 +
awt/java/awt/ImageCapabilities.java | 78 +
awt/java/awt/Insets.java | 179 +
awt/java/awt/ItemSelectable.java | 59 +
awt/java/awt/MenuComponent.java | 783 +++
awt/java/awt/MenuContainer.java | 57 +
awt/java/awt/ModalContext.java | 64 +
awt/java/awt/MouseDispatcher.java | 418 ++
awt/java/awt/Paint.java | 57 +
awt/java/awt/PaintContext.java | 69 +
awt/java/awt/Point.java | 211 +
awt/java/awt/Polygon.java | 515 ++
awt/java/awt/Rectangle.java | 723 ++
awt/java/awt/RenderingHints.java | 606 ++
awt/java/awt/Shape.java | 162 +
awt/java/awt/Stroke.java | 50 +
awt/java/awt/Toolkit.java | 1444 ++++
awt/java/awt/ToolkitImpl.java | 255 +
awt/java/awt/Transparency.java | 57 +
awt/java/awt/color/CMMException.java | 44 +
awt/java/awt/color/ColorSpace.java | 414 ++
awt/java/awt/color/ICC_ColorSpace.java | 468 ++
awt/java/awt/color/ICC_Profile.java | 1477 ++++
awt/java/awt/color/ICC_ProfileGray.java | 78 +
awt/java/awt/color/ICC_ProfileRGB.java | 154 +
awt/java/awt/color/ICC_ProfileStub.java | 173 +
awt/java/awt/color/ProfileDataException.java | 47 +
awt/java/awt/color/package.html | 8 +
awt/java/awt/event/AWTEventListener.java | 36 +
awt/java/awt/event/AWTEventListenerProxy.java | 58 +
awt/java/awt/event/ActionEvent.java | 114 +
awt/java/awt/event/ActionListener.java | 35 +
awt/java/awt/event/AdjustmentEvent.java | 123 +
awt/java/awt/event/AdjustmentListener.java | 35 +
awt/java/awt/event/ComponentAdapter.java | 46 +
awt/java/awt/event/ComponentEvent.java | 88 +
awt/java/awt/event/ComponentListener.java | 41 +
awt/java/awt/event/ContainerAdapter.java | 40 +
awt/java/awt/event/ContainerEvent.java | 89 +
awt/java/awt/event/ContainerListener.java | 37 +
awt/java/awt/event/FocusAdapter.java | 40 +
awt/java/awt/event/FocusEvent.java | 96 +
awt/java/awt/event/FocusListener.java | 37 +
.../awt/event/HierarchyBoundsAdapter.java | 40 +
.../awt/event/HierarchyBoundsListener.java | 37 +
awt/java/awt/event/HierarchyEvent.java | 154 +
awt/java/awt/event/HierarchyListener.java | 35 +
awt/java/awt/event/InputEvent.java | 190 +
awt/java/awt/event/InputMethodEvent.java | 156 +
awt/java/awt/event/InputMethodListener.java | 37 +
awt/java/awt/event/InvocationEvent.java | 138 +
awt/java/awt/event/ItemEvent.java | 96 +
awt/java/awt/event/ItemListener.java | 35 +
awt/java/awt/event/KeyAdapter.java | 43 +
awt/java/awt/event/KeyEvent.java | 687 ++
awt/java/awt/event/KeyListener.java | 39 +
awt/java/awt/event/MouseAdapter.java | 49 +
awt/java/awt/event/MouseEvent.java | 232 +
awt/java/awt/event/MouseListener.java | 43 +
awt/java/awt/event/MouseMotionAdapter.java | 40 +
awt/java/awt/event/MouseMotionListener.java | 37 +
awt/java/awt/event/MouseWheelEvent.java | 103 +
awt/java/awt/event/MouseWheelListener.java | 35 +
awt/java/awt/event/PaintEvent.java | 86 +
awt/java/awt/event/TextEvent.java | 59 +
awt/java/awt/event/TextListener.java | 36 +
awt/java/awt/event/WindowAdapter.java | 64 +
awt/java/awt/event/WindowEvent.java | 168 +
awt/java/awt/event/WindowFocusListener.java | 37 +
awt/java/awt/event/WindowListener.java | 47 +
awt/java/awt/event/WindowStateListener.java | 36 +
awt/java/awt/font/FontRenderContext.java | 178 +
awt/java/awt/font/GlyphJustificationInfo.java | 197 +
awt/java/awt/font/GlyphMetrics.java | 266 +
awt/java/awt/font/GlyphVector.java | 403 ++
awt/java/awt/font/GraphicAttribute.java | 179 +
awt/java/awt/font/ImageGraphicAttribute.java | 185 +
awt/java/awt/font/LineBreakMeasurer.java | 238 +
awt/java/awt/font/LineMetrics.java | 116 +
awt/java/awt/font/MultipleMaster.java | 91 +
awt/java/awt/font/OpenType.java | 418 ++
awt/java/awt/font/ShapeGraphicAttribute.java | 206 +
awt/java/awt/font/TextHitInfo.java | 215 +
awt/java/awt/font/TextLayout.java | 927 +++
awt/java/awt/font/TextMeasurer.java | 182 +
awt/java/awt/font/TransformAttribute.java | 86 +
awt/java/awt/font/package.html | 8 +
awt/java/awt/geom/AffineTransform.java | 1267 ++++
awt/java/awt/geom/Arc2D.java | 1157 ++++
awt/java/awt/geom/Area.java | 330 +
awt/java/awt/geom/CubicCurve2D.java | 1047 +++
awt/java/awt/geom/Dimension2D.java | 83 +
awt/java/awt/geom/Ellipse2D.java | 458 ++
awt/java/awt/geom/FlatteningPathIterator.java | 358 +
awt/java/awt/geom/GeneralPath.java | 624 ++
.../awt/geom/IllegalPathStateException.java | 55 +
awt/java/awt/geom/Line2D.java | 948 +++
.../geom/NoninvertibleTransformException.java | 48 +
awt/java/awt/geom/PathIterator.java | 146 +
awt/java/awt/geom/Point2D.java | 323 +
awt/java/awt/geom/QuadCurve2D.java | 918 +++
awt/java/awt/geom/Rectangle2D.java | 824 +++
awt/java/awt/geom/RectangularShape.java | 297 +
awt/java/awt/geom/RoundRectangle2D.java | 635 ++
awt/java/awt/geom/package.html | 8 +
awt/java/awt/im/InputContext.java | 83 +
awt/java/awt/im/InputMethodHighlight.java | 95 +
awt/java/awt/im/InputMethodRequests.java | 49 +
awt/java/awt/im/InputSubset.java | 59 +
awt/java/awt/im/spi/InputMethod.java | 67 +
awt/java/awt/im/spi/InputMethodContext.java | 46 +
.../awt/im/spi/InputMethodDescriptor.java | 46 +
awt/java/awt/image/AffineTransformOp.java | 618 ++
.../awt/image/AreaAveragingScaleFilter.java | 288 +
.../image/AwtImageBackdoorAccessorImpl.java | 156 +
awt/java/awt/image/BandCombineOp.java | 658 ++
awt/java/awt/image/BandedSampleModel.java | 425 ++
awt/java/awt/image/BufferStrategy.java | 74 +
awt/java/awt/image/BufferedImage.java | 952 +++
awt/java/awt/image/BufferedImageFilter.java | 397 ++
awt/java/awt/image/BufferedImageOp.java | 92 +
awt/java/awt/image/ByteLookupTable.java | 140 +
awt/java/awt/image/ColorConvertOp.java | 710 ++
awt/java/awt/image/ColorModel.java | 964 +++
awt/java/awt/image/ComponentColorModel.java | 1482 ++++
awt/java/awt/image/ComponentSampleModel.java | 705 ++
awt/java/awt/image/ConvolveOp.java | 545 ++
awt/java/awt/image/CropImageFilter.java | 196 +
awt/java/awt/image/DataBuffer.java | 481 ++
awt/java/awt/image/DataBufferByte.java | 183 +
awt/java/awt/image/DataBufferDouble.java | 226 +
awt/java/awt/image/DataBufferFloat.java | 226 +
awt/java/awt/image/DataBufferInt.java | 182 +
awt/java/awt/image/DataBufferShort.java | 181 +
awt/java/awt/image/DataBufferUShort.java | 195 +
awt/java/awt/image/DirectColorModel.java | 889 +++
awt/java/awt/image/FilteredImageSource.java | 98 +
awt/java/awt/image/ImageConsumer.java | 185 +
awt/java/awt/image/ImageFilter.java | 134 +
awt/java/awt/image/ImageObserver.java | 101 +
awt/java/awt/image/ImageProducer.java | 79 +
awt/java/awt/image/ImagingOpException.java | 49 +
awt/java/awt/image/IndexColorModel.java | 1080 +++
awt/java/awt/image/Kernel.java | 153 +
awt/java/awt/image/LookupOp.java | 661 ++
awt/java/awt/image/LookupTable.java | 101 +
awt/java/awt/image/MemoryImageSource.java | 603 ++
.../image/MultiPixelPackedSampleModel.java | 479 ++
awt/java/awt/image/PackedColorModel.java | 402 ++
awt/java/awt/image/PixelGrabber.java | 408 ++
.../image/PixelInterleavedSampleModel.java | 134 +
awt/java/awt/image/RGBImageFilter.java | 195 +
awt/java/awt/image/Raster.java | 1515 +++++
awt/java/awt/image/RasterFormatException.java | 48 +
awt/java/awt/image/RasterOp.java | 88 +
awt/java/awt/image/RenderedImage.java | 198 +
awt/java/awt/image/ReplicateScaleFilter.java | 225 +
awt/java/awt/image/RescaleOp.java | 659 ++
awt/java/awt/image/SampleModel.java | 1166 ++++
awt/java/awt/image/ShortLookupTable.java | 137 +
.../image/SinglePixelPackedSampleModel.java | 519 ++
awt/java/awt/image/TileObserver.java | 49 +
awt/java/awt/image/VolatileImage.java | 146 +
awt/java/awt/image/WritableRaster.java | 592 ++
awt/java/awt/image/WritableRenderedImage.java | 109 +
awt/java/awt/image/package.html | 8 +
.../ContextualRenderedImageFactory.java | 97 +
.../awt/image/renderable/ParameterBlock.java | 568 ++
.../awt/image/renderable/RenderContext.java | 214 +
.../awt/image/renderable/RenderableImage.java | 138 +
.../image/renderable/RenderableImageOp.java | 191 +
.../renderable/RenderableImageProducer.java | 151 +
.../renderable/RenderedImageFactory.java | 46 +
awt/java/awt/image/renderable/package.html | 8 +
awt/java/awt/package.html | 8 +
awt/java/awt/peer/ButtonPeer.java | 25 +
awt/java/awt/peer/CanvasPeer.java | 25 +
awt/java/awt/peer/CheckboxMenuItemPeer.java | 25 +
awt/java/awt/peer/CheckboxPeer.java | 25 +
awt/java/awt/peer/ChoicePeer.java | 25 +
awt/java/awt/peer/ComponentPeer.java | 25 +
awt/java/awt/peer/DialogPeer.java | 25 +
awt/java/awt/peer/FileDialogPeer.java | 25 +
awt/java/awt/peer/FontPeer.java | 25 +
awt/java/awt/peer/FramePeer.java | 25 +
awt/java/awt/peer/LabelPeer.java | 25 +
awt/java/awt/peer/LightweightPeer.java | 25 +
awt/java/awt/peer/ListPeer.java | 25 +
awt/java/awt/peer/MenuBarPeer.java | 25 +
awt/java/awt/peer/MenuComponentPeer.java | 25 +
awt/java/awt/peer/MenuItemPeer.java | 25 +
awt/java/awt/peer/MenuPeer.java | 25 +
awt/java/awt/peer/MouseInfoPeer.java | 25 +
awt/java/awt/peer/PanelPeer.java | 25 +
awt/java/awt/peer/PopupMenuPeer.java | 25 +
awt/java/awt/peer/ScrollPanePeer.java | 25 +
awt/java/awt/peer/ScrollbarPeer.java | 25 +
awt/java/awt/peer/TextAreaPeer.java | 25 +
awt/java/awt/peer/TextFieldPeer.java | 25 +
awt/java/awt/peer/WindowPeer.java | 25 +
awt/java/beans/FeatureDescriptor.java | 234 +
awt/java/beans/IndexedPropertyDescriptor.java | 227 +
awt/java/beans/IntrospectionException.java | 27 +
awt/java/beans/PropertyDescriptor.java | 300 +
awt/java/beans/PropertyEditor.java | 49 +
awt/java/beans/PropertyEditorManager.java | 114 +
awt/java/beans/PropertyEditorSupport.java | 129 +
awt/java/beans/PropertyVetoException.java | 54 +
awt/javax/imageio/IIOException.java | 60 +
awt/javax/imageio/IIOImage.java | 224 +
awt/javax/imageio/IIOParam.java | 342 +
awt/javax/imageio/IIOParamController.java | 45 +
awt/javax/imageio/ImageIO.java | 800 +++
awt/javax/imageio/ImageReadParam.java | 201 +
awt/javax/imageio/ImageReader.java | 1162 ++++
awt/javax/imageio/ImageTranscoder.java | 67 +
awt/javax/imageio/ImageTypeSpecifier.java | 347 +
awt/javax/imageio/ImageWriteParam.java | 664 ++
awt/javax/imageio/ImageWriter.java | 1001 +++
.../event/IIOReadProgressListener.java | 121 +
.../imageio/event/IIOReadUpdateListener.java | 182 +
.../imageio/event/IIOReadWarningListener.java | 49 +
.../event/IIOWriteProgressListener.java | 101 +
.../event/IIOWriteWarningListener.java | 46 +
awt/javax/imageio/event/package.html | 8 +
.../metadata/IIOInvalidTreeException.java | 74 +
awt/javax/imageio/metadata/IIOMetadata.java | 391 ++
.../metadata/IIOMetadataController.java | 46 +
.../imageio/metadata/IIOMetadataFormat.java | 404 ++
.../metadata/IIOMetadataFormatImpl.java | 1056 +++
.../imageio/metadata/IIOMetadataNode.java | 1070 +++
.../metadata/IIOStandardMetadataFormat.java | 297 +
...StandardMetadataFormatResources.properties | 133 +
awt/javax/imageio/metadata/package.html | 8 +
awt/javax/imageio/package.html | 8 +
.../plugins/bmp/BMPImageWriteParam.java | 79 +
awt/javax/imageio/plugins/bmp/package.html | 8 +
.../plugins/jpeg/JPEGHuffmanTable.java | 226 +
.../plugins/jpeg/JPEGImageReadParam.java | 123 +
.../plugins/jpeg/JPEGImageWriteParam.java | 209 +
.../imageio/plugins/jpeg/JPEGQTable.java | 165 +
awt/javax/imageio/plugins/jpeg/package.html | 8 +
awt/javax/imageio/spi/IIORegistry.java | 115 +
awt/javax/imageio/spi/IIOServiceProvider.java | 105 +
.../imageio/spi/ImageInputStreamSpi.java | 131 +
.../imageio/spi/ImageOutputStreamSpi.java | 132 +
awt/javax/imageio/spi/ImageReaderSpi.java | 204 +
.../imageio/spi/ImageReaderWriterSpi.java | 344 +
awt/javax/imageio/spi/ImageTranscoderSpi.java | 76 +
awt/javax/imageio/spi/ImageWriterSpi.java | 227 +
.../imageio/spi/RegisterableService.java | 54 +
awt/javax/imageio/spi/ServiceRegistry.java | 552 ++
awt/javax/imageio/spi/package.html | 8 +
.../stream/FileCacheImageInputStream.java | 137 +
.../stream/FileCacheImageOutputStream.java | 196 +
.../imageio/stream/FileImageInputStream.java | 122 +
.../imageio/stream/FileImageOutputStream.java | 128 +
awt/javax/imageio/stream/IIOByteBuffer.java | 124 +
.../imageio/stream/ImageInputStream.java | 502 ++
.../imageio/stream/ImageInputStreamImpl.java | 418 ++
.../imageio/stream/ImageOutputStream.java | 307 +
.../imageio/stream/ImageOutputStreamImpl.java | 174 +
.../stream/MemoryCacheImageInputStream.java | 119 +
.../stream/MemoryCacheImageOutputStream.java | 135 +
awt/javax/imageio/stream/package.html | 8 +
awt/org/apache/harmony/awt/ChoiceStyle.java | 33 +
awt/org/apache/harmony/awt/ClipRegion.java | 84 +
.../harmony/awt/ComponentInternals.java | 212 +
.../apache/harmony/awt/ContextStorage.java | 154 +
.../harmony/awt/ContextThreadGroup.java | 34 +
awt/org/apache/harmony/awt/ListenerList.java | 194 +
.../apache/harmony/awt/ReadOnlyIterator.java | 53 +
.../awt/gl/AwtImageBackdoorAccessor.java | 65 +
.../harmony/awt/gl/CommonGraphics2D.java | 1132 ++++
.../awt/gl/CommonGraphics2DFactory.java | 78 +
.../awt/gl/CommonGraphicsEnvironment.java | 67 +
awt/org/apache/harmony/awt/gl/Crossing.java | 889 +++
.../harmony/awt/gl/GLVolatileImage.java | 30 +
.../harmony/awt/gl/ICompositeContext.java | 90 +
.../apache/harmony/awt/gl/ImageSurface.java | 323 +
.../apache/harmony/awt/gl/MultiRectArea.java | 836 +++
.../harmony/awt/gl/MultiRectAreaOp.java | 837 +++
awt/org/apache/harmony/awt/gl/Surface.java | 309 +
.../apache/harmony/awt/gl/TextRenderer.java | 59 +
.../apache/harmony/awt/gl/XORComposite.java | 48 +
.../harmony/awt/gl/color/ColorConverter.java | 257 +
.../harmony/awt/gl/color/ColorScaler.java | 355 +
.../awt/gl/color/ICC_ProfileHelper.java | 82 +
.../harmony/awt/gl/color/ICC_Transform.java | 156 +
.../awt/gl/color/LUTColorConverter.java | 148 +
.../harmony/awt/gl/color/NativeCMM.java | 92 +
.../awt/gl/color/NativeImageFormat.java | 642 ++
.../harmony/awt/gl/font/AndroidFont.java | 254 +
.../awt/gl/font/AndroidFontManager.java | 277 +
.../awt/gl/font/AndroidFontProperty.java | 81 +
.../awt/gl/font/AndroidGlyphVector.java | 219 +
.../awt/gl/font/AndroidLineMetrics.java | 120 +
.../harmony/awt/gl/font/BasicMetrics.java | 134 +
.../harmony/awt/gl/font/CaretManager.java | 530 ++
.../awt/gl/font/CommonGlyphVector.java | 954 +++
.../harmony/awt/gl/font/CompositeFont.java | 486 ++
.../harmony/awt/gl/font/FontExtraMetrics.java | 145 +
.../harmony/awt/gl/font/FontFinder.java | 121 +
.../harmony/awt/gl/font/FontManager.java | 819 +++
.../harmony/awt/gl/font/FontMetricsImpl.java | 282 +
.../harmony/awt/gl/font/FontPeerImpl.java | 499 ++
.../harmony/awt/gl/font/FontProperty.java | 106 +
awt/org/apache/harmony/awt/gl/font/Glyph.java | 236 +
.../harmony/awt/gl/font/LineMetricsImpl.java | 412 ++
.../harmony/awt/gl/font/TextDecorator.java | 433 ++
.../awt/gl/font/TextMetricsCalculator.java | 209 +
.../harmony/awt/gl/font/TextRunBreaker.java | 861 +++
.../harmony/awt/gl/font/TextRunSegment.java | 165 +
.../awt/gl/font/TextRunSegmentImpl.java | 979 +++
.../awt/gl/image/BufferedImageGraphics2D.java | 79 +
.../awt/gl/image/BufferedImageSource.java | 136 +
.../image/ByteArrayDecodingImageSource.java | 62 +
.../awt/gl/image/DataBufferListener.java | 31 +
.../awt/gl/image/DecodingImageSource.java | 261 +
.../awt/gl/image/FileDecodingImageSource.java | 68 +
.../harmony/awt/gl/image/GifDecoder.java | 692 ++
.../harmony/awt/gl/image/ImageDecoder.java | 258 +
.../harmony/awt/gl/image/ImageLoader.java | 208 +
.../harmony/awt/gl/image/JpegDecoder.java | 231 +
.../harmony/awt/gl/image/OffscreenImage.java | 532 ++
.../awt/gl/image/OrdinaryWritableRaster.java | 153 +
.../harmony/awt/gl/image/PngDecoder.java | 270 +
.../harmony/awt/gl/image/PngDecoderJava.java | 282 +
.../awt/gl/image/URLDecodingImageSource.java | 77 +
.../apache/harmony/awt/gl/render/Blitter.java | 53 +
.../awt/gl/render/JavaArcRasterizer.java | 502 ++
.../harmony/awt/gl/render/JavaBlitter.java | 611 ++
.../awt/gl/render/JavaLineRasterizer.java | 760 +++
.../awt/gl/render/JavaShapeRasterizer.java | 475 ++
.../awt/gl/render/JavaTextRenderer.java | 263 +
.../awt/gl/render/NativeImageBlitter.java | 218 +
.../harmony/awt/gl/render/NullBlitter.java | 56 +
.../harmony/awt/im/InputMethodContext.java | 563 ++
.../harmony/awt/internal/nls/Messages.java | 151 +
.../harmony/awt/internal/nls/MsgHelp.java | 86 +
.../harmony/awt/state/MenuItemState.java | 51 +
.../apache/harmony/awt/state/MenuState.java | 46 +
awt/org/apache/harmony/awt/state/State.java | 55 +
.../harmony/awt/wtk/CreationParams.java | 133 +
.../apache/harmony/awt/wtk/CursorFactory.java | 85 +
.../harmony/awt/wtk/GraphicsFactory.java | 82 +
awt/org/apache/harmony/awt/wtk/KeyInfo.java | 53 +
.../apache/harmony/awt/wtk/NativeCursor.java | 45 +
.../apache/harmony/awt/wtk/NativeEvent.java | 268 +
.../harmony/awt/wtk/NativeEventQueue.java | 117 +
.../harmony/awt/wtk/NativeEventThread.java | 78 +
awt/org/apache/harmony/awt/wtk/NativeIM.java | 130 +
.../harmony/awt/wtk/NativeMouseInfo.java | 42 +
.../apache/harmony/awt/wtk/NativeRobot.java | 75 +
.../apache/harmony/awt/wtk/NativeWindow.java | 220 +
.../harmony/awt/wtk/ShutdownThread.java | 83 +
.../harmony/awt/wtk/ShutdownWatchdog.java | 86 +
.../apache/harmony/awt/wtk/Synchronizer.java | 200 +
.../harmony/awt/wtk/SystemProperties.java | 59 +
awt/org/apache/harmony/awt/wtk/WTK.java | 61 +
.../apache/harmony/awt/wtk/WindowFactory.java | 85 +
.../harmony/beans/internal/nls/Messages.java | 151 +
.../harmony/beans/internal/nls/MsgHelp.java | 86 +
.../x/imageio/internal/nls/Messages.java | 124 +
.../imageio/internal/nls/messages.properties | 18 +
.../x/imageio/metadata/IIOMetadataUtils.java | 94 +
.../plugins/jpeg/IISDecodingImageSource.java | 115 +
.../x/imageio/plugins/jpeg/JPEGConsts.java | 44 +
.../imageio/plugins/jpeg/JPEGImageReader.java | 126 +
.../plugins/jpeg/JPEGImageReaderSpi.java | 86 +
.../imageio/plugins/jpeg/JPEGImageWriter.java | 402 ++
.../plugins/jpeg/JPEGImageWriterSpi.java | 56 +
.../x/imageio/plugins/jpeg/JPEGSpiConsts.java | 57 +
.../x/imageio/plugins/png/PNGImageReader.java | 106 +
.../plugins/png/PNGImageReaderSpi.java | 88 +
.../x/imageio/plugins/png/PNGImageWriter.java | 247 +
.../plugins/png/PNGImageWriterParam.java | 41 +
.../plugins/png/PNGImageWriterSpi.java | 113 +
.../harmony/x/imageio/spi/FileIISSpi.java | 53 +
.../harmony/x/imageio/spi/FileIOSSpi.java | 52 +
.../x/imageio/spi/InputStreamIISSpi.java | 59 +
.../x/imageio/spi/OutputStreamIOSSpi.java | 60 +
.../harmony/x/imageio/spi/RAFIISSpi.java | 54 +
.../harmony/x/imageio/spi/RAFIOSSpi.java | 53 +
.../stream/RandomAccessMemoryCache.java | 226 +
.../awt/internal/nls/messages.properties | 495 ++
.../beans/internals/nls/messages.properties | 103 +
camera/libcameraservice/Android.mk | 59 +
.../libcameraservice/CameraHardwareStub.cpp | 388 ++
camera/libcameraservice/CameraHardwareStub.h | 124 +
camera/libcameraservice/CameraService.cpp | 1073 +++
camera/libcameraservice/CameraService.h | 206 +
camera/libcameraservice/CannedJpeg.h | 1546 +++++
camera/libcameraservice/FakeCamera.cpp | 404 ++
camera/libcameraservice/FakeCamera.h | 51 +
cmds/runtime/Android.mk | 29 +
cmds/runtime/MODULE_LICENSE_APACHE2 | 0
cmds/runtime/NOTICE | 190 +
cmds/runtime/ServiceManager.cpp | 74 +
cmds/runtime/ServiceManager.h | 38 +
cmds/runtime/SignalHandler.cpp | 249 +
cmds/runtime/SignalHandler.h | 137 +
cmds/runtime/main_runtime.cpp | 514 ++
cmds/surfaceflinger/Android.mk | 16 +
cmds/surfaceflinger/main_surfaceflinger.cpp | 18 +
im/java/android/im/BrandingResourceIDs.java | 52 +
im/java/android/im/IImPlugin.aidl | 69 +
im/java/android/im/ImPluginConsts.java | 27 +
include/pim/EventRecurrence.h | 82 +
include/private/opengles/gl_context.h | 632 ++
include/private/ui/LayerState.h | 75 +
include/private/ui/SharedState.h | 168 +
include/private/ui/SurfaceFlingerSynchro.h | 76 +
include/private/utils/Static.h | 58 +
include/private/utils/binder_module.h | 148 +
include/private/utils/futex_synchro.h | 60 +
include/ui/Camera.h | 196 +
include/ui/CameraHardwareInterface.h | 190 +
include/ui/CameraParameters.h | 79 +
include/ui/DisplayInfo.h | 43 +
include/ui/EGLDisplaySurface.h | 86 +
include/ui/EGLNativeSurface.h | 55 +
include/ui/EGLNativeWindowSurface.h | 59 +
include/ui/EventHub.h | 145 +
include/ui/ICamera.h | 102 +
include/ui/ICameraClient.h | 55 +
include/ui/ICameraService.h | 55 +
include/ui/IOverlay.h | 53 +
include/ui/ISurface.h | 105 +
include/ui/ISurfaceComposer.h | 181 +
include/ui/ISurfaceFlingerClient.h | 90 +
include/ui/KeyCharacterMap.h | 72 +
include/ui/KeycodeLabels.h | 236 +
include/ui/Overlay.h | 109 +
include/ui/PixelFormat.h | 125 +
include/ui/Point.h | 88 +
include/ui/Rect.h | 152 +
include/ui/Region.h | 174 +
include/ui/Surface.h | 137 +
include/ui/SurfaceComposerClient.h | 179 +
include/utils.h | 33 +
include/utils/AndroidUnicode.h | 255 +
include/utils/Asset.h | 315 +
include/utils/AssetDir.h | 145 +
include/utils/AssetManager.h | 323 +
include/utils/Atomic.h | 22 +
include/utils/Binder.h | 103 +
include/utils/BpBinder.h | 122 +
include/utils/Buffer.h | 107 +
include/utils/BufferedTextOutput.h | 67 +
include/utils/ByteOrder.h | 69 +
include/utils/CallStack.h | 76 +
include/utils/Debug.h | 45 +
include/utils/Endian.h | 40 +
include/utils/Errors.h | 87 +
include/utils/FileMap.h | 134 +
include/utils/IBinder.h | 159 +
include/utils/IInterface.h | 135 +
include/utils/IMemory.h | 94 +
include/utils/IPCThreadState.h | 110 +
include/utils/IPermissionController.h | 56 +
include/utils/IServiceManager.h | 98 +
include/utils/KeyedVector.h | 201 +
include/utils/List.h | 280 +
include/utils/Log.h | 33 +
include/utils/LogSocket.h | 20 +
include/utils/MemoryBase.h | 51 +
include/utils/MemoryDealer.h | 238 +
include/utils/MemoryHeapBase.h | 98 +
include/utils/MemoryHeapPmem.h | 80 +
include/utils/Parcel.h | 209 +
include/utils/Pipe.h | 108 +
include/utils/ProcessState.h | 117 +
include/utils/RefBase.h | 550 ++
include/utils/ResourceTypes.h | 1720 +++++
include/utils/SharedBuffer.h | 146 +
include/utils/Socket.h | 80 +
include/utils/SortedVector.h | 282 +
include/utils/StopWatch.h | 62 +
include/utils/String16.h | 260 +
include/utils/String8.h | 353 +
include/utils/SystemClock.h | 32 +
include/utils/TextOutput.h | 190 +
include/utils/TimeUtils.h | 89 +
include/utils/TimerProbe.h | 72 +
include/utils/Timers.h | 137 +
include/utils/TypeHelpers.h | 254 +
include/utils/Vector.h | 359 +
include/utils/VectorImpl.h | 199 +
include/utils/ZipEntry.h | 345 +
include/utils/ZipFile.h | 269 +
include/utils/ZipFileCRO.h | 59 +
include/utils/ZipFileRO.h | 222 +
include/utils/ZipUtils.h | 67 +
include/utils/ashmem.h | 41 +
include/utils/executablepath.h | 28 +
include/utils/inet_address.h | 103 +
include/utils/misc.h | 93 +
include/utils/ported.h | 50 +
include/utils/string_array.h | 135 +
include/utils/threads.h | 347 +
libs/audioflinger/A2dpAudioInterface.cpp | 242 +
libs/audioflinger/A2dpAudioInterface.h | 109 +
libs/audioflinger/Android.mk | 56 +
libs/audioflinger/AudioBufferProvider.h | 47 +
libs/audioflinger/AudioDumpInterface.cpp | 117 +
libs/audioflinger/AudioDumpInterface.h | 97 +
libs/audioflinger/AudioFlinger.cpp | 2474 +++++++
libs/audioflinger/AudioFlinger.h | 637 ++
libs/audioflinger/AudioHardwareGeneric.cpp | 313 +
libs/audioflinger/AudioHardwareGeneric.h | 141 +
libs/audioflinger/AudioHardwareInterface.cpp | 247 +
libs/audioflinger/AudioHardwareStub.cpp | 185 +
libs/audioflinger/AudioHardwareStub.h | 100 +
libs/audioflinger/AudioMixer.cpp | 913 +++
libs/audioflinger/AudioMixer.h | 192 +
libs/audioflinger/AudioResampler.cpp | 595 ++
libs/audioflinger/AudioResampler.h | 93 +
libs/audioflinger/AudioResamplerCubic.cpp | 184 +
libs/audioflinger/AudioResamplerCubic.h | 68 +
libs/audioflinger/AudioResamplerSinc.cpp | 358 +
libs/audioflinger/AudioResamplerSinc.h | 88 +
libs/surfaceflinger/Android.mk | 49 +
libs/surfaceflinger/Barrier.h | 59 +
libs/surfaceflinger/BlurFilter.cpp | 326 +
libs/surfaceflinger/BlurFilter.h | 35 +
libs/surfaceflinger/BootAnimation.cpp | 403 ++
libs/surfaceflinger/BootAnimation.h | 87 +
libs/surfaceflinger/CPUGauge.cpp | 171 +
libs/surfaceflinger/CPUGauge.h | 74 +
.../DisplayHardware/DisplayHardware.cpp | 353 +
.../DisplayHardware/DisplayHardware.h | 113 +
.../DisplayHardware/DisplayHardwareBase.cpp | 403 ++
.../DisplayHardware/DisplayHardwareBase.h | 96 +
.../GPUHardware/GPUHardware.cpp | 581 ++
libs/surfaceflinger/GPUHardware/GPUHardware.h | 63 +
libs/surfaceflinger/Layer.cpp | 568 ++
libs/surfaceflinger/Layer.h | 120 +
libs/surfaceflinger/LayerBase.cpp | 740 ++
libs/surfaceflinger/LayerBase.h | 356 +
libs/surfaceflinger/LayerBitmap.cpp | 185 +
libs/surfaceflinger/LayerBitmap.h | 84 +
libs/surfaceflinger/LayerBlur.cpp | 234 +
libs/surfaceflinger/LayerBlur.h | 65 +
libs/surfaceflinger/LayerBuffer.cpp | 655 ++
libs/surfaceflinger/LayerBuffer.h | 216 +
libs/surfaceflinger/LayerDim.cpp | 113 +
libs/surfaceflinger/LayerDim.h | 57 +
libs/surfaceflinger/LayerOrientationAnim.cpp | 287 +
libs/surfaceflinger/LayerOrientationAnim.h | 75 +
libs/surfaceflinger/MODULE_LICENSE_APACHE2 | 0
libs/surfaceflinger/OrientationAnimation.cpp | 155 +
libs/surfaceflinger/OrientationAnimation.h | 73 +
libs/surfaceflinger/SurfaceFlinger.cpp | 1840 +++++
libs/surfaceflinger/SurfaceFlinger.h | 435 ++
libs/surfaceflinger/Tokenizer.cpp | 172 +
libs/surfaceflinger/Tokenizer.h | 57 +
libs/surfaceflinger/Transform.cpp | 204 +
libs/surfaceflinger/Transform.h | 87 +
libs/surfaceflinger/VRamHeap.cpp | 176 +
libs/surfaceflinger/VRamHeap.h | 78 +
libs/surfaceflinger/clz.cpp | 37 +
libs/surfaceflinger/clz.h | 37 +
libs/surfaceflinger/tests/Android.mk | 1 +
libs/surfaceflinger/tests/overlays/Android.mk | 16 +
.../tests/overlays/overlays.cpp | 58 +
libs/ui/Android.mk | 41 +
libs/ui/Camera.cpp | 408 ++
libs/ui/CameraParameters.cpp | 273 +
libs/ui/EGLDisplaySurface.cpp | 519 ++
libs/ui/EGLNativeWindowSurface.cpp | 161 +
libs/ui/EventHub.cpp | 793 +++
libs/ui/EventRecurrence.cpp | 484 ++
libs/ui/ICamera.cpp | 346 +
libs/ui/ICameraClient.cpp | 185 +
libs/ui/ICameraService.cpp | 77 +
libs/ui/IOverlay.cpp | 72 +
libs/ui/ISurface.cpp | 164 +
libs/ui/ISurfaceComposer.cpp | 277 +
libs/ui/ISurfaceFlingerClient.cpp | 208 +
libs/ui/KeyCharacterMap.cpp | 263 +
libs/ui/KeyLayoutMap.cpp | 235 +
libs/ui/KeyLayoutMap.h | 31 +
libs/ui/LayerState.cpp | 53 +
libs/ui/MODULE_LICENSE_APACHE2 | 0
libs/ui/NOTICE | 190 +
libs/ui/Overlay.cpp | 181 +
libs/ui/PixelFormat.cpp | 97 +
libs/ui/Point.cpp | 11 +
libs/ui/Rect.cpp | 86 +
libs/ui/Region.cpp | 313 +
libs/ui/Surface.cpp | 256 +
libs/ui/SurfaceComposerClient.cpp | 1026 +++
libs/ui/SurfaceFlingerSynchro.cpp | 123 +
libs/ui/Time.cpp | 199 +
libs/utils/Android.mk | 156 +
libs/utils/Asset.cpp | 813 +++
libs/utils/AssetDir.cpp | 66 +
libs/utils/AssetManager.cpp | 1637 +++++
libs/utils/Binder.cpp | 242 +
libs/utils/BpBinder.cpp | 348 +
libs/utils/BufferedTextOutput.cpp | 279 +
libs/utils/CallStack.cpp | 335 +
libs/utils/Debug.cpp | 318 +
libs/utils/FileMap.cpp | 222 +
libs/utils/IDataConnection.cpp | 89 +
libs/utils/IInterface.cpp | 35 +
libs/utils/IMemory.cpp | 486 ++
libs/utils/IPCThreadState.cpp | 1030 +++
libs/utils/IPermissionController.cpp | 86 +
libs/utils/IServiceManager.cpp | 230 +
libs/utils/InetAddress.cpp | 236 +
libs/utils/LogSocket.cpp | 129 +
libs/utils/MODULE_LICENSE_APACHE2 | 0
libs/utils/MemoryBase.cpp | 46 +
libs/utils/MemoryDealer.cpp | 409 ++
libs/utils/MemoryHeapBase.cpp | 183 +
libs/utils/MemoryHeapPmem.cpp | 248 +
libs/utils/NOTICE | 190 +
libs/utils/Parcel.cpp | 1377 ++++
libs/utils/Pipe.cpp | 465 ++
libs/utils/ProcessState.cpp | 398 ++
libs/utils/README | 14 +
libs/utils/RefBase.cpp | 534 ++
libs/utils/ResourceTypes.cpp | 3983 +++++++++++
libs/utils/SharedBuffer.cpp | 113 +
libs/utils/Socket.cpp | 388 ++
libs/utils/Static.cpp | 120 +
libs/utils/StopWatch.cpp | 79 +
libs/utils/String16.cpp | 609 ++
libs/utils/String8.cpp | 604 ++
libs/utils/SystemClock.cpp | 139 +
libs/utils/TextOutput.cpp | 146 +
libs/utils/Threads.cpp | 1128 +++
libs/utils/TimerProbe.cpp | 131 +
libs/utils/Timers.cpp | 240 +
libs/utils/Unicode.cpp | 193 +
libs/utils/VectorImpl.cpp | 611 ++
libs/utils/ZipEntry.cpp | 696 ++
libs/utils/ZipFile.cpp | 1296 ++++
libs/utils/ZipFileCRO.cpp | 54 +
libs/utils/ZipFileRO.cpp | 724 ++
libs/utils/ZipUtils.cpp | 344 +
libs/utils/characterData.h | 730 ++
libs/utils/executablepath_darwin.cpp | 31 +
libs/utils/executablepath_linux.cpp | 30 +
libs/utils/futex_synchro.c | 175 +
libs/utils/misc.cpp | 185 +
libs/utils/ported.cpp | 106 +
opengl/include/EGL/egl.h | 330 +
opengl/include/EGL/eglext.h | 138 +
opengl/include/EGL/eglnatives.h | 271 +
opengl/include/EGL/eglplatform.h | 117 +
opengl/include/GLES/egl.h | 15 +
opengl/include/GLES/gl.h | 769 +++
opengl/include/GLES/glext.h | 622 ++
opengl/include/GLES/glplatform.h | 39 +
opengl/include/KHR/khrplatform.h | 241 +
opengl/libagl/Android.mk | 39 +
opengl/libagl/BufferObjectManager.cpp | 103 +
opengl/libagl/BufferObjectManager.h | 85 +
opengl/libagl/TextureObjectManager.cpp | 309 +
opengl/libagl/TextureObjectManager.h | 140 +
opengl/libagl/TokenManager.cpp | 62 +
opengl/libagl/TokenManager.h | 53 +
opengl/libagl/Tokenizer.cpp | 173 +
opengl/libagl/Tokenizer.h | 59 +
opengl/libagl/array.cpp | 1557 +++++
opengl/libagl/array.h | 37 +
opengl/libagl/context.h | 20 +
opengl/libagl/dxt.cpp | 636 ++
opengl/libagl/dxt.h | 33 +
opengl/libagl/egl.cpp | 1543 +++++
opengl/libagl/fixed_asm.S | 65 +
opengl/libagl/fp.cpp | 87 +
opengl/libagl/fp.h | 243 +
opengl/libagl/iterators.S | 88 +
opengl/libagl/light.cpp | 852 +++
opengl/libagl/light.h | 38 +
opengl/libagl/matrix.cpp | 1145 ++++
opengl/libagl/matrix.h | 355 +
opengl/libagl/mipmap.cpp | 192 +
opengl/libagl/primitives.cpp | 1111 +++
opengl/libagl/primitives.h | 37 +
opengl/libagl/state.cpp | 586 ++
opengl/libagl/state.h | 54 +
opengl/libagl/texture.cpp | 1421 ++++
opengl/libagl/texture.h | 45 +
opengl/libagl/vertex.cpp | 247 +
opengl/libagl/vertex.h | 48 +
opengl/libs/Android.mk | 53 +
opengl/libs/EGL/egl.cpp | 1363 ++++
opengl/libs/EGL/gpu.cpp | 212 +
opengl/libs/GLES_CM/gl.cpp | 116 +
opengl/libs/GLES_CM/gl_api.in | 606 ++
opengl/libs/GLES_CM/gl_logger.cpp | 1060 +++
opengl/libs/egl_entries.in | 45 +
opengl/libs/egl_impl.h | 43 +
opengl/libs/gl_entries.in | 159 +
opengl/libs/gl_enums.in | 261 +
opengl/libs/gl_logger.h | 26 +
opengl/libs/hooks.h | 134 +
opengl/libs/tools/enumextract.sh | 32 +
opengl/tests/Android.mk | 1 +
opengl/tests/angeles/Android.mk | 17 +
.../tests/angeles/MODULE_LICENSE_BSD_OR_LGPL | 0
opengl/tests/angeles/README.txt | 77 +
opengl/tests/angeles/app-linux.c | 223 +
opengl/tests/angeles/app.h | 56 +
opengl/tests/angeles/cams.h | 65 +
opengl/tests/angeles/demo.c | 792 +++
opengl/tests/angeles/gpustate.c | 39 +
opengl/tests/angeles/include/GLES/egl.h | 229 +
opengl/tests/angeles/include/GLES/egltypes.h | 20 +
opengl/tests/angeles/include/GLES/gl.h | 584 ++
opengl/tests/angeles/license-BSD.txt | 34 +
opengl/tests/angeles/license-LGPL.txt | 504 ++
opengl/tests/angeles/license.txt | 19 +
opengl/tests/angeles/shapes.h | 59 +
opengl/tests/filter/Android.mk | 17 +
opengl/tests/filter/filter.c | 130 +
opengl/tests/finish/Android.mk | 17 +
opengl/tests/finish/finish.c | 224 +
opengl/tests/textures/Android.mk | 17 +
opengl/tests/textures/textures.c | 109 +
opengl/tests/tritex/Android.mk | 17 +
opengl/tests/tritex/tritex.c | 273 +
opengl/tools/glgen/gen | 99 +
opengl/tools/glgen/glspec-1.0 | 106 +
opengl/tools/glgen/glspec-1.0ext | 1 +
opengl/tools/glgen/glspec-1.1 | 42 +
opengl/tools/glgen/glspec-1.1ext | 16 +
opengl/tools/glgen/glspec-1.1extpack | 38 +
opengl/tools/glgen/glspec-checks | 59 +
opengl/tools/glgen/src/CFunc.java | 155 +
opengl/tools/glgen/src/CType.java | 85 +
opengl/tools/glgen/src/CodeEmitter.java | 8 +
opengl/tools/glgen/src/GenerateGL.java | 164 +
opengl/tools/glgen/src/JFunc.java | 148 +
opengl/tools/glgen/src/JType.java | 139 +
opengl/tools/glgen/src/JniCodeEmitter.java | 1086 +++
opengl/tools/glgen/src/ParameterChecker.java | 28 +
.../tools/glgen/stubs/GL10ExtHeader.java-if | 22 +
opengl/tools/glgen/stubs/GL10Header.java-if | 259 +
.../tools/glgen/stubs/GL11ExtHeader.java-if | 40 +
.../stubs/GL11ExtensionPackHeader.java-if | 108 +
opengl/tools/glgen/stubs/GL11Header.java-if | 145 +
.../glgen/stubs/GL11ImplHeader.java-impl | 30 +
opengl/tools/glgen/stubs/GLCHeader.cpp | 129 +
opengl/tools/glgen/stubs/GLHeader.java-if | 22 +
.../tools/glgen/stubs/GLImplHeader.java-impl | 48 +
opengl/tools/glgen/stubs/glGetString.cpp | 10 +
.../tools/glgen/stubs/glGetString.java-10-if | 4 +
opengl/tools/glgen/stubs/glGetString.java-if | 4 +
.../tools/glgen/stubs/glGetString.java-impl | 16 +
.../tools/glgen/stubs/glGetString.nativeReg | 1 +
services/Android.mk | 17 +
807 files changed, 207817 insertions(+)
create mode 100644 MODULE_LICENSE_APACHE2
create mode 100644 NOTICE
create mode 100644 awt/Android.mk
create mode 100644 awt/com/android/internal/awt/AndroidGraphics2D.java
create mode 100644 awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
create mode 100644 awt/com/android/internal/awt/AndroidGraphicsFactory.java
create mode 100644 awt/com/android/internal/awt/AndroidImageDecoder.java
create mode 100644 awt/com/android/internal/awt/AndroidJavaBlitter.java
create mode 100644 awt/com/android/internal/awt/AndroidNativeEventQueue.java
create mode 100644 awt/com/android/internal/awt/AndroidWTK.java
create mode 100644 awt/com/android/internal/awt/AwtFactory.java
create mode 100644 awt/com/android/internal/awt/ImageOutputStreamWrapper.java
create mode 100644 awt/java/awt/AWTEvent.java
create mode 100644 awt/java/awt/AWTException.java
create mode 100644 awt/java/awt/AWTKeyStroke.java
create mode 100644 awt/java/awt/AWTListenerList.java
create mode 100644 awt/java/awt/AWTPermission.java
create mode 100644 awt/java/awt/ActiveEvent.java
create mode 100644 awt/java/awt/Adjustable.java
create mode 100644 awt/java/awt/AlphaComposite.java
create mode 100644 awt/java/awt/BasicStroke.java
create mode 100644 awt/java/awt/BufferCapabilities.java
create mode 100644 awt/java/awt/Color.java
create mode 100644 awt/java/awt/Component.java
create mode 100644 awt/java/awt/ComponentBehavior.java
create mode 100644 awt/java/awt/ComponentOrientation.java
create mode 100644 awt/java/awt/Composite.java
create mode 100644 awt/java/awt/CompositeContext.java
create mode 100644 awt/java/awt/Cursor.java
create mode 100644 awt/java/awt/Dimension.java
create mode 100644 awt/java/awt/Dispatcher.java
create mode 100644 awt/java/awt/DisplayMode.java
create mode 100644 awt/java/awt/Event.java
create mode 100644 awt/java/awt/EventDispatchThread.java
create mode 100644 awt/java/awt/EventQueue.java
create mode 100644 awt/java/awt/EventQueueCore.java
create mode 100644 awt/java/awt/Font.java
create mode 100644 awt/java/awt/FontFormatException.java
create mode 100644 awt/java/awt/FontMetrics.java
create mode 100644 awt/java/awt/GradientPaint.java
create mode 100644 awt/java/awt/GradientPaintContext.java
create mode 100644 awt/java/awt/Graphics.java
create mode 100644 awt/java/awt/Graphics2D.java
create mode 100644 awt/java/awt/GraphicsConfiguration.java
create mode 100644 awt/java/awt/GraphicsDevice.java
create mode 100644 awt/java/awt/GraphicsEnvironment.java
create mode 100644 awt/java/awt/HeadlessException.java
create mode 100644 awt/java/awt/HeadlessGraphicsEnvironment.java
create mode 100644 awt/java/awt/HeadlessToolkit.java
create mode 100644 awt/java/awt/IllegalComponentStateException.java
create mode 100644 awt/java/awt/Image.java
create mode 100644 awt/java/awt/ImageCapabilities.java
create mode 100644 awt/java/awt/Insets.java
create mode 100644 awt/java/awt/ItemSelectable.java
create mode 100644 awt/java/awt/MenuComponent.java
create mode 100644 awt/java/awt/MenuContainer.java
create mode 100644 awt/java/awt/ModalContext.java
create mode 100644 awt/java/awt/MouseDispatcher.java
create mode 100644 awt/java/awt/Paint.java
create mode 100644 awt/java/awt/PaintContext.java
create mode 100644 awt/java/awt/Point.java
create mode 100644 awt/java/awt/Polygon.java
create mode 100644 awt/java/awt/Rectangle.java
create mode 100644 awt/java/awt/RenderingHints.java
create mode 100644 awt/java/awt/Shape.java
create mode 100644 awt/java/awt/Stroke.java
create mode 100644 awt/java/awt/Toolkit.java
create mode 100644 awt/java/awt/ToolkitImpl.java
create mode 100644 awt/java/awt/Transparency.java
create mode 100644 awt/java/awt/color/CMMException.java
create mode 100644 awt/java/awt/color/ColorSpace.java
create mode 100644 awt/java/awt/color/ICC_ColorSpace.java
create mode 100644 awt/java/awt/color/ICC_Profile.java
create mode 100644 awt/java/awt/color/ICC_ProfileGray.java
create mode 100644 awt/java/awt/color/ICC_ProfileRGB.java
create mode 100644 awt/java/awt/color/ICC_ProfileStub.java
create mode 100644 awt/java/awt/color/ProfileDataException.java
create mode 100644 awt/java/awt/color/package.html
create mode 100644 awt/java/awt/event/AWTEventListener.java
create mode 100644 awt/java/awt/event/AWTEventListenerProxy.java
create mode 100644 awt/java/awt/event/ActionEvent.java
create mode 100644 awt/java/awt/event/ActionListener.java
create mode 100644 awt/java/awt/event/AdjustmentEvent.java
create mode 100644 awt/java/awt/event/AdjustmentListener.java
create mode 100644 awt/java/awt/event/ComponentAdapter.java
create mode 100644 awt/java/awt/event/ComponentEvent.java
create mode 100644 awt/java/awt/event/ComponentListener.java
create mode 100644 awt/java/awt/event/ContainerAdapter.java
create mode 100644 awt/java/awt/event/ContainerEvent.java
create mode 100644 awt/java/awt/event/ContainerListener.java
create mode 100644 awt/java/awt/event/FocusAdapter.java
create mode 100644 awt/java/awt/event/FocusEvent.java
create mode 100644 awt/java/awt/event/FocusListener.java
create mode 100644 awt/java/awt/event/HierarchyBoundsAdapter.java
create mode 100644 awt/java/awt/event/HierarchyBoundsListener.java
create mode 100644 awt/java/awt/event/HierarchyEvent.java
create mode 100644 awt/java/awt/event/HierarchyListener.java
create mode 100644 awt/java/awt/event/InputEvent.java
create mode 100644 awt/java/awt/event/InputMethodEvent.java
create mode 100644 awt/java/awt/event/InputMethodListener.java
create mode 100644 awt/java/awt/event/InvocationEvent.java
create mode 100644 awt/java/awt/event/ItemEvent.java
create mode 100644 awt/java/awt/event/ItemListener.java
create mode 100644 awt/java/awt/event/KeyAdapter.java
create mode 100644 awt/java/awt/event/KeyEvent.java
create mode 100644 awt/java/awt/event/KeyListener.java
create mode 100644 awt/java/awt/event/MouseAdapter.java
create mode 100644 awt/java/awt/event/MouseEvent.java
create mode 100644 awt/java/awt/event/MouseListener.java
create mode 100644 awt/java/awt/event/MouseMotionAdapter.java
create mode 100644 awt/java/awt/event/MouseMotionListener.java
create mode 100644 awt/java/awt/event/MouseWheelEvent.java
create mode 100644 awt/java/awt/event/MouseWheelListener.java
create mode 100644 awt/java/awt/event/PaintEvent.java
create mode 100644 awt/java/awt/event/TextEvent.java
create mode 100644 awt/java/awt/event/TextListener.java
create mode 100644 awt/java/awt/event/WindowAdapter.java
create mode 100644 awt/java/awt/event/WindowEvent.java
create mode 100644 awt/java/awt/event/WindowFocusListener.java
create mode 100644 awt/java/awt/event/WindowListener.java
create mode 100644 awt/java/awt/event/WindowStateListener.java
create mode 100644 awt/java/awt/font/FontRenderContext.java
create mode 100644 awt/java/awt/font/GlyphJustificationInfo.java
create mode 100644 awt/java/awt/font/GlyphMetrics.java
create mode 100644 awt/java/awt/font/GlyphVector.java
create mode 100644 awt/java/awt/font/GraphicAttribute.java
create mode 100644 awt/java/awt/font/ImageGraphicAttribute.java
create mode 100644 awt/java/awt/font/LineBreakMeasurer.java
create mode 100644 awt/java/awt/font/LineMetrics.java
create mode 100644 awt/java/awt/font/MultipleMaster.java
create mode 100644 awt/java/awt/font/OpenType.java
create mode 100644 awt/java/awt/font/ShapeGraphicAttribute.java
create mode 100644 awt/java/awt/font/TextHitInfo.java
create mode 100644 awt/java/awt/font/TextLayout.java
create mode 100644 awt/java/awt/font/TextMeasurer.java
create mode 100644 awt/java/awt/font/TransformAttribute.java
create mode 100644 awt/java/awt/font/package.html
create mode 100644 awt/java/awt/geom/AffineTransform.java
create mode 100644 awt/java/awt/geom/Arc2D.java
create mode 100644 awt/java/awt/geom/Area.java
create mode 100644 awt/java/awt/geom/CubicCurve2D.java
create mode 100644 awt/java/awt/geom/Dimension2D.java
create mode 100644 awt/java/awt/geom/Ellipse2D.java
create mode 100644 awt/java/awt/geom/FlatteningPathIterator.java
create mode 100644 awt/java/awt/geom/GeneralPath.java
create mode 100644 awt/java/awt/geom/IllegalPathStateException.java
create mode 100644 awt/java/awt/geom/Line2D.java
create mode 100644 awt/java/awt/geom/NoninvertibleTransformException.java
create mode 100644 awt/java/awt/geom/PathIterator.java
create mode 100644 awt/java/awt/geom/Point2D.java
create mode 100644 awt/java/awt/geom/QuadCurve2D.java
create mode 100644 awt/java/awt/geom/Rectangle2D.java
create mode 100644 awt/java/awt/geom/RectangularShape.java
create mode 100644 awt/java/awt/geom/RoundRectangle2D.java
create mode 100644 awt/java/awt/geom/package.html
create mode 100644 awt/java/awt/im/InputContext.java
create mode 100644 awt/java/awt/im/InputMethodHighlight.java
create mode 100644 awt/java/awt/im/InputMethodRequests.java
create mode 100644 awt/java/awt/im/InputSubset.java
create mode 100644 awt/java/awt/im/spi/InputMethod.java
create mode 100644 awt/java/awt/im/spi/InputMethodContext.java
create mode 100644 awt/java/awt/im/spi/InputMethodDescriptor.java
create mode 100644 awt/java/awt/image/AffineTransformOp.java
create mode 100644 awt/java/awt/image/AreaAveragingScaleFilter.java
create mode 100644 awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
create mode 100644 awt/java/awt/image/BandCombineOp.java
create mode 100644 awt/java/awt/image/BandedSampleModel.java
create mode 100644 awt/java/awt/image/BufferStrategy.java
create mode 100644 awt/java/awt/image/BufferedImage.java
create mode 100644 awt/java/awt/image/BufferedImageFilter.java
create mode 100644 awt/java/awt/image/BufferedImageOp.java
create mode 100644 awt/java/awt/image/ByteLookupTable.java
create mode 100644 awt/java/awt/image/ColorConvertOp.java
create mode 100644 awt/java/awt/image/ColorModel.java
create mode 100644 awt/java/awt/image/ComponentColorModel.java
create mode 100644 awt/java/awt/image/ComponentSampleModel.java
create mode 100644 awt/java/awt/image/ConvolveOp.java
create mode 100644 awt/java/awt/image/CropImageFilter.java
create mode 100644 awt/java/awt/image/DataBuffer.java
create mode 100644 awt/java/awt/image/DataBufferByte.java
create mode 100644 awt/java/awt/image/DataBufferDouble.java
create mode 100644 awt/java/awt/image/DataBufferFloat.java
create mode 100644 awt/java/awt/image/DataBufferInt.java
create mode 100644 awt/java/awt/image/DataBufferShort.java
create mode 100644 awt/java/awt/image/DataBufferUShort.java
create mode 100644 awt/java/awt/image/DirectColorModel.java
create mode 100644 awt/java/awt/image/FilteredImageSource.java
create mode 100644 awt/java/awt/image/ImageConsumer.java
create mode 100644 awt/java/awt/image/ImageFilter.java
create mode 100644 awt/java/awt/image/ImageObserver.java
create mode 100644 awt/java/awt/image/ImageProducer.java
create mode 100644 awt/java/awt/image/ImagingOpException.java
create mode 100644 awt/java/awt/image/IndexColorModel.java
create mode 100644 awt/java/awt/image/Kernel.java
create mode 100644 awt/java/awt/image/LookupOp.java
create mode 100644 awt/java/awt/image/LookupTable.java
create mode 100644 awt/java/awt/image/MemoryImageSource.java
create mode 100644 awt/java/awt/image/MultiPixelPackedSampleModel.java
create mode 100644 awt/java/awt/image/PackedColorModel.java
create mode 100644 awt/java/awt/image/PixelGrabber.java
create mode 100644 awt/java/awt/image/PixelInterleavedSampleModel.java
create mode 100644 awt/java/awt/image/RGBImageFilter.java
create mode 100644 awt/java/awt/image/Raster.java
create mode 100644 awt/java/awt/image/RasterFormatException.java
create mode 100644 awt/java/awt/image/RasterOp.java
create mode 100644 awt/java/awt/image/RenderedImage.java
create mode 100644 awt/java/awt/image/ReplicateScaleFilter.java
create mode 100644 awt/java/awt/image/RescaleOp.java
create mode 100644 awt/java/awt/image/SampleModel.java
create mode 100644 awt/java/awt/image/ShortLookupTable.java
create mode 100644 awt/java/awt/image/SinglePixelPackedSampleModel.java
create mode 100644 awt/java/awt/image/TileObserver.java
create mode 100644 awt/java/awt/image/VolatileImage.java
create mode 100644 awt/java/awt/image/WritableRaster.java
create mode 100644 awt/java/awt/image/WritableRenderedImage.java
create mode 100644 awt/java/awt/image/package.html
create mode 100644 awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
create mode 100644 awt/java/awt/image/renderable/ParameterBlock.java
create mode 100644 awt/java/awt/image/renderable/RenderContext.java
create mode 100644 awt/java/awt/image/renderable/RenderableImage.java
create mode 100644 awt/java/awt/image/renderable/RenderableImageOp.java
create mode 100644 awt/java/awt/image/renderable/RenderableImageProducer.java
create mode 100644 awt/java/awt/image/renderable/RenderedImageFactory.java
create mode 100644 awt/java/awt/image/renderable/package.html
create mode 100644 awt/java/awt/package.html
create mode 100644 awt/java/awt/peer/ButtonPeer.java
create mode 100644 awt/java/awt/peer/CanvasPeer.java
create mode 100644 awt/java/awt/peer/CheckboxMenuItemPeer.java
create mode 100644 awt/java/awt/peer/CheckboxPeer.java
create mode 100644 awt/java/awt/peer/ChoicePeer.java
create mode 100644 awt/java/awt/peer/ComponentPeer.java
create mode 100644 awt/java/awt/peer/DialogPeer.java
create mode 100644 awt/java/awt/peer/FileDialogPeer.java
create mode 100644 awt/java/awt/peer/FontPeer.java
create mode 100644 awt/java/awt/peer/FramePeer.java
create mode 100644 awt/java/awt/peer/LabelPeer.java
create mode 100644 awt/java/awt/peer/LightweightPeer.java
create mode 100644 awt/java/awt/peer/ListPeer.java
create mode 100644 awt/java/awt/peer/MenuBarPeer.java
create mode 100644 awt/java/awt/peer/MenuComponentPeer.java
create mode 100644 awt/java/awt/peer/MenuItemPeer.java
create mode 100644 awt/java/awt/peer/MenuPeer.java
create mode 100644 awt/java/awt/peer/MouseInfoPeer.java
create mode 100644 awt/java/awt/peer/PanelPeer.java
create mode 100644 awt/java/awt/peer/PopupMenuPeer.java
create mode 100644 awt/java/awt/peer/ScrollPanePeer.java
create mode 100644 awt/java/awt/peer/ScrollbarPeer.java
create mode 100644 awt/java/awt/peer/TextAreaPeer.java
create mode 100644 awt/java/awt/peer/TextFieldPeer.java
create mode 100644 awt/java/awt/peer/WindowPeer.java
create mode 100644 awt/java/beans/FeatureDescriptor.java
create mode 100644 awt/java/beans/IndexedPropertyDescriptor.java
create mode 100644 awt/java/beans/IntrospectionException.java
create mode 100644 awt/java/beans/PropertyDescriptor.java
create mode 100644 awt/java/beans/PropertyEditor.java
create mode 100644 awt/java/beans/PropertyEditorManager.java
create mode 100644 awt/java/beans/PropertyEditorSupport.java
create mode 100644 awt/java/beans/PropertyVetoException.java
create mode 100644 awt/javax/imageio/IIOException.java
create mode 100644 awt/javax/imageio/IIOImage.java
create mode 100644 awt/javax/imageio/IIOParam.java
create mode 100644 awt/javax/imageio/IIOParamController.java
create mode 100644 awt/javax/imageio/ImageIO.java
create mode 100644 awt/javax/imageio/ImageReadParam.java
create mode 100644 awt/javax/imageio/ImageReader.java
create mode 100644 awt/javax/imageio/ImageTranscoder.java
create mode 100644 awt/javax/imageio/ImageTypeSpecifier.java
create mode 100644 awt/javax/imageio/ImageWriteParam.java
create mode 100644 awt/javax/imageio/ImageWriter.java
create mode 100644 awt/javax/imageio/event/IIOReadProgressListener.java
create mode 100644 awt/javax/imageio/event/IIOReadUpdateListener.java
create mode 100644 awt/javax/imageio/event/IIOReadWarningListener.java
create mode 100644 awt/javax/imageio/event/IIOWriteProgressListener.java
create mode 100644 awt/javax/imageio/event/IIOWriteWarningListener.java
create mode 100644 awt/javax/imageio/event/package.html
create mode 100644 awt/javax/imageio/metadata/IIOInvalidTreeException.java
create mode 100644 awt/javax/imageio/metadata/IIOMetadata.java
create mode 100644 awt/javax/imageio/metadata/IIOMetadataController.java
create mode 100644 awt/javax/imageio/metadata/IIOMetadataFormat.java
create mode 100644 awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
create mode 100644 awt/javax/imageio/metadata/IIOMetadataNode.java
create mode 100644 awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
create mode 100644 awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
create mode 100644 awt/javax/imageio/metadata/package.html
create mode 100644 awt/javax/imageio/package.html
create mode 100644 awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
create mode 100644 awt/javax/imageio/plugins/bmp/package.html
create mode 100644 awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
create mode 100644 awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
create mode 100644 awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
create mode 100644 awt/javax/imageio/plugins/jpeg/JPEGQTable.java
create mode 100644 awt/javax/imageio/plugins/jpeg/package.html
create mode 100644 awt/javax/imageio/spi/IIORegistry.java
create mode 100644 awt/javax/imageio/spi/IIOServiceProvider.java
create mode 100644 awt/javax/imageio/spi/ImageInputStreamSpi.java
create mode 100644 awt/javax/imageio/spi/ImageOutputStreamSpi.java
create mode 100644 awt/javax/imageio/spi/ImageReaderSpi.java
create mode 100644 awt/javax/imageio/spi/ImageReaderWriterSpi.java
create mode 100644 awt/javax/imageio/spi/ImageTranscoderSpi.java
create mode 100644 awt/javax/imageio/spi/ImageWriterSpi.java
create mode 100644 awt/javax/imageio/spi/RegisterableService.java
create mode 100644 awt/javax/imageio/spi/ServiceRegistry.java
create mode 100644 awt/javax/imageio/spi/package.html
create mode 100644 awt/javax/imageio/stream/FileCacheImageInputStream.java
create mode 100644 awt/javax/imageio/stream/FileCacheImageOutputStream.java
create mode 100644 awt/javax/imageio/stream/FileImageInputStream.java
create mode 100644 awt/javax/imageio/stream/FileImageOutputStream.java
create mode 100644 awt/javax/imageio/stream/IIOByteBuffer.java
create mode 100644 awt/javax/imageio/stream/ImageInputStream.java
create mode 100644 awt/javax/imageio/stream/ImageInputStreamImpl.java
create mode 100644 awt/javax/imageio/stream/ImageOutputStream.java
create mode 100644 awt/javax/imageio/stream/ImageOutputStreamImpl.java
create mode 100644 awt/javax/imageio/stream/MemoryCacheImageInputStream.java
create mode 100644 awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
create mode 100644 awt/javax/imageio/stream/package.html
create mode 100644 awt/org/apache/harmony/awt/ChoiceStyle.java
create mode 100644 awt/org/apache/harmony/awt/ClipRegion.java
create mode 100644 awt/org/apache/harmony/awt/ComponentInternals.java
create mode 100644 awt/org/apache/harmony/awt/ContextStorage.java
create mode 100644 awt/org/apache/harmony/awt/ContextThreadGroup.java
create mode 100644 awt/org/apache/harmony/awt/ListenerList.java
create mode 100644 awt/org/apache/harmony/awt/ReadOnlyIterator.java
create mode 100644 awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
create mode 100644 awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
create mode 100644 awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
create mode 100644 awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
create mode 100644 awt/org/apache/harmony/awt/gl/Crossing.java
create mode 100644 awt/org/apache/harmony/awt/gl/GLVolatileImage.java
create mode 100644 awt/org/apache/harmony/awt/gl/ICompositeContext.java
create mode 100644 awt/org/apache/harmony/awt/gl/ImageSurface.java
create mode 100644 awt/org/apache/harmony/awt/gl/MultiRectArea.java
create mode 100644 awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
create mode 100644 awt/org/apache/harmony/awt/gl/Surface.java
create mode 100644 awt/org/apache/harmony/awt/gl/TextRenderer.java
create mode 100644 awt/org/apache/harmony/awt/gl/XORComposite.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/ColorConverter.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/ColorScaler.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/NativeCMM.java
create mode 100644 awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/AndroidFont.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/CaretManager.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/CompositeFont.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/FontFinder.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/FontManager.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/FontProperty.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/Glyph.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/TextDecorator.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
create mode 100644 awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/GifDecoder.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/ImageLoader.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/PngDecoder.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
create mode 100644 awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/Blitter.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
create mode 100644 awt/org/apache/harmony/awt/gl/render/NullBlitter.java
create mode 100644 awt/org/apache/harmony/awt/im/InputMethodContext.java
create mode 100644 awt/org/apache/harmony/awt/internal/nls/Messages.java
create mode 100644 awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
create mode 100644 awt/org/apache/harmony/awt/state/MenuItemState.java
create mode 100644 awt/org/apache/harmony/awt/state/MenuState.java
create mode 100644 awt/org/apache/harmony/awt/state/State.java
create mode 100644 awt/org/apache/harmony/awt/wtk/CreationParams.java
create mode 100644 awt/org/apache/harmony/awt/wtk/CursorFactory.java
create mode 100644 awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
create mode 100644 awt/org/apache/harmony/awt/wtk/KeyInfo.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeCursor.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeEvent.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeEventThread.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeIM.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeRobot.java
create mode 100644 awt/org/apache/harmony/awt/wtk/NativeWindow.java
create mode 100644 awt/org/apache/harmony/awt/wtk/ShutdownThread.java
create mode 100644 awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
create mode 100644 awt/org/apache/harmony/awt/wtk/Synchronizer.java
create mode 100644 awt/org/apache/harmony/awt/wtk/SystemProperties.java
create mode 100644 awt/org/apache/harmony/awt/wtk/WTK.java
create mode 100644 awt/org/apache/harmony/awt/wtk/WindowFactory.java
create mode 100644 awt/org/apache/harmony/beans/internal/nls/Messages.java
create mode 100644 awt/org/apache/harmony/beans/internal/nls/MsgHelp.java
create mode 100644 awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
create mode 100644 awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
create mode 100644 awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
create mode 100644 awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
create mode 100644 awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
create mode 100644 awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
create mode 100644 awt/resources/org/apache/harmony/beans/internals/nls/messages.properties
create mode 100644 camera/libcameraservice/Android.mk
create mode 100644 camera/libcameraservice/CameraHardwareStub.cpp
create mode 100644 camera/libcameraservice/CameraHardwareStub.h
create mode 100644 camera/libcameraservice/CameraService.cpp
create mode 100644 camera/libcameraservice/CameraService.h
create mode 100644 camera/libcameraservice/CannedJpeg.h
create mode 100644 camera/libcameraservice/FakeCamera.cpp
create mode 100644 camera/libcameraservice/FakeCamera.h
create mode 100644 cmds/runtime/Android.mk
create mode 100644 cmds/runtime/MODULE_LICENSE_APACHE2
create mode 100644 cmds/runtime/NOTICE
create mode 100644 cmds/runtime/ServiceManager.cpp
create mode 100644 cmds/runtime/ServiceManager.h
create mode 100644 cmds/runtime/SignalHandler.cpp
create mode 100644 cmds/runtime/SignalHandler.h
create mode 100644 cmds/runtime/main_runtime.cpp
create mode 100644 cmds/surfaceflinger/Android.mk
create mode 100644 cmds/surfaceflinger/main_surfaceflinger.cpp
create mode 100644 im/java/android/im/BrandingResourceIDs.java
create mode 100644 im/java/android/im/IImPlugin.aidl
create mode 100644 im/java/android/im/ImPluginConsts.java
create mode 100644 include/pim/EventRecurrence.h
create mode 100644 include/private/opengles/gl_context.h
create mode 100644 include/private/ui/LayerState.h
create mode 100644 include/private/ui/SharedState.h
create mode 100644 include/private/ui/SurfaceFlingerSynchro.h
create mode 100644 include/private/utils/Static.h
create mode 100644 include/private/utils/binder_module.h
create mode 100644 include/private/utils/futex_synchro.h
create mode 100644 include/ui/Camera.h
create mode 100644 include/ui/CameraHardwareInterface.h
create mode 100644 include/ui/CameraParameters.h
create mode 100644 include/ui/DisplayInfo.h
create mode 100644 include/ui/EGLDisplaySurface.h
create mode 100644 include/ui/EGLNativeSurface.h
create mode 100644 include/ui/EGLNativeWindowSurface.h
create mode 100644 include/ui/EventHub.h
create mode 100644 include/ui/ICamera.h
create mode 100644 include/ui/ICameraClient.h
create mode 100644 include/ui/ICameraService.h
create mode 100644 include/ui/IOverlay.h
create mode 100644 include/ui/ISurface.h
create mode 100644 include/ui/ISurfaceComposer.h
create mode 100644 include/ui/ISurfaceFlingerClient.h
create mode 100644 include/ui/KeyCharacterMap.h
create mode 100644 include/ui/KeycodeLabels.h
create mode 100644 include/ui/Overlay.h
create mode 100644 include/ui/PixelFormat.h
create mode 100644 include/ui/Point.h
create mode 100644 include/ui/Rect.h
create mode 100644 include/ui/Region.h
create mode 100644 include/ui/Surface.h
create mode 100644 include/ui/SurfaceComposerClient.h
create mode 100644 include/utils.h
create mode 100644 include/utils/AndroidUnicode.h
create mode 100644 include/utils/Asset.h
create mode 100644 include/utils/AssetDir.h
create mode 100644 include/utils/AssetManager.h
create mode 100644 include/utils/Atomic.h
create mode 100644 include/utils/Binder.h
create mode 100644 include/utils/BpBinder.h
create mode 100644 include/utils/Buffer.h
create mode 100644 include/utils/BufferedTextOutput.h
create mode 100644 include/utils/ByteOrder.h
create mode 100644 include/utils/CallStack.h
create mode 100644 include/utils/Debug.h
create mode 100644 include/utils/Endian.h
create mode 100644 include/utils/Errors.h
create mode 100644 include/utils/FileMap.h
create mode 100644 include/utils/IBinder.h
create mode 100644 include/utils/IInterface.h
create mode 100644 include/utils/IMemory.h
create mode 100644 include/utils/IPCThreadState.h
create mode 100644 include/utils/IPermissionController.h
create mode 100644 include/utils/IServiceManager.h
create mode 100644 include/utils/KeyedVector.h
create mode 100644 include/utils/List.h
create mode 100644 include/utils/Log.h
create mode 100644 include/utils/LogSocket.h
create mode 100644 include/utils/MemoryBase.h
create mode 100644 include/utils/MemoryDealer.h
create mode 100644 include/utils/MemoryHeapBase.h
create mode 100644 include/utils/MemoryHeapPmem.h
create mode 100644 include/utils/Parcel.h
create mode 100644 include/utils/Pipe.h
create mode 100644 include/utils/ProcessState.h
create mode 100644 include/utils/RefBase.h
create mode 100644 include/utils/ResourceTypes.h
create mode 100644 include/utils/SharedBuffer.h
create mode 100644 include/utils/Socket.h
create mode 100644 include/utils/SortedVector.h
create mode 100644 include/utils/StopWatch.h
create mode 100644 include/utils/String16.h
create mode 100644 include/utils/String8.h
create mode 100644 include/utils/SystemClock.h
create mode 100644 include/utils/TextOutput.h
create mode 100644 include/utils/TimeUtils.h
create mode 100644 include/utils/TimerProbe.h
create mode 100644 include/utils/Timers.h
create mode 100644 include/utils/TypeHelpers.h
create mode 100644 include/utils/Vector.h
create mode 100644 include/utils/VectorImpl.h
create mode 100644 include/utils/ZipEntry.h
create mode 100644 include/utils/ZipFile.h
create mode 100644 include/utils/ZipFileCRO.h
create mode 100644 include/utils/ZipFileRO.h
create mode 100644 include/utils/ZipUtils.h
create mode 100644 include/utils/ashmem.h
create mode 100644 include/utils/executablepath.h
create mode 100644 include/utils/inet_address.h
create mode 100644 include/utils/misc.h
create mode 100644 include/utils/ported.h
create mode 100644 include/utils/string_array.h
create mode 100644 include/utils/threads.h
create mode 100644 libs/audioflinger/A2dpAudioInterface.cpp
create mode 100644 libs/audioflinger/A2dpAudioInterface.h
create mode 100644 libs/audioflinger/Android.mk
create mode 100644 libs/audioflinger/AudioBufferProvider.h
create mode 100644 libs/audioflinger/AudioDumpInterface.cpp
create mode 100644 libs/audioflinger/AudioDumpInterface.h
create mode 100644 libs/audioflinger/AudioFlinger.cpp
create mode 100644 libs/audioflinger/AudioFlinger.h
create mode 100644 libs/audioflinger/AudioHardwareGeneric.cpp
create mode 100644 libs/audioflinger/AudioHardwareGeneric.h
create mode 100644 libs/audioflinger/AudioHardwareInterface.cpp
create mode 100644 libs/audioflinger/AudioHardwareStub.cpp
create mode 100644 libs/audioflinger/AudioHardwareStub.h
create mode 100644 libs/audioflinger/AudioMixer.cpp
create mode 100644 libs/audioflinger/AudioMixer.h
create mode 100644 libs/audioflinger/AudioResampler.cpp
create mode 100644 libs/audioflinger/AudioResampler.h
create mode 100644 libs/audioflinger/AudioResamplerCubic.cpp
create mode 100644 libs/audioflinger/AudioResamplerCubic.h
create mode 100644 libs/audioflinger/AudioResamplerSinc.cpp
create mode 100644 libs/audioflinger/AudioResamplerSinc.h
create mode 100644 libs/surfaceflinger/Android.mk
create mode 100644 libs/surfaceflinger/Barrier.h
create mode 100644 libs/surfaceflinger/BlurFilter.cpp
create mode 100644 libs/surfaceflinger/BlurFilter.h
create mode 100644 libs/surfaceflinger/BootAnimation.cpp
create mode 100644 libs/surfaceflinger/BootAnimation.h
create mode 100644 libs/surfaceflinger/CPUGauge.cpp
create mode 100644 libs/surfaceflinger/CPUGauge.h
create mode 100644 libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
create mode 100644 libs/surfaceflinger/DisplayHardware/DisplayHardware.h
create mode 100644 libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
create mode 100644 libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
create mode 100644 libs/surfaceflinger/GPUHardware/GPUHardware.cpp
create mode 100644 libs/surfaceflinger/GPUHardware/GPUHardware.h
create mode 100644 libs/surfaceflinger/Layer.cpp
create mode 100644 libs/surfaceflinger/Layer.h
create mode 100644 libs/surfaceflinger/LayerBase.cpp
create mode 100644 libs/surfaceflinger/LayerBase.h
create mode 100644 libs/surfaceflinger/LayerBitmap.cpp
create mode 100644 libs/surfaceflinger/LayerBitmap.h
create mode 100644 libs/surfaceflinger/LayerBlur.cpp
create mode 100644 libs/surfaceflinger/LayerBlur.h
create mode 100644 libs/surfaceflinger/LayerBuffer.cpp
create mode 100644 libs/surfaceflinger/LayerBuffer.h
create mode 100644 libs/surfaceflinger/LayerDim.cpp
create mode 100644 libs/surfaceflinger/LayerDim.h
create mode 100644 libs/surfaceflinger/LayerOrientationAnim.cpp
create mode 100644 libs/surfaceflinger/LayerOrientationAnim.h
create mode 100644 libs/surfaceflinger/MODULE_LICENSE_APACHE2
create mode 100644 libs/surfaceflinger/OrientationAnimation.cpp
create mode 100644 libs/surfaceflinger/OrientationAnimation.h
create mode 100644 libs/surfaceflinger/SurfaceFlinger.cpp
create mode 100644 libs/surfaceflinger/SurfaceFlinger.h
create mode 100644 libs/surfaceflinger/Tokenizer.cpp
create mode 100644 libs/surfaceflinger/Tokenizer.h
create mode 100644 libs/surfaceflinger/Transform.cpp
create mode 100644 libs/surfaceflinger/Transform.h
create mode 100644 libs/surfaceflinger/VRamHeap.cpp
create mode 100644 libs/surfaceflinger/VRamHeap.h
create mode 100644 libs/surfaceflinger/clz.cpp
create mode 100644 libs/surfaceflinger/clz.h
create mode 100644 libs/surfaceflinger/tests/Android.mk
create mode 100644 libs/surfaceflinger/tests/overlays/Android.mk
create mode 100644 libs/surfaceflinger/tests/overlays/overlays.cpp
create mode 100644 libs/ui/Android.mk
create mode 100644 libs/ui/Camera.cpp
create mode 100644 libs/ui/CameraParameters.cpp
create mode 100644 libs/ui/EGLDisplaySurface.cpp
create mode 100644 libs/ui/EGLNativeWindowSurface.cpp
create mode 100644 libs/ui/EventHub.cpp
create mode 100644 libs/ui/EventRecurrence.cpp
create mode 100644 libs/ui/ICamera.cpp
create mode 100644 libs/ui/ICameraClient.cpp
create mode 100644 libs/ui/ICameraService.cpp
create mode 100644 libs/ui/IOverlay.cpp
create mode 100644 libs/ui/ISurface.cpp
create mode 100644 libs/ui/ISurfaceComposer.cpp
create mode 100644 libs/ui/ISurfaceFlingerClient.cpp
create mode 100644 libs/ui/KeyCharacterMap.cpp
create mode 100644 libs/ui/KeyLayoutMap.cpp
create mode 100644 libs/ui/KeyLayoutMap.h
create mode 100644 libs/ui/LayerState.cpp
create mode 100644 libs/ui/MODULE_LICENSE_APACHE2
create mode 100644 libs/ui/NOTICE
create mode 100644 libs/ui/Overlay.cpp
create mode 100644 libs/ui/PixelFormat.cpp
create mode 100644 libs/ui/Point.cpp
create mode 100644 libs/ui/Rect.cpp
create mode 100644 libs/ui/Region.cpp
create mode 100644 libs/ui/Surface.cpp
create mode 100644 libs/ui/SurfaceComposerClient.cpp
create mode 100644 libs/ui/SurfaceFlingerSynchro.cpp
create mode 100644 libs/ui/Time.cpp
create mode 100644 libs/utils/Android.mk
create mode 100644 libs/utils/Asset.cpp
create mode 100644 libs/utils/AssetDir.cpp
create mode 100644 libs/utils/AssetManager.cpp
create mode 100644 libs/utils/Binder.cpp
create mode 100644 libs/utils/BpBinder.cpp
create mode 100644 libs/utils/BufferedTextOutput.cpp
create mode 100644 libs/utils/CallStack.cpp
create mode 100644 libs/utils/Debug.cpp
create mode 100644 libs/utils/FileMap.cpp
create mode 100644 libs/utils/IDataConnection.cpp
create mode 100644 libs/utils/IInterface.cpp
create mode 100644 libs/utils/IMemory.cpp
create mode 100644 libs/utils/IPCThreadState.cpp
create mode 100644 libs/utils/IPermissionController.cpp
create mode 100644 libs/utils/IServiceManager.cpp
create mode 100644 libs/utils/InetAddress.cpp
create mode 100644 libs/utils/LogSocket.cpp
create mode 100644 libs/utils/MODULE_LICENSE_APACHE2
create mode 100644 libs/utils/MemoryBase.cpp
create mode 100644 libs/utils/MemoryDealer.cpp
create mode 100644 libs/utils/MemoryHeapBase.cpp
create mode 100644 libs/utils/MemoryHeapPmem.cpp
create mode 100644 libs/utils/NOTICE
create mode 100644 libs/utils/Parcel.cpp
create mode 100644 libs/utils/Pipe.cpp
create mode 100644 libs/utils/ProcessState.cpp
create mode 100644 libs/utils/README
create mode 100644 libs/utils/RefBase.cpp
create mode 100644 libs/utils/ResourceTypes.cpp
create mode 100644 libs/utils/SharedBuffer.cpp
create mode 100644 libs/utils/Socket.cpp
create mode 100644 libs/utils/Static.cpp
create mode 100644 libs/utils/StopWatch.cpp
create mode 100644 libs/utils/String16.cpp
create mode 100644 libs/utils/String8.cpp
create mode 100644 libs/utils/SystemClock.cpp
create mode 100644 libs/utils/TextOutput.cpp
create mode 100644 libs/utils/Threads.cpp
create mode 100644 libs/utils/TimerProbe.cpp
create mode 100644 libs/utils/Timers.cpp
create mode 100644 libs/utils/Unicode.cpp
create mode 100644 libs/utils/VectorImpl.cpp
create mode 100644 libs/utils/ZipEntry.cpp
create mode 100644 libs/utils/ZipFile.cpp
create mode 100644 libs/utils/ZipFileCRO.cpp
create mode 100644 libs/utils/ZipFileRO.cpp
create mode 100644 libs/utils/ZipUtils.cpp
create mode 100644 libs/utils/characterData.h
create mode 100644 libs/utils/executablepath_darwin.cpp
create mode 100644 libs/utils/executablepath_linux.cpp
create mode 100644 libs/utils/futex_synchro.c
create mode 100644 libs/utils/misc.cpp
create mode 100644 libs/utils/ported.cpp
create mode 100644 opengl/include/EGL/egl.h
create mode 100644 opengl/include/EGL/eglext.h
create mode 100644 opengl/include/EGL/eglnatives.h
create mode 100644 opengl/include/EGL/eglplatform.h
create mode 100644 opengl/include/GLES/egl.h
create mode 100644 opengl/include/GLES/gl.h
create mode 100644 opengl/include/GLES/glext.h
create mode 100644 opengl/include/GLES/glplatform.h
create mode 100644 opengl/include/KHR/khrplatform.h
create mode 100644 opengl/libagl/Android.mk
create mode 100644 opengl/libagl/BufferObjectManager.cpp
create mode 100644 opengl/libagl/BufferObjectManager.h
create mode 100644 opengl/libagl/TextureObjectManager.cpp
create mode 100644 opengl/libagl/TextureObjectManager.h
create mode 100644 opengl/libagl/TokenManager.cpp
create mode 100644 opengl/libagl/TokenManager.h
create mode 100644 opengl/libagl/Tokenizer.cpp
create mode 100644 opengl/libagl/Tokenizer.h
create mode 100644 opengl/libagl/array.cpp
create mode 100644 opengl/libagl/array.h
create mode 100644 opengl/libagl/context.h
create mode 100644 opengl/libagl/dxt.cpp
create mode 100644 opengl/libagl/dxt.h
create mode 100644 opengl/libagl/egl.cpp
create mode 100644 opengl/libagl/fixed_asm.S
create mode 100644 opengl/libagl/fp.cpp
create mode 100644 opengl/libagl/fp.h
create mode 100644 opengl/libagl/iterators.S
create mode 100644 opengl/libagl/light.cpp
create mode 100644 opengl/libagl/light.h
create mode 100644 opengl/libagl/matrix.cpp
create mode 100644 opengl/libagl/matrix.h
create mode 100644 opengl/libagl/mipmap.cpp
create mode 100644 opengl/libagl/primitives.cpp
create mode 100644 opengl/libagl/primitives.h
create mode 100644 opengl/libagl/state.cpp
create mode 100644 opengl/libagl/state.h
create mode 100644 opengl/libagl/texture.cpp
create mode 100644 opengl/libagl/texture.h
create mode 100644 opengl/libagl/vertex.cpp
create mode 100644 opengl/libagl/vertex.h
create mode 100644 opengl/libs/Android.mk
create mode 100644 opengl/libs/EGL/egl.cpp
create mode 100644 opengl/libs/EGL/gpu.cpp
create mode 100644 opengl/libs/GLES_CM/gl.cpp
create mode 100644 opengl/libs/GLES_CM/gl_api.in
create mode 100644 opengl/libs/GLES_CM/gl_logger.cpp
create mode 100644 opengl/libs/egl_entries.in
create mode 100644 opengl/libs/egl_impl.h
create mode 100644 opengl/libs/gl_entries.in
create mode 100644 opengl/libs/gl_enums.in
create mode 100644 opengl/libs/gl_logger.h
create mode 100644 opengl/libs/hooks.h
create mode 100644 opengl/libs/tools/enumextract.sh
create mode 100644 opengl/tests/Android.mk
create mode 100644 opengl/tests/angeles/Android.mk
create mode 100644 opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL
create mode 100644 opengl/tests/angeles/README.txt
create mode 100644 opengl/tests/angeles/app-linux.c
create mode 100644 opengl/tests/angeles/app.h
create mode 100644 opengl/tests/angeles/cams.h
create mode 100644 opengl/tests/angeles/demo.c
create mode 100644 opengl/tests/angeles/gpustate.c
create mode 100644 opengl/tests/angeles/include/GLES/egl.h
create mode 100644 opengl/tests/angeles/include/GLES/egltypes.h
create mode 100644 opengl/tests/angeles/include/GLES/gl.h
create mode 100644 opengl/tests/angeles/license-BSD.txt
create mode 100644 opengl/tests/angeles/license-LGPL.txt
create mode 100644 opengl/tests/angeles/license.txt
create mode 100644 opengl/tests/angeles/shapes.h
create mode 100644 opengl/tests/filter/Android.mk
create mode 100644 opengl/tests/filter/filter.c
create mode 100644 opengl/tests/finish/Android.mk
create mode 100644 opengl/tests/finish/finish.c
create mode 100644 opengl/tests/textures/Android.mk
create mode 100644 opengl/tests/textures/textures.c
create mode 100644 opengl/tests/tritex/Android.mk
create mode 100644 opengl/tests/tritex/tritex.c
create mode 100755 opengl/tools/glgen/gen
create mode 100644 opengl/tools/glgen/glspec-1.0
create mode 100644 opengl/tools/glgen/glspec-1.0ext
create mode 100644 opengl/tools/glgen/glspec-1.1
create mode 100644 opengl/tools/glgen/glspec-1.1ext
create mode 100644 opengl/tools/glgen/glspec-1.1extpack
create mode 100644 opengl/tools/glgen/glspec-checks
create mode 100644 opengl/tools/glgen/src/CFunc.java
create mode 100644 opengl/tools/glgen/src/CType.java
create mode 100644 opengl/tools/glgen/src/CodeEmitter.java
create mode 100644 opengl/tools/glgen/src/GenerateGL.java
create mode 100644 opengl/tools/glgen/src/JFunc.java
create mode 100644 opengl/tools/glgen/src/JType.java
create mode 100644 opengl/tools/glgen/src/JniCodeEmitter.java
create mode 100644 opengl/tools/glgen/src/ParameterChecker.java
create mode 100644 opengl/tools/glgen/stubs/GL10ExtHeader.java-if
create mode 100644 opengl/tools/glgen/stubs/GL10Header.java-if
create mode 100644 opengl/tools/glgen/stubs/GL11ExtHeader.java-if
create mode 100644 opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if
create mode 100644 opengl/tools/glgen/stubs/GL11Header.java-if
create mode 100644 opengl/tools/glgen/stubs/GL11ImplHeader.java-impl
create mode 100644 opengl/tools/glgen/stubs/GLCHeader.cpp
create mode 100644 opengl/tools/glgen/stubs/GLHeader.java-if
create mode 100644 opengl/tools/glgen/stubs/GLImplHeader.java-impl
create mode 100644 opengl/tools/glgen/stubs/glGetString.cpp
create mode 100644 opengl/tools/glgen/stubs/glGetString.java-10-if
create mode 100644 opengl/tools/glgen/stubs/glGetString.java-if
create mode 100644 opengl/tools/glgen/stubs/glGetString.java-impl
create mode 100644 opengl/tools/glgen/stubs/glGetString.nativeReg
create mode 100644 services/Android.mk
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000..e69de29bb
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 000000000..267a6aafd
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,222 @@
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Android-specific code. ==
+ =========================================================================
+
+Android Code
+Copyright 2005-2008 The Android Open Source Project
+
+This product includes software developed as part of
+The Android Open Source Project (http://source.android.com).
+
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for Apache Commons code. ==
+ =========================================================================
+
+Apache Commons
+Copyright 1999-2004 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for Jakarta Commons Logging. ==
+ =========================================================================
+
+Jakarta Commons Logging (JCL)
+Copyright 2005,2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Nuance code. ==
+ =========================================================================
+
+These files are Copyright 2007 Nuance Communications, but released under
+the Apache2 License.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/awt/Android.mk b/awt/Android.mk
new file mode 100644
index 000000000..c7480f53a
--- /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 000000000..9a8ae02a1
--- /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 000000000..0c888cd2d
--- /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 000000000..ca255b559
--- /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 000000000..81b2e1a8c
--- /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
+ * On the other hand, the following do not affect equality: the
+ * ownerDocument, baseURI, and parentNode attributes, the specified
+ * attribute for Attr nodes, the schemaTypeInfo attribute for Attr and
+ * Element nodes, the Text.isElementContentWhitespace attribute for Text
+ * nodes, as well as any user data or event listeners registered on the
+ * nodes.
+ *
+ * Note: As a general rule, anything not mentioned in the description above
+ * is not significant in consideration of equality checking. Note that
+ * future versions of this specification may take into account more
+ * attributes and implementations conform to this specification are expected
+ * to be updated accordingly.
+ *
+ *
+ * @param arg
+ * the node to compare equality with.
+ * @return true, if the nodes are equal, false otherwise.
+ */
+ public boolean isEqualNode(Node arg) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ /**
+ * Description copied from interface: org.w3c.dom.Node (DOM Level 3)
+ *
+ * This method returns a specialized object which implements the specialized
+ * APIs of the specified feature and version, as specified in. The
+ * specialized object may also be obtained by using binding-specific casting
+ * methods but is not necessarily expected to, as discussed in. This method
+ * also allow the implementation to provide specialized objects which do not
+ * support the Node interface.
+ *
+ *
+ * @param feature
+ * the name of the feature requested. Note that any plus sign "+"
+ * prepended to the name of the feature will be ignored since it
+ * is not significant in the context of this method.
+ * @param version
+ * this is the version number of the feature to test.
+ * @return the object which implements the specialized APIs of the specified
+ * feature and version, if any, or null if there is no object which
+ * implements interfaces associated with that feature. If the
+ * DOMObject returned by this method implements the Node interface,
+ * it must delegate to the primary core Node and not return results
+ * inconsistent with the primary core Node such as attributes,
+ * childNodes, etc.
+ */
+ 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"); }
+ */
+
+ /**
+ * Description copied from interface: org.w3c.dom.Node (DOM Level 3)
+ *
+ * Retrieves the object associated to a key on a this node. The object must
+ * first have been set to this node by calling setUserData with the same
+ * key.
+ *
+ *
+ * @param key
+ * the key the object is associated to.
+ * @return the DOMUserData associated to the given key on this node, or null
+ * if there was none.
+ */
+ 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;
+ }
+
+ /**
+ * @return
+ */
+ 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 list;
+
+ /**
+ * Instantiates a new iIO metadata node list.
+ *
+ * @param list
+ * the list.
+ */
+ IIOMetadataNodeList(List 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 000000000..706cb2f7a
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.
+ *
+ * @since Android 1.0
+ */
+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 values = new ArrayList(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(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(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(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(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(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(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 000000000..d18580898
--- /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/metadata/package.html b/awt/javax/imageio/metadata/package.html
new file mode 100644
index 000000000..29bd51b2c
--- /dev/null
+++ b/awt/javax/imageio/metadata/package.html
@@ -0,0 +1,8 @@
+
+
+
+ This package contains classes which allows to read and write describing metadata of image files.
+
+ This package contains classes and interfaces which provides an Image I/O API. The contained classes and interfaces allow reading and writing image files of different formats.
+
+ @since Android 1.0
+
+
diff --git a/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
new file mode 100644
index 000000000..ecfb20ad3
--- /dev/null
+++ b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.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.
+ */
+
+package javax.imageio.plugins.bmp;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The BMPImageWriteParam class allows encoding an image in BMP format.
+ *
+ * @since Android 1.0
+ */
+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/bmp/package.html b/awt/javax/imageio/plugins/bmp/package.html
new file mode 100644
index 000000000..9494a102d
--- /dev/null
+++ b/awt/javax/imageio/plugins/bmp/package.html
@@ -0,0 +1,8 @@
+
+
+
+ This package contains auxiliary classes for the built-in BMP image plug-in.
+
+ @since Android 1.0
+
+
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
new file mode 100644
index 000000000..67b504be2
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.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 javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGHuffmanTable class represents a single JPEG Huffman table. It
+ * contains the standard tables from the JPEG specification.
+ *
+ * @since Android 1.0
+ */
+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 000000000..2f3a9a8fb
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.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.
+ */
+
+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.
+ *
+ * @since Android 1.0
+ */
+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 000000000..b9799112e
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.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.
+ */
+
+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.
+ *
+ * @since Android 1.0
+ */
+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 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 000000000..3461d4669
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGQTable.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 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.
+ *
+ * @since Android 1.0
+ */
+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 standard 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 integer values.
+ *
+ * @return the current quantization table as an array of integer 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/plugins/jpeg/package.html b/awt/javax/imageio/plugins/jpeg/package.html
new file mode 100644
index 000000000..14575c417
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/package.html
@@ -0,0 +1,8 @@
+
+
+
+ This package contains auxiliary classes for the built-in JPEG image plug-in.
+
+ @since Android 1.0
+
+
diff --git a/awt/javax/imageio/spi/IIORegistry.java b/awt/javax/imageio/spi/IIORegistry.java
new file mode 100644
index 000000000..01ddeaafe
--- /dev/null
+++ b/awt/javax/imageio/spi/IIORegistry.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 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.
+ *
+ * @since Android 1.0
+ */
+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.> asList(CATEGORIES).iterator());
+ registerBuiltinSpis();
+ registerApplicationClasspathSpis();
+ }
+
+ /**
+ * Register built-in 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 000000000..e9476773a
--- /dev/null
+++ b/awt/javax/imageio/spi/IIOServiceProvider.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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).
+ *
+ * @since Android 1.0
+ */
+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 000000000..fc859a871
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageInputStreamSpi.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.
+ */
+/**
+ * @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.
+ *
+ * @since Android 1.0
+ */
+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 the
+ * 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
+ * if 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
+ * if 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 000000000..b7a9a5c33
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageOutputStreamSpi.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 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.
+ *
+ * @since Android 1.0
+ */
+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
+ * if 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
+ * if 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 000000000..0528d250b
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderSpi.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 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.
+ *
+ * @since Android 1.0
+ */
+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 plug-in 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
+ * 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 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
+ * if 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
+ * if 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 plug-in specific extension object, or null.
+ * @return the ImageReader.
+ * @throws IOException
+ * if 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 the 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 000000000..9ca08b5ea
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
@@ -0,0 +1,344 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.
+ *
+ * @since Android 1.0
+ */
+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 plug-in 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 plug-in class name.
+ * @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 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 the 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 the 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 000000000..742af1908
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageTranscoderSpi.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.
+ *
+ * @since Android 1.0
+ */
+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 000000000..bf2545592
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageWriterSpi.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.
+ */
+/**
+ * @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.
+ *
+ * @since Android 1.0
+ */
+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 plug-in 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
+ * if 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 plug-in specific extension object, or null.
+ * @return the ImageWriter.
+ * @throws IOException
+ * if 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 the 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 000000000..ae2f4d39f
--- /dev/null
+++ b/awt/javax/imageio/spi/RegisterableService.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.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.
+ *
+ * @since Android 1.0
+ */
+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 000000000..79b02a366
--- /dev/null
+++ b/awt/javax/imageio/spi/ServiceRegistry.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 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.
+ *
+ * @since Android 1.0
+ */
+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> 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 Iterator lookupProviders(Class 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 Iterator lookupProviders(Class 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 boolean registerServiceProvider(T provider, Class 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 boolean deregisterServiceProvider(T provider, Class 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 Iterator getServiceProviders(Class category, Filter filter, boolean useOrdering) {
+ return new FilteredIterator(filter, (Iterator)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 Iterator getServiceProviders(Class category, boolean useOrdering) {
+ return (Iterator)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 getServiceProviderByClass(Class 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 boolean setOrdering(Class 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 boolean unsetOrdering(Class 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
+ * 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> getCategories() {
+ return categories.list();
+ }
+
+ /**
+ * The ServiceRegistry.Filter interface is used by
+ * ServiceRegistry.getServiceProviders to filter providers according to the
+ * specified criterion.
+ *
+ * @since Android 1.0
+ */
+ 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, ProvidersMap> categories = new HashMap, 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> 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 category is
+ * null 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 true, 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, 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, Object> providers = new HashMap, 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> 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 implements Iterator {
+
+ /**
+ * The filter.
+ */
+ private Filter filter;
+
+ /**
+ * The backend.
+ */
+ private Iterator 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 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/spi/package.html b/awt/javax/imageio/spi/package.html
new file mode 100644
index 000000000..18ceff486
--- /dev/null
+++ b/awt/javax/imageio/spi/package.html
@@ -0,0 +1,8 @@
+
+
+
+ This package provides several Service Provider Interface (SPI) classes for readers, writers, transcoders and streams to handle images.
+
+ @since Android 1.0
+
+
diff --git a/awt/javax/imageio/stream/FileCacheImageInputStream.java b/awt/javax/imageio/stream/FileCacheImageInputStream.java
new file mode 100644
index 000000000..710ac6660
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageInputStream.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.
+ *
+ * @since Android 1.0
+ */
+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 cache file will be created.
+ * @throws IOException
+ * if 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 000000000..135afab37
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageOutputStream.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.
+ */
+
+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.
+ *
+ * @since Android 1.0
+ */
+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 cache file will be created.
+ * @throws IOException
+ * if 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 000000000..b9b6002b3
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageInputStream.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.
+ */
+
+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.
+ *
+ * @since Android 1.0
+ */
+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
+ * if 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 000000000..2730ba6a9
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageOutputStream.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.
+ *
+ * @since Android 1.0
+ */
+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
+ * if 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 000000000..867d80843
--- /dev/null
+++ b/awt/javax/imageio/stream/IIOByteBuffer.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 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.
+ *
+ * @since Android 1.0
+ */
+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 000000000..3dec5d296
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStream.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 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.
+ *
+ * @since Android 1.0
+ */
+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
+ * if 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
+ * if 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
+ * if 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
+ * if 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 the boolean value for read byte.
+ * @throws IOException
+ * if an I/O exception has occurred.
+ */
+ boolean readBoolean() throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns its value as signed byte.
+ *
+ * @return the signed byte value for read byte.
+ * @throws IOException
+ * if an I/O exception has occurred.
+ */
+ byte readByte() throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns its value as an integer.
+ *
+ * @return the unsigned byte value for read byte as an integer.
+ * @throws IOException
+ * if 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
+ * if 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 integer.
+ * @throws IOException
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ char readChar() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream, and returns the result as an integer.
+ *
+ * @return the signed integer value from the stream.
+ * @throws IOException
+ * if an I/O exception has occurred.
+ */
+ int readInt() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream and returns its value as long.
+ *
+ * @return the unsigned integer value as long.
+ * @throws IOException
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ void readFully(char[] c, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of integer from the stream, and stores the
+ * result into the specified array starting at the specified index offset.
+ *
+ * @param i
+ * the integer array.
+ * @param off
+ * the offset.
+ * @param len
+ * the number of integer to be read.
+ * @throws IOException
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ long getStreamPosition() throws IOException;
+
+ /**
+ * Gets the bit offset.
+ *
+ * @return the bit offset.
+ * @throws IOException
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ long length() throws IOException;
+
+ /**
+ * Skips the specified number of bytes by moving stream position.
+ *
+ * @param n
+ * the number of bytes.
+ * @return the actual skipped number of bytes.
+ * @throws IOException
+ * if an I/O exception has occurred.
+ */
+ int skipBytes(int n) throws IOException;
+
+ /**
+ * Skips the specified number of bytes by moving stream position.
+ *
+ * @param n
+ * the number of bytes.
+ * @return the actual skipped number of bytes.
+ * @throws IOException
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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 000000000..d79da4185
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStreamImpl.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 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.
+ *
+ * @since Android 1.0
+ */
+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
+ * if 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 000000000..28ec93277
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStream.java
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.
+ *
+ * @since Android 1.0
+ */
+public interface ImageOutputStream extends DataOutput, ImageInputStream {
+
+ /**
+ * Writes a single byte to the stream at the current position.
+ *
+ * @param b
+ * the integer value, of which the 8 lowest bits will be written.
+ * @throws IOException
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ void write(byte[] b) throws IOException;
+
+ /**
+ * Writes a number of bytes from the specified byte array beginning from the
+ * specified offset.
+ *
+ * @param b
+ * the byte array.
+ * @param off
+ * the offset.
+ * @param len
+ * the number of bytes to be written.
+ * @throws IOException
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ void writeBoolean(boolean b) throws IOException;
+
+ /**
+ * Writes the 8 lowest bits of the specified integer value to the stream.
+ *
+ * @param b
+ * the specified integer value.
+ * @throws IOException
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ void writeShort(int v) throws IOException;
+
+ /**
+ * Writes the 16 lowest bits of the specified integer value to the stream.
+ *
+ * @param v
+ * the specified integer value.
+ * @throws IOException
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ void writeInt(int v) throws IOException;
+
+ /**
+ * Write long.
+ *
+ * @param v
+ * the long value.
+ * @throws IOException
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if 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
+ * if an I/O exception has occurred.
+ */
+ void writeChars(char[] c, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of integer values from the specified array to the
+ * stream.
+ *
+ * @param i
+ * the integer array to be written.
+ * @param off
+ * the offset in the char array.
+ * @param len
+ * the length of chars to be written.
+ * @throws IOException
+ * if 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
+ * if 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
+ * if 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
+ * if 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 integer whose least significant bit is to be written to
+ * the stream.
+ * @throws IOException
+ * if an I/O exception has occurred.
+ */
+ void writeBit(int bit) throws IOException;
+
+ /**
+ * Writes a sequence of bits beginning from the current position.
+ *
+ * @param bits
+ * the 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
+ * if 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 000000000..0fef78f1d
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.
+ *
+ * @since Android 1.0
+ */
+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
+ * if 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 000000000..d7fc79139
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.
+ *
+ * @since Android 1.0
+ */
+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 000000000..1df40a342
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.
+ *
+ * @since Android 1.0
+ */
+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/javax/imageio/stream/package.html b/awt/javax/imageio/stream/package.html
new file mode 100644
index 000000000..6cf53c3c0
--- /dev/null
+++ b/awt/javax/imageio/stream/package.html
@@ -0,0 +1,8 @@
+
+
+
+ This package contains classes and interfaces for handling images with low-level I/O operations.
+
+ @since Android 1.0
+
+
diff --git a/awt/org/apache/harmony/awt/ChoiceStyle.java b/awt/org/apache/harmony/awt/ChoiceStyle.java
new file mode 100644
index 000000000..93b7aada2
--- /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 000000000..c89a81dd1
--- /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 000000000..c3597846e
--- /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-null 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 popup 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.
+ * 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 000000000..d44648aa3
--- /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 000000000..4f0af52fe
--- /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 000000000..f5c55f10a
--- /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 implements Serializable {
+ private static final long serialVersionUID = 9180703263299648154L;
+
+ private transient ArrayList systemList;
+ private transient ArrayList 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();
+ }
+ 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();
+ userList.add(listener);
+ return;
+ }
+ ArrayList newList = new ArrayList(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 newList = new ArrayList(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[] 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 getUserListeners() {
+ synchronized (this) {
+ if (userList == null || userList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return new ArrayList(userList);
+ }
+ }
+
+ public List getSystemListeners() {
+ synchronized (this) {
+ if (systemList == null || systemList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return new ArrayList(systemList);
+ }
+ }
+
+ /**
+ * Gets iterator for user listeners.
+ *
+ * @return iterator for user listeners.
+ */
+ public Iterator getUserIterator() {
+ synchronized (this) {
+ if (userList == null) {
+ List emptyList = Collections.emptyList();
+ return emptyList.iterator();
+ }
+ return new ReadOnlyIterator(userList.iterator());
+ }
+ }
+
+ /**
+ * Gets iterator for system listeners.
+ *
+ * @return iterator for system listeners.
+ */
+ public Iterator getSystemIterator() {
+ return systemList.iterator();
+ }
+
+ private static ArrayList> getOnlySerializable(ArrayList> list) {
+ if (list == null) {
+ return null;
+ }
+
+ ArrayList result = new ArrayList();
+ 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)stream.readObject();
+ userList = (ArrayList)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 000000000..671653fb9
--- /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 implements Iterator {
+
+ private final Iterator it;
+
+ public ReadOnlyIterator(Iterator 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 000000000..bd5f6c680
--- /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 000000000..a33c38b3d
--- /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.
+ *
CommonGraphics2D Class Internals
+ *
Line and Shape Rasterizers
+ *
+ * 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.
+ *
+ *
+ * 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.
+ *
+
+ *
Blitters
+ *
+ * Blitter classes draw images on the display or buffered images. All blitters inherit
+ * the org.apache.harmony.awt.gl.render.Blitter interface.
+ *
+ *
Blitters are divided into:
+ *
+ *
Native blitters for simple types of images, which the underlying native library
+ * can draw.
+ *
Java* blitters for those types of images, which the underlying native library
+ * cannot handle.
+ *
+ *
+ * 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.
+ *
+ *
+ *
Text Renderers
+ *
+ *Text renderers draw strings and glyph vectors. All text renderers are subclasses
+ *of the org.apache.harmony.awt.gl.TextRenderer class.
+ *
+ *
+ */
+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 000000000..27e3ef078
--- /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 000000000..5c78e50d5
--- /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 familyNames = new ArrayList();
+
+ 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 000000000..ae7fb0eb4
--- /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 ROOT_DELTA 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 000000000..177be2309
--- /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 000000000..fc5631f37
--- /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 000000000..6368dd876
--- /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 000000000..c4267f3a9
--- /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 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 000000000..c75e2032a
--- /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 000000000..8b0ae38b9
--- /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 validCaches = new ArrayList();
+
+ 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 000000000..f57952d23
--- /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 000000000..e27e1d3f0
--- /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 000000000..c98e11497
--- /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 profileHandles = new HashMap();
+
+ 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() {
+ 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 000000000..9594047cd
--- /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 byte array.
+ *
+ * For common colorspaces with up to 4 color channels it
+ * should be short 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 byte or short
+ * @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 offsetsLst = new ArrayList();
+ 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
+ *
+ * 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 000000000..0cfdc43fc
--- /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 000000000..4ce5aed64
--- /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 000000000..f37be6d4f
--- /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 000000000..c0fb390f2
--- /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 000000000..b18bdd53a
--- /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 000000000..4040a60d9
--- /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 000000000..70cb3341b
--- /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 000000000..047ba6d10
--- /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 000000000..09bcf5c96
--- /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 runStarts,
+ Map 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 000000000..8354e2593
--- /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 style_keys = new Hashtable(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> fProperties = new Hashtable>();
+
+ 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 tableLCID = new Hashtable();
+
+ /**
+ * Hash table that contains FontPeers instances.
+ */
+ public Hashtable fontsTable = new Hashtable();
+
+ /**
+ * ReferenceQueue for HashMapReference objects to check
+ * if they were collected by garbage collector.
+ */
+ public ReferenceQueue queue = new ReferenceQueue();
+
+ /**
+ * 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 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 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 {
+
+ /**
+ * 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 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 000000000..778331787
--- /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
+ * -metrics[6] - strikethrough offset
+ * metrics[7] - maximum char width
+ * metrics[8] - ascent in pixels
+ * metrics[9] - descent in pixles
+ * metrics[10] - external leading in pixels
+ * metrics[11] - underline thickness in pixels
+ * -metrics[12] - underline offset in pixels
+ * metrics[13] - strikethrough thickness in pixels
+ * -metrics[14] - strikethrough offset in pixels
+ * metrics[15] - maximum char width in pixels
+
+ * @param _baselineData an array of 3 elements with baseline offsets metrics
+ * _baselineData[0] - roman baseline offset
+ * _baselineData[1] - center baseline offset
+ * _baselineData[2] - hanging baseline offset
+ */
+ }
+
+
+ /**
+ * 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 000000000..14ff99761
--- /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 lst = new ArrayList(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 000000000..4eb7cbb0d
--- /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 000000000..44b8809d8
--- /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 000000000..370146d91
--- /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.
+ * metrics[0] - ascent
+ * metrics[1] - descent
+ * metrics[2] - external leading
+ * metrics[3] - underline thickness
+ * -metrics[4] - underline offset
+ * metrics[5] - strikethrough thickness
+ * -metrics[6] - strikethrough offset
+ * metrics[7] - maximum char width
+ * metrics[8] - ascent in pixels
+ * metrics[9] - descent in pixles
+ * metrics[10] - external leading in pixels
+ * metrics[11] - underline thickness in pixels
+ * -metrics[12] - underline offset in pixels
+ * metrics[13] - strikethrough thickness in pixels
+ * -metrics[14] - strikethrough offset in pixels
+ * metrics[15] - maximum char width in pixels
+
+ * @param _baselineData an array of 3 elements with baseline offsets metrics
+ * _baselineData[0] - roman baseline offset
+ * _baselineData[1] - center baseline offset
+ * _baselineData[2] - hanging baseline offset
+ */
+ 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 000000000..81905fd60
--- /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 000000000..be5762a40
--- /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 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 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 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 000000000..be606f708
--- /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 fonts;
+ HashMap decorations;
+
+ // Related to default font substitution
+ int forcedFontRunStarts[];
+
+ ArrayList runSegments = new ArrayList();
+
+ // 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 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 newAttrs = new HashMap();
+ 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();
+ decorations = new HashMap();
+ ////
+
+ ArrayList 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();
+ }
+ 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 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 keys = new ArrayList();
+
+ Integer key, oldkey;
+ for (Iterator it = fonts.keySet().iterator(); it.hasNext(); ) {
+ oldkey = it.next();
+ if (oldkey.intValue() > pos.intValue()) {
+ keys.add(oldkey);
+ }
+ }
+
+ for (int i=0; i();
+ logical2segment = null;
+ segment2visual = null;
+ visual2segment = null;
+ levels = null;
+ haveAllSegments = false;
+ }
+
+ private class SegmentsInfo {
+ ArrayList 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 newSegments = new ArrayList(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= 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 000000000..1cd2c055a
--- /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 000000000..0ec2d05da
--- /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 info.length) {
+ end = info.length;
+ }
+
+ float sum = 0;
+ for (int i=start; i info.length) {
+ limit = info.length;
+ }
+
+ GeneralPath result = new GeneralPath();
+
+ int glyphIndex = 0;
+
+ for (int i=start; i 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 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 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 000000000..f1d64fbec
--- /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 000000000..0fe25a2e8
--- /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();
+ } 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 000000000..cc6d7cf66
--- /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 000000000..8793050a3
--- /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 000000000..958d691ce
--- /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 consumers = new ArrayList(5);
+ List decoders = new ArrayList(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 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 consumersList) {
+ for (ImageConsumer imageConsumer : consumersList) {
+ abortConsumer(imageConsumer);
+ }
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ ImageDecoder d = null;
+
+ // Remove in all existing decoders
+ for (Iterator 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 consumersList, ImageConsumer ic) {
+ ImageConsumer cons = null;
+
+ for (Iterator 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 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 consumersList, ImageConsumer ic) {
+ ImageConsumer res = null;
+
+ for (Iterator 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(5); // Reset queue
+ }
+
+ return decoder;
+ }
+ // We were not able to find appropriate decoder
+ List cs;
+ synchronized (this) {
+ cs = consumers;
+ consumers = new ArrayList(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 000000000..54d466432
--- /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 000000000..7ecb15bfe
--- /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 properties = new Hashtable();
+
+ // 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 graphicBlocks = new ArrayList(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 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 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 000000000..d16128e55
--- /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 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() {
+ 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 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 000000000..5c7d18032
--- /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 queue = new LinkedList();
+ List loaders = new ArrayList(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() {
+ 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 000000000..2e64427f0
--- /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()); // 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 000000000..3445f8e82
--- /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 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();
+ 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 000000000..1748e1bdd
--- /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 000000000..7e85600ac
--- /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()); // 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 000000000..46545f9c4
--- /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 000000000..a1899d650
--- /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 000000000..3b8012e72
--- /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 000000000..b643b41ac
--- /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 000000000..67e0a59b7
--- /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 000000000..eb6f7b5cb
--- /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 000000000..dbaaf539a
--- /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 000000000..322ba5769
--- /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 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 imInstances; // Map
+ private final Map localeIM; // Map last user-selected IM for locale
+ private final Set 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 imWindows; // set of all IM windows created by this instance
+ private final NativeIM nativeIM;
+
+
+
+ public InputMethodContext() {
+ notifyIM = new HashSet();
+//???AWT: imWindows = new HashSet();
+ imInstances = new HashMap();
+ localeIM = new HashMap();
+ 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 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 000000000..c340358db
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/Messages.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.
+ *
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the
+ * org.apache.harmony.awt.internal.nls.messages
+ *
+ * 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 KEY
+ * 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) {
+ // BEGIN android-changed
+ return MsgHelp.getString(msg);
+ // END android-changed
+ }
+
+ /**
+ * 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) {
+ // BEGIN android-changed
+ return MsgHelp.getString(msg, args);
+ // END android-changed
+ }
+
+ // BEGIN android-note
+ // Duplicate code was dropped in favor of using MsgHelp.
+ // END android-note
+}
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 000000000..b57fe1166
--- /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 000000000..b13e50bf0
--- /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 000000000..564a49a08
--- /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 000000000..4b8706d13
--- /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 000000000..63c581df2
--- /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 000000000..35e7d33bb
--- /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 000000000..0d7c84f7b
--- /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 000000000..1f8a29aa0
--- /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 000000000..2c6eb1ef6
--- /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 000000000..1471c1a72
--- /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.
+ *
+ *
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 000000000..0738cd138
--- /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
+ *
+ * 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 eventQueue = new LinkedList();
+
+ 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().
+ *
+ * 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 000000000..d50add4e3
--- /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 000000000..1626f4a9a
--- /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 000000000..06969756b
--- /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 000000000..0b354d05b
--- /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 000000000..73fd6c00b
--- /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).
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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 000000000..701eb46ca
--- /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 000000000..6efa519fc
--- /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 000000000..3eeaa0b07
--- /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 waitQueue = new LinkedList();
+
+ /**
+ * The event dispatch thread
+ */
+ protected Thread dispatchThread;
+
+ private final Hashtable storedStates = new Hashtable();
+
+ /**
+ * 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 000000000..6b59f0e70
--- /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 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 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 000000000..4162fbd52
--- /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 000000000..23604dad4
--- /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 000000000..51e8168fa
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/Messages.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+// 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.
+ *
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the
+ * org.apache.harmony.beans.internal.nls.messages
+ *
+ * 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 KEY
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ // BEGIN android-deleted
+ // private static final String sResource =
+ // "org.apache.harmony.beans.internal.nls.messages"; //$NON-NLS-1$
+ // 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) {
+ // BEGIN android-changed
+ return MsgHelp.getString(msg);
+ // END android-changed
+ }
+
+ /**
+ * 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) {
+ // BEGIN android-changed
+ return MsgHelp.getString(msg, args);
+ // END android-changed
+ }
+
+ // BEGIN android-note
+ // Duplicate code was dropped in favor of using MsgHelp.
+ // END android-note
+}
diff --git a/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java b/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java
new file mode 100644
index 000000000..68faabfa3
--- /dev/null
+++ b/awt/org/apache/harmony/beans/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.beans.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/beans/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/x/imageio/internal/nls/Messages.java b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
new file mode 100644
index 000000000..498e1bbe6
--- /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.
+ *
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the
+ * org.apache.harmony.x.imageio.internal.nls.messages
+ *
+ * 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 KEY
+ * 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 000000000..8a49dd8fd
--- /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 000000000..caeefdd5c
--- /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() {
+ 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 000000000..051f9065c
--- /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 000000000..067a82505
--- /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 000000000..110ed23ac
--- /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 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 000000000..c719ce77a
--- /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 000000000..ae3e87639
--- /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 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 000000000..b7990e088
--- /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 000000000..c3b4a506f
--- /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 000000000..480041c9c
--- /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 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 000000000..50f8b1078
--- /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 000000000..e2a8d7de6
--- /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 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 000000000..bf3a0003a
--- /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 000000000..6eed14dfc
--- /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 000000000..d4fdd764f
--- /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 000000000..acda6a1bf
--- /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 000000000..ed2fef076
--- /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 000000000..dd1e88dd4
--- /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 000000000..f97eb87e2
--- /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 000000000..a9d36492a
--- /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 000000000..64f7b2a09
--- /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 blocks = new ArrayList();
+
+ 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 000000000..9f647e9be
--- /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}
diff --git a/awt/resources/org/apache/harmony/beans/internals/nls/messages.properties b/awt/resources/org/apache/harmony/beans/internals/nls/messages.properties
new file mode 100644
index 000000000..72b1c8cad
--- /dev/null
+++ b/awt/resources/org/apache/harmony/beans/internals/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
+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/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
new file mode 100644
index 000000000..2dfe659a2
--- /dev/null
+++ b/camera/libcameraservice/Android.mk
@@ -0,0 +1,59 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want
+# the camera service to use the fake camera. For emulator or simulator builds,
+# we always use the fake camera.
+
+ifeq ($(USE_CAMERA_STUB),)
+USE_CAMERA_STUB:=false
+ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
+USE_CAMERA_STUB:=true
+endif #libcamerastub
+endif
+
+ifeq ($(USE_CAMERA_STUB),true)
+#
+# libcamerastub
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ CameraHardwareStub.cpp \
+ FakeCamera.cpp
+
+LOCAL_MODULE:= libcamerastub
+
+LOCAL_SHARED_LIBRARIES:= libui
+
+include $(BUILD_STATIC_LIBRARY)
+endif # USE_CAMERA_STUB
+
+#
+# libcameraservice
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ CameraService.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+ libui \
+ libutils \
+ libcutils
+
+LOCAL_MODULE:= libcameraservice
+
+LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"
+
+ifeq ($(USE_CAMERA_STUB), true)
+LOCAL_STATIC_LIBRARIES += libcamerastub
+LOCAL_CFLAGS += -include CameraHardwareStub.h
+else
+LOCAL_SHARED_LIBRARIES += libcamera
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
new file mode 100644
index 000000000..0f1ae8ea4
--- /dev/null
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -0,0 +1,388 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "CameraHardwareStub"
+#include
+
+#include "CameraHardwareStub.h"
+#include
+#include
+#include
+
+#include "CannedJpeg.h"
+
+namespace android {
+
+CameraHardwareStub::CameraHardwareStub()
+ : mParameters(),
+ mPreviewHeap(0),
+ mRawHeap(0),
+ mFakeCamera(0),
+ mPreviewFrameSize(0),
+ mRawPictureCallback(0),
+ mJpegPictureCallback(0),
+ mPictureCallbackCookie(0),
+ mPreviewCallback(0),
+ mPreviewCallbackCookie(0),
+ mAutoFocusCallback(0),
+ mAutoFocusCallbackCookie(0),
+ mCurrentPreviewFrame(0)
+{
+ initDefaultParameters();
+}
+
+void CameraHardwareStub::initDefaultParameters()
+{
+ CameraParameters p;
+
+ p.setPreviewSize(176, 144);
+ p.setPreviewFrameRate(15);
+ p.setPreviewFormat("yuv422sp");
+
+ p.setPictureSize(kCannedJpegWidth, kCannedJpegHeight);
+ p.setPictureFormat("jpeg");
+
+ if (setParameters(p) != NO_ERROR) {
+ LOGE("Failed to set default parameters?!");
+ }
+}
+
+void CameraHardwareStub::initHeapLocked()
+{
+ // Create raw heap.
+ int picture_width, picture_height;
+ mParameters.getPictureSize(&picture_width, &picture_height);
+ mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height);
+
+ int preview_width, preview_height;
+ mParameters.getPreviewSize(&preview_width, &preview_height);
+ LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
+
+ // Note that we enforce yuv422 in setParameters().
+ int how_big = preview_width * preview_height * 2;
+
+ // If we are being reinitialized to the same size as before, no
+ // work needs to be done.
+ if (how_big == mPreviewFrameSize)
+ return;
+
+ mPreviewFrameSize = how_big;
+
+ // Make a new mmap'ed heap that can be shared across processes.
+ // use code below to test with pmem
+ mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
+ // Make an IMemory for each frame so that we can reuse them in callbacks.
+ for (int i = 0; i < kBufferCount; i++) {
+ mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
+ }
+
+ // Recreate the fake camera to reflect the current size.
+ delete mFakeCamera;
+ mFakeCamera = new FakeCamera(preview_width, preview_height);
+}
+
+CameraHardwareStub::~CameraHardwareStub()
+{
+ delete mFakeCamera;
+ mFakeCamera = 0; // paranoia
+ singleton.clear();
+}
+
+sp CameraHardwareStub::getPreviewHeap() const
+{
+ return mPreviewHeap;
+}
+
+sp CameraHardwareStub::getRawHeap() const
+{
+ return mRawHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardwareStub::previewThread()
+{
+ mLock.lock();
+ // the attributes below can change under our feet...
+
+ int previewFrameRate = mParameters.getPreviewFrameRate();
+
+ // Find the offset within the heap of the current buffer.
+ ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
+
+ sp heap = mPreviewHeap;
+
+ // this assumes the internal state of fake camera doesn't change
+ // (or is thread safe)
+ FakeCamera* fakeCamera = mFakeCamera;
+
+ sp buffer = mBuffers[mCurrentPreviewFrame];
+
+ mLock.unlock();
+
+ // TODO: here check all the conditions that could go wrong
+ if (buffer != 0) {
+ // Calculate how long to wait between frames.
+ int delay = (int)(1000000.0f / float(previewFrameRate));
+
+ // This is always valid, even if the client died -- the memory
+ // is still mapped in our process.
+ void *base = heap->base();
+
+ // Fill the current frame with the fake camera.
+ uint8_t *frame = ((uint8_t *)base) + offset;
+ fakeCamera->getNextFrameAsYuv422(frame);
+
+ //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
+
+ // Notify the client of a new frame.
+ mPreviewCallback(buffer, mPreviewCallbackCookie);
+
+ // Advance the buffer pointer.
+ mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
+
+ // Wait for it...
+ usleep(delay);
+ }
+
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::startPreview(preview_callback cb, void* user)
+{
+ Mutex::Autolock lock(mLock);
+ if (mPreviewThread != 0) {
+ // already running
+ return INVALID_OPERATION;
+ }
+ mPreviewCallback = cb;
+ mPreviewCallbackCookie = user;
+ mPreviewThread = new PreviewThread(this);
+ return NO_ERROR;
+}
+
+void CameraHardwareStub::stopPreview()
+{
+ sp previewThread;
+
+ { // scope for the lock
+ Mutex::Autolock lock(mLock);
+ previewThread = mPreviewThread;
+ }
+
+ // don't hold the lock while waiting for the thread to quit
+ if (previewThread != 0) {
+ previewThread->requestExitAndWait();
+ }
+
+ Mutex::Autolock lock(mLock);
+ mPreviewThread.clear();
+}
+
+bool CameraHardwareStub::previewEnabled() {
+ return mPreviewThread != 0;
+}
+
+status_t CameraHardwareStub::startRecording(recording_callback cb, void* user)
+{
+ return UNKNOWN_ERROR;
+}
+
+void CameraHardwareStub::stopRecording()
+{
+}
+
+bool CameraHardwareStub::recordingEnabled()
+{
+ return false;
+}
+
+void CameraHardwareStub::releaseRecordingFrame(const sp& mem)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardwareStub::beginAutoFocusThread(void *cookie)
+{
+ CameraHardwareStub *c = (CameraHardwareStub *)cookie;
+ return c->autoFocusThread();
+}
+
+int CameraHardwareStub::autoFocusThread()
+{
+ if (mAutoFocusCallback != NULL) {
+ mAutoFocusCallback(true, mAutoFocusCallbackCookie);
+ mAutoFocusCallback = NULL;
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+}
+
+status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
+ void *user)
+{
+ Mutex::Autolock lock(mLock);
+
+ if (mAutoFocusCallback != NULL) {
+ return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION;
+ }
+
+ mAutoFocusCallback = af_cb;
+ mAutoFocusCallbackCookie = user;
+ if (createThread(beginAutoFocusThread, this) == false)
+ return UNKNOWN_ERROR;
+ return NO_ERROR;
+}
+
+/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
+{
+ CameraHardwareStub *c = (CameraHardwareStub *)cookie;
+ return c->pictureThread();
+}
+
+int CameraHardwareStub::pictureThread()
+{
+ if (mShutterCallback)
+ mShutterCallback(mPictureCallbackCookie);
+
+ if (mRawPictureCallback) {
+ //FIXME: use a canned YUV image!
+ // In the meantime just make another fake camera picture.
+ int w, h;
+ mParameters.getPictureSize(&w, &h);
+ sp mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
+ FakeCamera cam(w, h);
+ cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
+ if (mRawPictureCallback)
+ mRawPictureCallback(mem, mPictureCallbackCookie);
+ }
+
+ if (mJpegPictureCallback) {
+ sp heap = new MemoryHeapBase(kCannedJpegSize);
+ sp mem = new MemoryBase(heap, 0, kCannedJpegSize);
+ memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
+ if (mJpegPictureCallback)
+ mJpegPictureCallback(mem, mPictureCallbackCookie);
+ }
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::takePicture(shutter_callback shutter_cb,
+ raw_callback raw_cb,
+ jpeg_callback jpeg_cb,
+ void* user)
+{
+ stopPreview();
+ mShutterCallback = shutter_cb;
+ mRawPictureCallback = raw_cb;
+ mJpegPictureCallback = jpeg_cb;
+ mPictureCallbackCookie = user;
+ if (createThread(beginPictureThread, this) == false)
+ return -1;
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::cancelPicture(bool cancel_shutter,
+ bool cancel_raw,
+ bool cancel_jpeg)
+{
+ if (cancel_shutter) mShutterCallback = NULL;
+ if (cancel_raw) mRawPictureCallback = NULL;
+ if (cancel_jpeg) mJpegPictureCallback = NULL;
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::dump(int fd, const Vector& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ AutoMutex lock(&mLock);
+ if (mFakeCamera != 0) {
+ mFakeCamera->dump(fd, args);
+ mParameters.dump(fd, args);
+ snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
+ result.append(buffer);
+ } else {
+ result.append("No camera client yet.\n");
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::setParameters(const CameraParameters& params)
+{
+ Mutex::Autolock lock(mLock);
+ // XXX verify params
+
+ if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) {
+ LOGE("Only yuv422sp preview is supported");
+ return -1;
+ }
+
+ if (strcmp(params.getPictureFormat(), "jpeg") != 0) {
+ LOGE("Only jpeg still pictures are supported");
+ return -1;
+ }
+
+ int w, h;
+ params.getPictureSize(&w, &h);
+ if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
+ LOGE("Still picture size must be size of canned JPEG (%dx%d)",
+ kCannedJpegWidth, kCannedJpegHeight);
+ return -1;
+ }
+
+ mParameters = params;
+
+ initHeapLocked();
+
+ return NO_ERROR;
+}
+
+CameraParameters CameraHardwareStub::getParameters() const
+{
+ Mutex::Autolock lock(mLock);
+ return mParameters;
+}
+
+void CameraHardwareStub::release()
+{
+}
+
+wp CameraHardwareStub::singleton;
+
+sp CameraHardwareStub::createInstance()
+{
+ if (singleton != 0) {
+ sp hardware = singleton.promote();
+ if (hardware != 0) {
+ return hardware;
+ }
+ }
+ sp hardware(new CameraHardwareStub());
+ singleton = hardware;
+ return hardware;
+}
+
+extern "C" sp openCameraHardware()
+{
+ return CameraHardwareStub::createInstance();
+}
+
+}; // namespace android
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
new file mode 100644
index 000000000..0d26d47ec
--- /dev/null
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -0,0 +1,124 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
+
+#include "FakeCamera.h"
+#include
+#include
+#include
+#include
+#include
+
+namespace android {
+
+class CameraHardwareStub : public CameraHardwareInterface {
+public:
+ virtual sp getPreviewHeap() const;
+ virtual sp getRawHeap() const;
+
+ virtual status_t startPreview(preview_callback cb, void* user);
+ virtual void stopPreview();
+ virtual bool previewEnabled();
+
+ virtual status_t startRecording(recording_callback cb, void* user);
+ virtual void stopRecording();
+ virtual bool recordingEnabled();
+ virtual void releaseRecordingFrame(const sp& mem);
+
+ virtual status_t autoFocus(autofocus_callback, void *user);
+ virtual status_t takePicture(shutter_callback,
+ raw_callback,
+ jpeg_callback,
+ void* user);
+ virtual status_t cancelPicture(bool cancel_shutter,
+ bool cancel_raw,
+ bool cancel_jpeg);
+ virtual status_t dump(int fd, const Vector& args) const;
+ virtual status_t setParameters(const CameraParameters& params);
+ virtual CameraParameters getParameters() const;
+ virtual void release();
+
+ static sp createInstance();
+
+private:
+ CameraHardwareStub();
+ virtual ~CameraHardwareStub();
+
+ static wp singleton;
+
+ static const int kBufferCount = 4;
+
+ class PreviewThread : public Thread {
+ CameraHardwareStub* mHardware;
+ public:
+ PreviewThread(CameraHardwareStub* hw)
+ : Thread(false), mHardware(hw) { }
+ virtual void onFirstRef() {
+ run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
+ }
+ virtual bool threadLoop() {
+ mHardware->previewThread();
+ // loop until we need to quit
+ return true;
+ }
+ };
+
+ void initDefaultParameters();
+ void initHeapLocked();
+
+ int previewThread();
+
+ static int beginAutoFocusThread(void *cookie);
+ int autoFocusThread();
+
+ static int beginPictureThread(void *cookie);
+ int pictureThread();
+
+ mutable Mutex mLock;
+
+ CameraParameters mParameters;
+
+ sp mPreviewHeap;
+ sp mRawHeap;
+ sp mBuffers[kBufferCount];
+
+ FakeCamera *mFakeCamera;
+ bool mPreviewRunning;
+ int mPreviewFrameSize;
+
+ shutter_callback mShutterCallback;
+ raw_callback mRawPictureCallback;
+ jpeg_callback mJpegPictureCallback;
+ void *mPictureCallbackCookie;
+
+ // protected by mLock
+ sp mPreviewThread;
+ preview_callback mPreviewCallback;
+ void *mPreviewCallbackCookie;
+
+ autofocus_callback mAutoFocusCallback;
+ void *mAutoFocusCallbackCookie;
+
+ // only used from PreviewThread
+ int mCurrentPreviewFrame;
+};
+
+}; // namespace android
+
+#endif
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
new file mode 100644
index 000000000..15e3b21ae
--- /dev/null
+++ b/camera/libcameraservice/CameraService.cpp
@@ -0,0 +1,1073 @@
+/*
+**
+** Copyright (C) 2008, The Android Open Source Project
+** Copyright (C) 2008 HTC Inc.
+**
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CameraService"
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "CameraService.h"
+
+namespace android {
+
+extern "C" {
+#include
+#include
+#include
+#include
+#include
+}
+
+// When you enable this, as well as DEBUG_REFS=1 and
+// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp, this will track all
+// references to the CameraService::Client in order to catch the case where the
+// client is being destroyed while a callback from the CameraHardwareInterface
+// is outstanding. This is a serious bug because if we make another call into
+// CameraHardwreInterface that itself triggers a callback, we will deadlock.
+
+#define DEBUG_CLIENT_REFERENCES 0
+
+#define PICTURE_TIMEOUT seconds(5)
+
+#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
+#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
+#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
+
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+static int debug_frame_cnt;
+#endif
+
+// ----------------------------------------------------------------------------
+
+void CameraService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.camera"), new CameraService());
+}
+
+// ----------------------------------------------------------------------------
+
+CameraService::CameraService() :
+ BnCameraService()
+{
+ LOGI("CameraService started: pid=%d", getpid());
+}
+
+CameraService::~CameraService()
+{
+ if (mClient != 0) {
+ LOGE("mClient was still connected in destructor!");
+ }
+}
+
+sp CameraService::connect(const sp& cameraClient)
+{
+ LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
+
+ Mutex::Autolock lock(mLock);
+ sp client;
+ if (mClient != 0) {
+ sp currentClient = mClient.promote();
+ if (currentClient != 0) {
+ sp currentCameraClient(currentClient->getCameraClient());
+ if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
+ // this is the same client reconnecting...
+ LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get());
+ return currentClient;
+ } else {
+ // it's another client... reject it
+ LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get());
+ return client;
+ }
+ } else {
+ // can't promote, the previous client has died...
+ LOGD("new client connecting, old reference was dangling...");
+ mClient.clear();
+ }
+ }
+
+ // create a new Client object
+ client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
+ mClient = client;
+#if DEBUG_CLIENT_REFERENCES
+ // Enable tracking for this object, and track increments and decrements of
+ // the refcount.
+ client->trackMe(true, true);
+#endif
+ LOGD("Connect X");
+ return client;
+}
+
+void CameraService::removeClient(const sp& cameraClient)
+{
+ // declar this outside the lock to make absolutely sure the
+ // destructor won't be called with the lock held.
+ sp client;
+
+ Mutex::Autolock lock(mLock);
+
+ if (mClient == 0) {
+ // This happens when we have already disconnected.
+ LOGV("mClient is null.");
+ return;
+ }
+
+ // Promote mClient. It should never fail because we're called from
+ // a binder call, so someone has to have a strong reference.
+ client = mClient.promote();
+ if (client == 0) {
+ LOGW("can't get a strong reference on mClient!");
+ mClient.clear();
+ return;
+ }
+
+ if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
+ // ugh! that's not our client!!
+ LOGW("removeClient() called, but mClient doesn't match!");
+ } else {
+ // okay, good, forget about mClient
+ mClient.clear();
+ }
+}
+
+CameraService::Client::Client(const sp& cameraService,
+ const sp& cameraClient, pid_t clientPid)
+{
+ LOGD("Client E constructor");
+ mCameraService = cameraService;
+ mCameraClient = cameraClient;
+ mClientPid = clientPid;
+ mHardware = openCameraHardware();
+ mUseOverlay = mHardware->useOverlay();
+
+ // Callback is disabled by default
+ mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ LOGD("Client X constructor");
+}
+
+status_t CameraService::Client::checkPid()
+{
+ if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
+ LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get());
+ return -EBUSY;
+}
+
+status_t CameraService::Client::lock()
+{
+ Mutex::Autolock _l(mLock);
+ // lock camera to this client if the the camera is unlocked
+ if (mClientPid == 0) {
+ mClientPid = IPCThreadState::self()->getCallingPid();
+ return NO_ERROR;
+ }
+ // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
+ return checkPid();
+}
+
+status_t CameraService::Client::unlock()
+{
+ Mutex::Autolock _l(mLock);
+ // allow anyone to use camera
+ LOGV("unlock (%p)", getCameraClient()->asBinder().get());
+ status_t result = checkPid();
+ if (result == NO_ERROR) mClientPid = 0;
+ return result;
+}
+
+status_t CameraService::Client::connect(const sp& client)
+{
+ // connect a new process to the camera
+ LOGV("connect (%p)", client->asBinder().get());
+
+ // I hate this hack, but things get really ugly when the media recorder
+ // service is handing back the camera to the app. The ICameraClient
+ // destructor will be called during the same IPC, making it look like
+ // the remote client is trying to disconnect. This hack temporarily
+ // sets the mClientPid to an invalid pid to prevent the hardware from
+ // being torn down.
+ {
+
+ // hold a reference to the old client or we will deadlock if the client is
+ // in the same process and we hold the lock when we remove the reference
+ sp oldClient;
+ {
+ Mutex::Autolock _l(mLock);
+ if (mClientPid != 0) {
+ LOGW("Tried to connect to locked camera");
+ return -EBUSY;
+ }
+ oldClient = mCameraClient;
+
+ // did the client actually change?
+ if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+
+ mCameraClient = client;
+ mClientPid = -1;
+ mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ LOGV("connect new process (%d) to existing camera client", mClientPid);
+ }
+
+ }
+ // the old client destructor is called when oldClient goes out of scope
+ // now we set the new PID to lock the interface again
+ mClientPid = IPCThreadState::self()->getCallingPid();
+
+ return NO_ERROR;
+}
+
+#if HAVE_ANDROID_OS
+static void *unregister_surface(void *arg)
+{
+ ISurface *surface = (ISurface *)arg;
+ surface->unregisterBuffers();
+ IPCThreadState::self()->flushCommands();
+ return NULL;
+}
+#endif
+
+CameraService::Client::~Client()
+{
+ // tear down client
+ LOGD("Client (%p) E destructor", getCameraClient()->asBinder().get());
+ if (mSurface != 0 && !mUseOverlay) {
+#if HAVE_ANDROID_OS
+ pthread_t thr;
+ // We unregister the buffers in a different thread because binder does
+ // not let us make sychronous transactions in a binder destructor (that
+ // is, upon our reaching a refcount of zero.)
+ pthread_create(&thr, NULL,
+ unregister_surface,
+ mSurface.get());
+ pthread_join(thr, NULL);
+#else
+ mSurface->unregisterBuffers();
+#endif
+ }
+
+ // make sure we tear down the hardware
+ mClientPid = IPCThreadState::self()->getCallingPid();
+ disconnect();
+ LOGD("Client X destructor");
+}
+
+void CameraService::Client::disconnect()
+{
+ LOGD("Client (%p) E disconnect from (%d)",
+ getCameraClient()->asBinder().get(),
+ IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock lock(mLock);
+ if (mClientPid <= 0) {
+ LOGV("camera is unlocked, don't tear down hardware");
+ return;
+ }
+ if (checkPid() != NO_ERROR) {
+ LOGV("Different client - don't disconnect");
+ return;
+ }
+
+ mCameraService->removeClient(mCameraClient);
+ if (mHardware != 0) {
+ LOGV("hardware teardown");
+ // Before destroying mHardware, we must make sure it's in the
+ // idle state.
+ mHardware->stopPreview();
+ // Cancel all picture callbacks.
+ mHardware->cancelPicture(true, true, true);
+ // Release the hardware resources.
+ mHardware->release();
+ }
+ mHardware.clear();
+ LOGD("Client X disconnect");
+}
+
+// pass the buffered ISurface to the camera service
+status_t CameraService::Client::setPreviewDisplay(const sp